summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-06-14 12:10:13 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-06-14 12:10:13 +0000
commitb82c4935ecc86d1429710163287f5bd7d75bf226 (patch)
tree804f3e490810b4e4c6b9bbe1c9aeadaf3ca7de32
parent0e0ec3ddd5528b1d2114606158344226debabdc9 (diff)
downloadgitlab-ce-b82c4935ecc86d1429710163287f5bd7d75bf226.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_manual_todo.yml1
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js2
-rw-r--r--app/assets/javascripts/packages/details/components/file_sha.vue41
-rw-r--r--app/assets/javascripts/packages/details/components/package_files.vue33
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/app.vue5
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue40
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/index.js2
-rw-r--r--app/assets/javascripts/repository/log_tree.js22
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/details_row.vue5
-rw-r--r--app/controllers/clusters/applications_controller.rb2
-rw-r--r--app/controllers/projects/analytics/cycle_analytics/summary_controller.rb27
-rw-r--r--app/controllers/projects/cycle_analytics/events_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb6
-rw-r--r--app/finders/ci/runners_finder.rb9
-rw-r--r--app/graphql/mutations/ci/ci_cd_settings_update.rb4
-rw-r--r--app/graphql/types/ci/ci_cd_setting_type.rb3
-rw-r--r--app/graphql/types/ci/runner_sort_enum.rb4
-rw-r--r--app/models/analytics/cycle_analytics/project_level.rb49
-rw-r--r--app/models/ci/runner.rb9
-rw-r--r--app/models/clusters/applications/fluentd.rb9
-rw-r--r--app/models/clusters/applications/ingress.rb101
-rw-r--r--app/models/clusters/cluster.rb1
-rw-r--r--app/models/cycle_analytics/project_level.rb48
-rw-r--r--app/models/members/last_group_owner_assigner.rb62
-rw-r--r--app/serializers/cluster_application_entity.rb3
-rw-r--r--app/serializers/member_serializer.rb2
-rw-r--r--app/services/clusters/applications/base_service.rb8
-rw-r--r--app/views/admin/application_settings/_diff_limits.html.haml8
-rw-r--r--app/views/admin/application_settings/general.html.haml2
-rw-r--r--app/views/projects/forks/new.html.haml3
-rw-r--r--app/views/shared/issuable/form/_branch_chooser.html.haml14
-rw-r--r--app/workers/ssh_keys/expired_notification_worker.rb2
-rw-r--r--app/workers/ssh_keys/expiring_soon_notification_worker.rb2
-rw-r--r--config/feature_flags/development/background_pipeline_retry_endpoint.yml8
-rw-r--r--config/feature_flags/development/ci_dynamic_child_pipeline.yml8
-rw-r--r--config/feature_flags/development/sidekiq_load_balancing_rotate_up_to_date_replica.yml (renamed from config/feature_flags/development/remove_release_notes_from_tags_api.yml)8
-rw-r--r--config/feature_flags/development/ssh_key_expiration_email_notification.yml8
-rw-r--r--config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml16
-rw-r--r--config/metrics/license/20210204124854_license_management_jobs.yml17
-rw-r--r--config/routes/project.rb1
-rw-r--r--db/migrate/20210601125410_add_runners_created_at_index.rb20
-rw-r--r--db/migrate/20210601133459_replace_runners_contacted_at_index.rb26
-rw-r--r--db/schema_migrations/202106011254101
-rw-r--r--db/schema_migrations/202106011334591
-rw-r--r--db/structure.sql8
-rw-r--r--doc/administration/file_hooks.md7
-rw-r--r--doc/api/graphql/reference/index.md6
-rw-r--r--doc/api/tags.md85
-rw-r--r--doc/development/appsec/index.md2
-rw-r--r--doc/development/usage_ping/dictionary.md32
-rw-r--r--doc/user/profile/notifications.md1
-rw-r--r--lib/api/entities/issue_basic.rb2
-rw-r--r--lib/api/tags.rb91
-rw-r--r--lib/gitlab/ci/config/external/file/artifact.rb5
-rw-r--r--lib/gitlab/ci/features.rb4
-rw-r--r--lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml2
-rw-r--r--lib/gitlab/cycle_analytics/stage_summary.rb17
-rw-r--r--lib/gitlab/cycle_analytics/summary/base.rb5
-rw-r--r--lib/gitlab/cycle_analytics/summary/commit.rb2
-rw-r--r--lib/gitlab/cycle_analytics/summary/deploy.rb2
-rw-r--r--lib/gitlab/cycle_analytics/summary/deployment_frequency.rb6
-rw-r--r--lib/gitlab/cycle_analytics/summary/issue.rb15
-rw-r--r--lib/gitlab/database/load_balancing/load_balancer.rb14
-rw-r--r--lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb6
-rw-r--r--lib/gitlab/database/migration_helpers.rb2
-rw-r--r--lib/gitlab/file_hook_logger.rb2
-rw-r--r--lib/gitlab/graphql.rb7
-rw-r--r--lib/gitlab/graphql/standard_graphql_error.rb10
-rw-r--r--locale/gitlab.pot12
-rwxr-xr-xscripts/gitaly-test-build2
-rw-r--r--spec/controllers/projects/analytics/cycle_analytics/summary_controller_spec.rb46
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb13
-rw-r--r--spec/factories/clusters/applications/helm.rb20
-rw-r--r--spec/factories/projects.rb2
-rw-r--r--spec/finders/ci/runners_finder_spec.rb58
-rw-r--r--spec/fixtures/api/schemas/analytics/cycle_analytics/summary.json21
-rw-r--r--spec/fixtures/api/schemas/cluster_status.json1
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js1
-rw-r--r--spec/frontend/packages/details/components/__snapshots__/file_sha_spec.js.snap30
-rw-r--r--spec/frontend/packages/details/components/file_sha_spec.js33
-rw-r--r--spec/frontend/packages/details/components/package_files_spec.js77
-rw-r--r--spec/frontend/packages/mock_data.js3
-rw-r--r--spec/frontend/pages/projects/forks/new/components/app_spec.js1
-rw-r--r--spec/frontend/pages/projects/forks/new/components/fork_form_spec.js129
-rw-r--r--spec/frontend/repository/log_tree_spec.js10
-rw-r--r--spec/graphql/resolvers/ci/runners_resolver_spec.rb20
-rw-r--r--spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb9
-rw-r--r--spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb34
-rw-r--r--spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb16
-rw-r--r--spec/lib/gitlab/database/load_balancing_spec.rb2
-rw-r--r--spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb16
-rw-r--r--spec/models/clusters/applications/fluentd_spec.rb19
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb90
-rw-r--r--spec/models/clusters/cluster_spec.rb22
-rw-r--r--spec/models/members/last_group_owner_assigner_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/ci_cd_setting_spec.rb1
-rw-r--r--spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb32
-rw-r--r--spec/requests/api/tags_spec.rb164
-rw-r--r--spec/serializers/analytics_summary_serializer_spec.rb4
-rw-r--r--spec/serializers/cluster_application_entity_spec.rb1
-rw-r--r--spec/serializers/member_serializer_spec.rb2
-rw-r--r--spec/services/clusters/applications/create_service_spec.rb7
-rw-r--r--spec/workers/ssh_keys/expired_notification_worker_spec.rb10
-rw-r--r--spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb10
-rw-r--r--vendor/elastic_stack/values.yaml6
-rw-r--r--vendor/ingress/modsecurity.conf274
107 files changed, 931 insertions, 1249 deletions
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index 5992affe96a..b88ccbabdea 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -1588,6 +1588,7 @@ Gitlab/NamespacedClass:
- 'app/models/list_user_preference.rb'
- 'app/models/member.rb'
- 'app/models/members/group_member.rb'
+ - 'app/models/members/last_group_owner_assigner.rb'
- 'app/models/members/project_member.rb'
- 'app/models/members_preloader.rb'
- 'app/models/merge_request.rb'
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 303d6d1dba9..48abc072675 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -323,7 +323,7 @@ export function isAbsolute(url) {
* @param {String} url
*/
export function isRootRelative(url) {
- return /^\//.test(url);
+ return /^\/(?!\/)/.test(url);
}
/**
diff --git a/app/assets/javascripts/packages/details/components/file_sha.vue b/app/assets/javascripts/packages/details/components/file_sha.vue
new file mode 100644
index 00000000000..a25839be7e1
--- /dev/null
+++ b/app/assets/javascripts/packages/details/components/file_sha.vue
@@ -0,0 +1,41 @@
+<script>
+import { s__ } from '~/locale';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
+
+export default {
+ name: 'FileSha',
+ components: {
+ DetailsRow,
+ ClipboardButton,
+ },
+ props: {
+ sha: {
+ type: String,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ },
+ i18n: {
+ copyButtonTitle: s__('PackageRegistry|Copy SHA'),
+ },
+};
+</script>
+
+<template>
+ <details-row dashed>
+ <div class="gl-px-4">
+ {{ title }}:
+ {{ sha }}
+ <clipboard-button
+ :text="sha"
+ :title="$options.i18n.copyButtonTitle"
+ category="tertiary"
+ size="small"
+ />
+ </div>
+ </details-row>
+</template>
diff --git a/app/assets/javascripts/packages/details/components/package_files.vue b/app/assets/javascripts/packages/details/components/package_files.vue
index 735f5c2e5cd..3c71ac5137e 100644
--- a/app/assets/javascripts/packages/details/components/package_files.vue
+++ b/app/assets/javascripts/packages/details/components/package_files.vue
@@ -1,8 +1,9 @@
<script>
-import { GlLink, GlTable, GlDropdownItem, GlDropdown, GlIcon } from '@gitlab/ui';
+import { GlLink, GlTable, GlDropdownItem, GlDropdown, GlIcon, GlButton } from '@gitlab/ui';
import { last } from 'lodash';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { __ } from '~/locale';
+import FileSha from '~/packages/details/components/file_sha.vue';
import Tracking from '~/tracking';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
@@ -15,8 +16,10 @@ export default {
GlIcon,
GlDropdown,
GlDropdownItem,
+ GlButton,
FileIcon,
TimeAgoTooltip,
+ FileSha,
},
mixins: [Tracking.mixin()],
props: {
@@ -76,6 +79,9 @@ export default {
formatSize(size) {
return numberToHumanSize(size);
},
+ hasDetails(item) {
+ return item.file_sha256 || item.file_md5 || item.file_sha1;
+ },
},
i18n: {
deleteFile: __('Delete file'),
@@ -91,7 +97,15 @@ export default {
:items="filesTableRows"
:tbody-tr-attr="{ 'data-testid': 'file-row' }"
>
- <template #cell(name)="{ item }">
+ <template #cell(name)="{ item, toggleDetails, detailsShowing }">
+ <gl-button
+ v-if="hasDetails(item)"
+ :icon="detailsShowing ? 'angle-up' : 'angle-down'"
+ :aria-label="detailsShowing ? __('Collapse') : __('Expand')"
+ category="tertiary"
+ size="small"
+ @click="toggleDetails"
+ />
<gl-link
:href="item.download_path"
class="gl-text-gray-500"
@@ -131,6 +145,21 @@ export default {
</gl-dropdown-item>
</gl-dropdown>
</template>
+
+ <template #row-details="{ item }">
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-flex-fill-1 gl-bg-gray-10 gl-rounded-base gl-inset-border-1-gray-100"
+ >
+ <file-sha
+ v-if="item.file_sha256"
+ data-testid="sha-256"
+ title="SHA-256"
+ :sha="item.file_sha256"
+ />
+ <file-sha v-if="item.file_md5" data-testid="md5" title="MD5" :sha="item.file_md5" />
+ <file-sha v-if="item.file_sha1" data-testid="sha-1" title="SHA-1" :sha="item.file_sha1" />
+ </div>
+ </template>
</gl-table>
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/app.vue b/app/assets/javascripts/pages/projects/forks/new/components/app.vue
index 02b357d389b..7fb41c6e7b7 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/app.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/app.vue
@@ -38,6 +38,10 @@ export default {
type: String,
required: true,
},
+ restrictedVisibilityLevels: {
+ type: Array,
+ required: true,
+ },
},
};
</script>
@@ -66,6 +70,7 @@ export default {
:project-path="projectPath"
:project-description="projectDescription"
:project-visibility="projectVisibility"
+ :restricted-visibility-levels="restrictedVisibilityLevels"
/>
</div>
</div>
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
index 96bd38ea9e2..75c3b6d564c 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/fork_form.vue
@@ -95,6 +95,10 @@ export default {
type: String,
required: true,
},
+ restrictedVisibilityLevels: {
+ type: Array,
+ required: true,
+ },
},
data() {
const form = {
@@ -111,7 +115,7 @@ export default {
required: false,
skipValidation: true,
}),
- visibility: initFormField({ value: this.projectVisibility }),
+ visibility: initFormField({ value: this.getInitialVisibilityValue() }),
},
};
return {
@@ -134,13 +138,28 @@ export default {
visibilityLevelCap() {
return Math.min(this.projectVisibilityLevel, this.namespaceVisibilityLevel);
},
+ restrictedVisibilityLevelsSet() {
+ return new Set(this.restrictedVisibilityLevels);
+ },
allowedVisibilityLevels() {
- return Object.entries(VISIBILITY_LEVEL).reduce((levels, [levelName, levelValue]) => {
- if (levelValue <= this.visibilityLevelCap) {
- levels.push(levelName);
- }
- return levels;
- }, []);
+ const allowedLevels = Object.entries(VISIBILITY_LEVEL).reduce(
+ (levels, [levelName, levelValue]) => {
+ if (
+ !this.restrictedVisibilityLevelsSet.has(levelValue) &&
+ levelValue <= this.visibilityLevelCap
+ ) {
+ levels.push(levelName);
+ }
+ return levels;
+ },
+ [],
+ );
+
+ if (!allowedLevels.length) {
+ return [PRIVATE_VISIBILITY];
+ }
+
+ return allowedLevels;
},
visibilityLevels() {
return [
@@ -173,7 +192,8 @@ export default {
watch: {
// eslint-disable-next-line func-names
'form.fields.namespace.value': function () {
- this.form.fields.visibility.value = PRIVATE_VISIBILITY;
+ this.form.fields.visibility.value =
+ this.restrictedVisibilityLevels.length !== 0 ? null : PRIVATE_VISIBILITY;
},
// eslint-disable-next-line func-names
'form.fields.name.value': function (newVal) {
@@ -191,6 +211,9 @@ export default {
isVisibilityLevelDisabled(visibility) {
return !this.allowedVisibilityLevels.includes(visibility);
},
+ getInitialVisibilityValue() {
+ return this.restrictedVisibilityLevels.length !== 0 ? null : this.projectVisibility;
+ },
async onSubmit() {
this.form.showValidation = true;
@@ -340,6 +363,7 @@ export default {
v-model="form.fields.visibility.value"
data-testid="fork-visibility-radio-group"
name="visibility"
+ :aria-label="__('visibility')"
required
>
<gl-form-radio
diff --git a/app/assets/javascripts/pages/projects/forks/new/index.js b/app/assets/javascripts/pages/projects/forks/new/index.js
index 372967c8a1e..1a171252048 100644
--- a/app/assets/javascripts/pages/projects/forks/new/index.js
+++ b/app/assets/javascripts/pages/projects/forks/new/index.js
@@ -16,6 +16,7 @@ if (gon.features.forkProjectForm) {
projectPath,
projectDescription,
projectVisibility,
+ restrictedVisibilityLevels,
} = mountElement.dataset;
// eslint-disable-next-line no-new
@@ -38,6 +39,7 @@ if (gon.features.forkProjectForm) {
projectPath,
projectDescription,
projectVisibility,
+ restrictedVisibilityLevels: JSON.parse(restrictedVisibilityLevels),
},
});
},
diff --git a/app/assets/javascripts/repository/log_tree.js b/app/assets/javascripts/repository/log_tree.js
index 7d9d962b6f4..ac02392d60f 100644
--- a/app/assets/javascripts/repository/log_tree.js
+++ b/app/assets/javascripts/repository/log_tree.js
@@ -8,6 +8,12 @@ import refQuery from './queries/ref.query.graphql';
const fetchpromises = {};
const resolvers = {};
let maxOffset;
+let nextOffset;
+let currentPath;
+
+function setNextOffset(offset) {
+ nextOffset = offset || null;
+}
export function resolveCommit(commits, path, { resolve, entry }) {
const commit = commits.find(
@@ -24,7 +30,17 @@ export function fetchLogsTree(client, path, offset, resolver = null, _maxOffset
maxOffset = _maxOffset;
}
- if (Number(offset) > maxOffset) {
+ if (!currentPath || currentPath !== path) {
+ // ensures the nextOffset is reset if the user changed directories
+ setNextOffset(null);
+ }
+
+ currentPath = path;
+
+ const offsetNumber = Number(offset);
+
+ if (!nextOffset && offsetNumber > maxOffset) {
+ setNextOffset(offsetNumber - 25); // ensures commit data is fetched for newly added rows that need data from the previous request (requests are made in batches of 25).
return Promise.resolve();
}
@@ -47,7 +63,7 @@ export function fetchLogsTree(client, path, offset, resolver = null, _maxOffset
path.replace(/^\//, ''),
)}`,
{
- params: { format: 'json', offset },
+ params: { format: 'json', offset: nextOffset || offset },
},
)
.then(({ data: newData, headers }) => {
@@ -66,10 +82,12 @@ export function fetchLogsTree(client, path, offset, resolver = null, _maxOffset
delete fetchpromises[path];
if (headerLogsOffset) {
+ setNextOffset(null);
fetchLogsTree(client, path, headerLogsOffset);
} else {
delete resolvers[path];
maxOffset = null;
+ setNextOffset(null);
}
});
diff --git a/app/assets/javascripts/vue_shared/components/registry/details_row.vue b/app/assets/javascripts/vue_shared/components/registry/details_row.vue
index 2e245fadead..72e06b45561 100644
--- a/app/assets/javascripts/vue_shared/components/registry/details_row.vue
+++ b/app/assets/javascripts/vue_shared/components/registry/details_row.vue
@@ -8,7 +8,8 @@ export default {
props: {
icon: {
type: String,
- required: true,
+ required: false,
+ default: null,
},
padding: {
type: String,
@@ -34,7 +35,7 @@ export default {
class="gl-display-flex gl-align-items-center gl-font-monospace gl-font-sm gl-word-break-all"
:class="[padding, borderClass]"
>
- <gl-icon :name="icon" class="gl-mr-4" />
+ <gl-icon v-if="icon" :name="icon" class="gl-mr-4" />
<span>
<slot></slot>
</span>
diff --git a/app/controllers/clusters/applications_controller.rb b/app/controllers/clusters/applications_controller.rb
index c533fe007d7..5c1d85f4374 100644
--- a/app/controllers/clusters/applications_controller.rb
+++ b/app/controllers/clusters/applications_controller.rb
@@ -47,7 +47,7 @@ class Clusters::ApplicationsController < Clusters::BaseController
end
def cluster_application_params
- params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :modsecurity_enabled, :modsecurity_mode, :host, :port, :protocol, :waf_log_enabled, :cilium_log_enabled)
+ params.permit(:application, :hostname, :pages_domain_id, :email, :stack, :host, :port, :protocol, :cilium_log_enabled)
end
def cluster_application_destroy_params
diff --git a/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb b/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb
new file mode 100644
index 00000000000..c51a5ac7b88
--- /dev/null
+++ b/app/controllers/projects/analytics/cycle_analytics/summary_controller.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class Projects::Analytics::CycleAnalytics::SummaryController < Projects::ApplicationController
+ include CycleAnalyticsParams
+
+ respond_to :json
+
+ feature_category :planning_analytics
+
+ before_action :authorize_read_cycle_analytics!
+
+ def show
+ render json: project_level.summary
+ end
+
+ private
+
+ def project_level
+ @project_level ||= Analytics::CycleAnalytics::ProjectLevel.new(project: @project, options: options(allowed_params))
+ end
+
+ def allowed_params
+ params.permit(:created_after, :created_before)
+ end
+end
+
+Projects::Analytics::CycleAnalytics::SummaryController.prepend_mod_with('Projects::Analytics::CycleAnalytics::SummaryController')
diff --git a/app/controllers/projects/cycle_analytics/events_controller.rb b/app/controllers/projects/cycle_analytics/events_controller.rb
index 3a5dd23047c..a1da8d4e91f 100644
--- a/app/controllers/projects/cycle_analytics/events_controller.rb
+++ b/app/controllers/projects/cycle_analytics/events_controller.rb
@@ -53,7 +53,7 @@ module Projects
end
def cycle_analytics
- @cycle_analytics ||= ::CycleAnalytics::ProjectLevel.new(project, options: options(cycle_analytics_project_params))
+ @cycle_analytics ||= ::Analytics::CycleAnalytics::ProjectLevel.new(project: project, options: options(cycle_analytics_project_params))
end
end
end
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index 5c15a5d246c..d1d27286c68 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -14,7 +14,7 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
feature_category :planning_analytics
def show
- @cycle_analytics = ::CycleAnalytics::ProjectLevel.new(@project, options: options(cycle_analytics_project_params))
+ @cycle_analytics = Analytics::CycleAnalytics::ProjectLevel.new(project: @project, options: options(cycle_analytics_project_params))
respond_to do |format|
format.html do
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index f0e4cd10366..116e7970bbf 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -176,11 +176,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def retry
- if Gitlab::Ci::Features.background_pipeline_retry_endpoint?(@project)
- ::Ci::RetryPipelineWorker.perform_async(pipeline.id, current_user.id) # rubocop:disable CodeReuse/Worker
- else
- pipeline.retry_failed(current_user)
- end
+ ::Ci::RetryPipelineWorker.perform_async(pipeline.id, current_user.id) # rubocop:disable CodeReuse/Worker
respond_to do |format|
format.html do
diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb
index 60dd977ff94..7ad51361efd 100644
--- a/app/finders/ci/runners_finder.rb
+++ b/app/finders/ci/runners_finder.rb
@@ -4,6 +4,9 @@ module Ci
class RunnersFinder < UnionFinder
include Gitlab::Allowable
+ ALLOWED_SORTS = %w[contacted_asc contacted_desc created_at_asc created_at_desc created_date].freeze
+ DEFAULT_SORT = 'created_at_desc'
+
def initialize(current_user:, group: nil, params:)
@params = params
@group = group
@@ -24,11 +27,7 @@ module Ci
end
def sort_key
- if @params[:sort] == 'contacted_asc'
- 'contacted_asc'
- else
- 'created_date'
- end
+ ALLOWED_SORTS.include?(@params[:sort]) ? @params[:sort] : DEFAULT_SORT
end
private
diff --git a/app/graphql/mutations/ci/ci_cd_settings_update.rb b/app/graphql/mutations/ci/ci_cd_settings_update.rb
index a484c2438a4..0973e9beae3 100644
--- a/app/graphql/mutations/ci/ci_cd_settings_update.rb
+++ b/app/graphql/mutations/ci/ci_cd_settings_update.rb
@@ -17,6 +17,10 @@ module Mutations
required: false,
description: 'Indicates if the latest artifact should be kept for this project.'
+ argument :job_token_scope_enabled, GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'Indicates CI job tokens generated in this project have restricted access to resources.'
+
field :ci_cd_settings,
Types::Ci::CiCdSettingType,
null: false,
diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb
index b34a91446a2..f90c75454ba 100644
--- a/app/graphql/types/ci/ci_cd_setting_type.rb
+++ b/app/graphql/types/ci/ci_cd_setting_type.rb
@@ -16,6 +16,9 @@ module Types
field :keep_latest_artifact, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether to keep the latest builds artifacts.',
method: :keep_latest_artifacts_available?
+ field :job_token_scope_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates CI job tokens generated in this project have restricted access to resources.',
+ method: :job_token_scope_enabled?
field :project, Types::ProjectType, null: true,
description: 'Project the CI/CD settings belong to.'
end
diff --git a/app/graphql/types/ci/runner_sort_enum.rb b/app/graphql/types/ci/runner_sort_enum.rb
index 550e870316a..95ec1867fea 100644
--- a/app/graphql/types/ci/runner_sort_enum.rb
+++ b/app/graphql/types/ci/runner_sort_enum.rb
@@ -7,7 +7,9 @@ module Types
description 'Values for sorting runners'
value 'CONTACTED_ASC', 'Ordered by contacted_at in ascending order.', value: :contacted_asc
- value 'CREATED_DESC', 'Ordered by created_date in descending order.', value: :created_date
+ value 'CONTACTED_DESC', 'Ordered by contacted_at in descending order.', value: :contacted_desc
+ value 'CREATED_ASC', 'Ordered by created_at in ascending order.', value: :created_at_asc
+ value 'CREATED_DESC', 'Ordered by created_at in descending order.', value: :created_at_desc
end
end
end
diff --git a/app/models/analytics/cycle_analytics/project_level.rb b/app/models/analytics/cycle_analytics/project_level.rb
new file mode 100644
index 00000000000..7a73bc75ed6
--- /dev/null
+++ b/app/models/analytics/cycle_analytics/project_level.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Analytics
+ module CycleAnalytics
+ class ProjectLevel
+ attr_reader :project, :options
+
+ def initialize(project:, options:)
+ @project = project
+ @options = options.merge(project: project)
+ end
+
+ def summary
+ @summary ||= ::Gitlab::CycleAnalytics::StageSummary.new(project,
+ options: options,
+ current_user: options[:current_user]).data
+ end
+
+ def permissions(user:)
+ Gitlab::CycleAnalytics::Permissions.get(user: user, project: project)
+ end
+
+ def stats
+ @stats ||= default_stage_names.map do |stage_name|
+ self[stage_name].as_json
+ end
+ end
+
+ def [](stage_name)
+ ::CycleAnalytics::ProjectLevelStageAdapter.new(build_stage(stage_name), options)
+ end
+
+ private
+
+ def build_stage(stage_name)
+ stage_params = stage_params_by_name(stage_name).merge(project: project)
+ Analytics::CycleAnalytics::ProjectStage.new(stage_params)
+ end
+
+ def stage_params_by_name(name)
+ Gitlab::Analytics::CycleAnalytics::DefaultStages.find_by_name!(name)
+ end
+
+ def default_stage_names
+ Gitlab::Analytics::CycleAnalytics::DefaultStages.symbolized_stage_names
+ end
+ end
+ end
+end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 14ec3a6838c..71110ef0696 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -134,6 +134,8 @@ module Ci
end
scope :order_contacted_at_asc, -> { order(contacted_at: :asc) }
+ scope :order_contacted_at_desc, -> { order(contacted_at: :desc) }
+ scope :order_created_at_asc, -> { order(created_at: :asc) }
scope :order_created_at_desc, -> { order(created_at: :desc) }
scope :with_tags, -> { preload(:tags) }
@@ -190,8 +192,13 @@ module Ci
end
def self.order_by(order)
- if order == 'contacted_asc'
+ case order
+ when 'contacted_asc'
order_contacted_at_asc
+ when 'contacted_desc'
+ order_contacted_at_desc
+ when 'created_at_asc'
+ order_created_at_asc
else
order_created_at_desc
end
diff --git a/app/models/clusters/applications/fluentd.rb b/app/models/clusters/applications/fluentd.rb
index 8d0bf7b6321..c5d674c1908 100644
--- a/app/models/clusters/applications/fluentd.rb
+++ b/app/models/clusters/applications/fluentd.rb
@@ -12,11 +12,13 @@ module Clusters
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
+ include IgnorableColumns
default_value_for :version, VERSION
default_value_for :port, 514
default_value_for :protocol, :tcp
- default_value_for :waf_log_enabled, false
+
+ ignore_column :waf_log_enabled, remove_with: '14.2', remove_after: '2021-07-22'
enum protocol: { tcp: 0, udp: 1 }
@@ -48,9 +50,7 @@ module Clusters
private
def has_at_least_one_log_enabled?
- if !waf_log_enabled && !cilium_log_enabled
- errors.add(:base, _("At least one logging option is required to be enabled"))
- end
+ errors.add(:base, _("At least one logging option is required to be enabled")) unless cilium_log_enabled
end
def content_values
@@ -113,7 +113,6 @@ module Clusters
def path_to_logs
path = []
- path << "/var/log/containers/*#{Ingress::MODSECURITY_LOG_CONTAINER_NAME}*.log" if waf_log_enabled
path << "/var/log/containers/*#{CILIUM_CONTAINER_NAME}*.log" if cilium_log_enabled
path.join(',')
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index e7d4d737b8e..3a8c314efe4 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -7,10 +7,6 @@ module Clusters
class Ingress < ApplicationRecord
VERSION = '1.40.2'
INGRESS_CONTAINER_NAME = 'nginx-ingress-controller'
- MODSECURITY_LOG_CONTAINER_NAME = 'modsecurity-log'
- MODSECURITY_MODE_LOGGING = "DetectionOnly"
- MODSECURITY_MODE_BLOCKING = "On"
- MODSECURITY_OWASP_RULES_FILE = "/etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf"
self.table_name = 'clusters_applications_ingress'
@@ -20,22 +16,18 @@ module Clusters
include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
include UsageStatistics
+ include IgnorableColumns
default_value_for :ingress_type, :nginx
- default_value_for :modsecurity_enabled, true
default_value_for :version, VERSION
- default_value_for :modsecurity_mode, :logging
+
+ ignore_column :modsecurity_enabled, remove_with: '14.2', remove_after: '2021-07-22'
+ ignore_column :modsecurity_mode, remove_with: '14.2', remove_after: '2021-07-22'
enum ingress_type: {
nginx: 1
}
- enum modsecurity_mode: { logging: 0, blocking: 1 }
-
- scope :modsecurity_not_installed, -> { where(modsecurity_enabled: nil) }
- scope :modsecurity_enabled, -> { where(modsecurity_enabled: true) }
- scope :modsecurity_disabled, -> { where(modsecurity_enabled: false) }
-
FETCH_IP_ADDRESS_DELAY = 30.seconds
state_machine :status do
@@ -92,96 +84,13 @@ module Clusters
private
- def specification
- return {} unless modsecurity_enabled
-
- {
- "controller" => {
- "config" => {
- "enable-modsecurity" => "true",
- "enable-owasp-modsecurity-crs" => "false",
- "modsecurity-snippet" => modsecurity_snippet_content,
- "modsecurity.conf" => modsecurity_config_content
- },
- "extraContainers" => [
- {
- "name" => MODSECURITY_LOG_CONTAINER_NAME,
- "image" => "busybox",
- "args" => [
- "/bin/sh",
- "-c",
- "tail -F /var/log/modsec/audit.log"
- ],
- "volumeMounts" => [
- {
- "name" => "modsecurity-log-volume",
- "mountPath" => "/var/log/modsec",
- "readOnly" => true
- }
- ],
- "livenessProbe" => {
- "exec" => {
- "command" => [
- "ls",
- "/var/log/modsec/audit.log"
- ]
- }
- }
- }
- ],
- "extraVolumeMounts" => [
- {
- "name" => "modsecurity-template-volume",
- "mountPath" => "/etc/nginx/modsecurity/modsecurity.conf",
- "subPath" => "modsecurity.conf"
- },
- {
- "name" => "modsecurity-log-volume",
- "mountPath" => "/var/log/modsec"
- }
- ],
- "extraVolumes" => [
- {
- "name" => "modsecurity-template-volume",
- "configMap" => {
- "name" => "ingress-#{INGRESS_CONTAINER_NAME}",
- "items" => [
- {
- "key" => "modsecurity.conf",
- "path" => "modsecurity.conf"
- }
- ]
- }
- },
- {
- "name" => "modsecurity-log-volume",
- "emptyDir" => {}
- }
- ]
- }
- }
- end
-
- def modsecurity_config_content
- File.read(modsecurity_config_file_path)
- end
-
- def modsecurity_config_file_path
- Rails.root.join('vendor', 'ingress', 'modsecurity.conf')
- end
-
def content_values
- YAML.load_file(chart_values_file).deep_merge!(specification)
+ YAML.load_file(chart_values_file)
end
def application_jupyter_installed?
cluster.application_jupyter&.installed?
end
-
- def modsecurity_snippet_content
- sec_rule_engine = logging? ? MODSECURITY_MODE_LOGGING : MODSECURITY_MODE_BLOCKING
- "SecRuleEngine #{sec_rule_engine}\nInclude #{MODSECURITY_OWASP_RULES_FILE}"
- end
end
end
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 257a7043ce2..aeebd2b368e 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -138,7 +138,6 @@ module Clusters
scope :gcp_installed, -> { gcp_provided.joins(:provider_gcp).merge(Clusters::Providers::Gcp.with_status(:created)) }
scope :aws_installed, -> { aws_provided.joins(:provider_aws).merge(Clusters::Providers::Aws.with_status(:created)) }
- scope :with_enabled_modsecurity, -> { joins(:application_ingress).merge(::Clusters::Applications::Ingress.modsecurity_enabled) }
scope :with_available_elasticstack, -> { joins(:application_elastic_stack).merge(::Clusters::Applications::ElasticStack.available) }
scope :with_available_cilium, -> { joins(:application_cilium).merge(::Clusters::Applications::Cilium.available) }
scope :distinct_with_deployed_environments, -> { joins(:environments).merge(::Deployment.success).distinct }
diff --git a/app/models/cycle_analytics/project_level.rb b/app/models/cycle_analytics/project_level.rb
deleted file mode 100644
index 5bd07b3f6c3..00000000000
--- a/app/models/cycle_analytics/project_level.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-module CycleAnalytics
- class ProjectLevel
- attr_reader :project, :options
-
- def initialize(project, options:)
- @project = project
- @options = options.merge(project: project)
- end
-
- def summary
- @summary ||= ::Gitlab::CycleAnalytics::StageSummary.new(project,
- from: options[:from],
- to: options[:to],
- current_user: options[:current_user]).data
- end
-
- def permissions(user:)
- Gitlab::CycleAnalytics::Permissions.get(user: user, project: project)
- end
-
- def stats
- @stats ||= default_stage_names.map do |stage_name|
- self[stage_name].as_json
- end
- end
-
- def [](stage_name)
- CycleAnalytics::ProjectLevelStageAdapter.new(build_stage(stage_name), options)
- end
-
- private
-
- def build_stage(stage_name)
- stage_params = stage_params_by_name(stage_name).merge(project: project)
- Analytics::CycleAnalytics::ProjectStage.new(stage_params)
- end
-
- def stage_params_by_name(name)
- Gitlab::Analytics::CycleAnalytics::DefaultStages.find_by_name!(name)
- end
-
- def default_stage_names
- Gitlab::Analytics::CycleAnalytics::DefaultStages.symbolized_stage_names
- end
- end
-end
diff --git a/app/models/members/last_group_owner_assigner.rb b/app/models/members/last_group_owner_assigner.rb
index 64decb1df36..dcf0a2d0ad3 100644
--- a/app/models/members/last_group_owner_assigner.rb
+++ b/app/models/members/last_group_owner_assigner.rb
@@ -1,46 +1,44 @@
# frozen_string_literal: true
-module Members
- class LastGroupOwnerAssigner
- def initialize(group, members)
- @group = group
- @members = members
- end
+class LastGroupOwnerAssigner
+ def initialize(group, members)
+ @group = group
+ @members = members
+ end
- def execute
- @last_blocked_owner = no_owners_in_heirarchy? && group.single_blocked_owner?
- @group_single_owner = owners.size == 1
+ def execute
+ @last_blocked_owner = no_owners_in_heirarchy? && group.single_blocked_owner?
+ @group_single_owner = owners.size == 1
- members.each { |member| set_last_owner(member) }
- end
+ members.each { |member| set_last_owner(member) }
+ end
- private
+ private
- attr_reader :group, :members, :last_blocked_owner, :group_single_owner
+ attr_reader :group, :members, :last_blocked_owner, :group_single_owner
- def no_owners_in_heirarchy?
- owners.empty?
- end
+ def no_owners_in_heirarchy?
+ owners.empty?
+ end
- def set_last_owner(member)
- member.last_owner = member.id.in?(owner_ids) && group_single_owner
- member.last_blocked_owner = member.id.in?(blocked_owner_ids) && last_blocked_owner
- end
+ def set_last_owner(member)
+ member.last_owner = member.id.in?(owner_ids) && group_single_owner
+ member.last_blocked_owner = member.id.in?(blocked_owner_ids) && last_blocked_owner
+ end
- def owner_ids
- @owner_ids ||= owners.where(id: member_ids).ids
- end
+ def owner_ids
+ @owner_ids ||= owners.where(id: member_ids).ids
+ end
- def blocked_owner_ids
- @blocked_owner_ids ||= group.blocked_owners.where(id: member_ids).ids
- end
+ def blocked_owner_ids
+ @blocked_owner_ids ||= group.blocked_owners.where(id: member_ids).ids
+ end
- def member_ids
- @members_ids ||= members.pluck(:id)
- end
+ def member_ids
+ @members_ids ||= members.pluck(:id)
+ end
- def owners
- @owners ||= group.members_with_parents.owners.load
- end
+ def owners
+ @owners ||= group.members_with_parents.owners.load
end
end
diff --git a/app/serializers/cluster_application_entity.rb b/app/serializers/cluster_application_entity.rb
index 6b9a3ce114b..fab590dbe09 100644
--- a/app/serializers/cluster_application_entity.rb
+++ b/app/serializers/cluster_application_entity.rb
@@ -10,15 +10,12 @@ class ClusterApplicationEntity < Grape::Entity
expose :hostname, if: -> (e, _) { e.respond_to?(:hostname) }
expose :email, if: -> (e, _) { e.respond_to?(:email) }
expose :stack, if: -> (e, _) { e.respond_to?(:stack) }
- expose :modsecurity_enabled, if: -> (e, _) { e.respond_to?(:modsecurity_enabled) }
expose :update_available?, as: :update_available, if: -> (e, _) { e.respond_to?(:update_available?) }
expose :can_uninstall?, as: :can_uninstall
expose :available_domains, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:available_domains) }
expose :pages_domain, using: Serverless::DomainEntity, if: -> (e, _) { e.respond_to?(:pages_domain) }
- expose :modsecurity_mode, if: -> (e, _) { e.respond_to?(:modsecurity_mode) }
expose :host, if: -> (e, _) { e.respond_to?(:host) }
expose :port, if: -> (e, _) { e.respond_to?(:port) }
expose :protocol, if: -> (e, _) { e.respond_to?(:protocol) }
- expose :waf_log_enabled, if: -> (e, _) { e.respond_to?(:waf_log_enabled) }
expose :cilium_log_enabled, if: -> (e, _) { e.respond_to?(:cilium_log_enabled) }
end
diff --git a/app/serializers/member_serializer.rb b/app/serializers/member_serializer.rb
index 462f6be5d04..ad258b0ef1e 100644
--- a/app/serializers/member_serializer.rb
+++ b/app/serializers/member_serializer.rb
@@ -4,7 +4,7 @@ class MemberSerializer < BaseSerializer
entity MemberEntity
def represent(members, opts = {})
- Members::LastGroupOwnerAssigner.new(opts[:group], members).execute unless opts[:source].is_a?(Project)
+ LastGroupOwnerAssigner.new(opts[:group], members).execute unless opts[:source].is_a?(Project)
super(members, opts)
end
diff --git a/app/services/clusters/applications/base_service.rb b/app/services/clusters/applications/base_service.rb
index 489360f9070..47d6fbbeda2 100644
--- a/app/services/clusters/applications/base_service.rb
+++ b/app/services/clusters/applications/base_service.rb
@@ -29,14 +29,6 @@ module Clusters
application.stack = params[:stack]
end
- if application.has_attribute?(:modsecurity_enabled)
- application.modsecurity_enabled = params[:modsecurity_enabled] || false
- end
-
- if application.has_attribute?(:modsecurity_mode)
- application.modsecurity_mode = params[:modsecurity_mode] || 0
- end
-
apply_fluentd_related_attributes(application)
if application.respond_to?(:oauth_application)
diff --git a/app/views/admin/application_settings/_diff_limits.html.haml b/app/views/admin/application_settings/_diff_limits.html.haml
index 7286fffcaf6..ff22f6181b3 100644
--- a/app/views/admin/application_settings/_diff_limits.html.haml
+++ b/app/views/admin/application_settings/_diff_limits.html.haml
@@ -3,13 +3,11 @@
%fieldset
.form-group
- = f.label :diff_max_patch_bytes, 'Maximum diff patch size (Bytes)', class: 'label-light'
+ = f.label :diff_max_patch_bytes, 'Maximum diff patch size in bytes', class: 'label-light'
= f.number_field :diff_max_patch_bytes, class: 'form-control gl-form-input'
%span.form-text.text-muted
- Diff files surpassing this limit will be presented as 'too large'
- and won't be expandable.
+ Collapse diffs larger than this size, and show a 'too large' message instead.
= link_to sprite_icon('question-o'),
- help_page_path('user/admin_area/diff_limits',
- anchor: 'maximum-diff-patch-size')
+ help_page_path('user/admin_area/diff_limits')
= f.submit _('Save changes'), class: 'gl-button btn btn-confirm'
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index 3f1c363bcb9..0fbbef02613 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -31,7 +31,7 @@
%button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
- = _('Diff content limits')
+ = _('Set size limits for displaying diffs in the browser.')
.settings-content
= render 'diff_limits'
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 267fc3ae986..0716eda79a8 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -10,7 +10,8 @@
project_name: @project.name,
project_path: @project.path,
project_description: @project.description,
- project_visibility: @project.visibility } }
+ project_visibility: @project.visibility,
+ restricted_visibility_levels: Gitlab::CurrentSettings.restricted_visibility_levels.to_json } }
- else
.row.gl-mt-3
.col-lg-3
diff --git a/app/views/shared/issuable/form/_branch_chooser.html.haml b/app/views/shared/issuable/form/_branch_chooser.html.haml
index 70e931ac164..1f391e8a321 100644
--- a/app/views/shared/issuable/form/_branch_chooser.html.haml
+++ b/app/views/shared/issuable/form/_branch_chooser.html.haml
@@ -37,10 +37,12 @@
data: { placeholder: _('Select branch'), endpoint: refs_project_path(@project, sort: 'updated_desc', find: 'branches') }})
- if source_level < target_level
- .gl-alert.gl-alert-warning.gl-mt-4
- = sprite_icon('warning', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
- .gl-alert-body
- = visibilityMismatchString
- %br
- = _('Review the target project before submitting to avoid exposing %{source} changes.') % { source: source_visibility }
+ .gl-alert.gl-alert-warning.gl-alert-not-dismissible.gl-max-content.gl-mt-4
+ .gl-alert-container
+ .gl-alert-content{ role: 'alert' }
+ = sprite_icon('warning', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ = visibilityMismatchString
+ %br
+ = _('Review the target project before submitting to avoid exposing %{source} changes.') % { source: source_visibility }
%hr
diff --git a/app/workers/ssh_keys/expired_notification_worker.rb b/app/workers/ssh_keys/expired_notification_worker.rb
index e8baf0c28dd..b67849942b0 100644
--- a/app/workers/ssh_keys/expired_notification_worker.rb
+++ b/app/workers/ssh_keys/expired_notification_worker.rb
@@ -15,8 +15,6 @@ module SshKeys
# rubocop: disable CodeReuse/ActiveRecord
def perform
- return unless ::Feature.enabled?(:ssh_key_expiration_email_notification, default_enabled: :yaml)
-
order = Gitlab::Pagination::Keyset::Order.build([
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
attribute_name: 'expires_at_utc',
diff --git a/app/workers/ssh_keys/expiring_soon_notification_worker.rb b/app/workers/ssh_keys/expiring_soon_notification_worker.rb
index 1ec655b5cf5..d87e31c36a5 100644
--- a/app/workers/ssh_keys/expiring_soon_notification_worker.rb
+++ b/app/workers/ssh_keys/expiring_soon_notification_worker.rb
@@ -12,8 +12,6 @@ module SshKeys
idempotent!
def perform
- return unless ::Feature.enabled?(:ssh_key_expiration_email_notification, default_enabled: :yaml)
-
# rubocop:disable CodeReuse/ActiveRecord
User.with_ssh_key_expiring_soon.find_each(batch_size: 10_000) do |user|
with_context(user: user) do
diff --git a/config/feature_flags/development/background_pipeline_retry_endpoint.yml b/config/feature_flags/development/background_pipeline_retry_endpoint.yml
deleted file mode 100644
index 57f90d01e2c..00000000000
--- a/config/feature_flags/development/background_pipeline_retry_endpoint.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: background_pipeline_retry_endpoint
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61270
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/330915
-milestone: '13.12'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/ci_dynamic_child_pipeline.yml b/config/feature_flags/development/ci_dynamic_child_pipeline.yml
deleted file mode 100644
index ad4b7bcadb2..00000000000
--- a/config/feature_flags/development/ci_dynamic_child_pipeline.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_dynamic_child_pipeline
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23790
-rollout_issue_url:
-milestone: '12.9'
-type: development
-group: group::pipeline execution
-default_enabled: true
diff --git a/config/feature_flags/development/remove_release_notes_from_tags_api.yml b/config/feature_flags/development/sidekiq_load_balancing_rotate_up_to_date_replica.yml
index 6fb26d9bea5..4532cc0a59d 100644
--- a/config/feature_flags/development/remove_release_notes_from_tags_api.yml
+++ b/config/feature_flags/development/sidekiq_load_balancing_rotate_up_to_date_replica.yml
@@ -1,8 +1,8 @@
---
-name: remove_release_notes_from_tags_api
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63392
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/290311
+name: sidekiq_load_balancing_rotate_up_to_date_replica
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63413/
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/333153
milestone: '14.0'
type: development
-group: group::release
+group: group::memory
default_enabled: false
diff --git a/config/feature_flags/development/ssh_key_expiration_email_notification.yml b/config/feature_flags/development/ssh_key_expiration_email_notification.yml
deleted file mode 100644
index f1d081dad18..00000000000
--- a/config/feature_flags/development/ssh_key_expiration_email_notification.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ssh_key_expiration_email_notification
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56888
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326386
-milestone: '13.11'
-type: development
-group: group::compliance
-default_enabled: true
diff --git a/config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml b/config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml
deleted file mode 100644
index f4eb1e39947..00000000000
--- a/config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml
+++ /dev/null
@@ -1,16 +0,0 @@
----
-key_path: usage_activity_by_stage_monthly.secure.dependency_scanning_scans
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
-value_type: number
-status: data_available
-time_frame: 28d
-data_source:
-distribution:
-- ce
-tier:
-- free
-skip_validation: true
diff --git a/config/metrics/license/20210204124854_license_management_jobs.yml b/config/metrics/license/20210204124854_license_management_jobs.yml
deleted file mode 100644
index 81e3e17e24b..00000000000
--- a/config/metrics/license/20210204124854_license_management_jobs.yml
+++ /dev/null
@@ -1,17 +0,0 @@
----
-key_path: counts.license_management_jobs
-description: Name on the GitLab license
-product_section: growth
-product_stage: growth
-product_group: group::product intelligence
-product_category: collection
-value_type: number
-status: data_available
-time_frame: none
-data_source: database
-distribution:
-- ce
-tier:
-- premium
-- ultimate
-skip_validation: true
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 22db62c9e07..641ca399547 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -273,6 +273,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :value_streams, only: [:index] do
resources :stages, only: [:index]
end
+ resource :summary, controller: :summary, only: :show
end
end
diff --git a/db/migrate/20210601125410_add_runners_created_at_index.rb b/db/migrate/20210601125410_add_runners_created_at_index.rb
new file mode 100644
index 00000000000..6a6be6d8480
--- /dev/null
+++ b/db/migrate/20210601125410_add_runners_created_at_index.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddRunnersCreatedAtIndex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_runners, [:created_at, :id], order: { id: :desc }, name: 'index_ci_runners_on_created_at_and_id_desc'
+ add_concurrent_index :ci_runners, [:created_at, :id], order: { created_at: :desc, id: :desc }, name: 'index_ci_runners_on_created_at_desc_and_id_desc'
+ end
+
+ def down
+ remove_concurrent_index :ci_runners, [:created_at, :id], order: { id: :desc }, name: 'index_ci_runners_on_created_at_and_id_desc'
+ remove_concurrent_index :ci_runners, [:created_at, :id], order: { created_at: :desc, id: :desc }, name: 'index_ci_runners_on_created_at_desc_and_id_desc'
+ end
+end
diff --git a/db/migrate/20210601133459_replace_runners_contacted_at_index.rb b/db/migrate/20210601133459_replace_runners_contacted_at_index.rb
new file mode 100644
index 00000000000..a0a933721f0
--- /dev/null
+++ b/db/migrate/20210601133459_replace_runners_contacted_at_index.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# See https://docs.gitlab.com/ee/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class ReplaceRunnersContactedAtIndex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ OLD_INDEX_NAME = 'index_ci_runners_on_contacted_at'
+
+ def up
+ add_concurrent_index :ci_runners, [:contacted_at, :id], order: { id: :desc }, name: 'index_ci_runners_on_contacted_at_and_id_desc', using: 'btree'
+ add_concurrent_index :ci_runners, [:contacted_at, :id], order: { contacted_at: :desc, id: :desc }, name: 'index_ci_runners_on_contacted_at_desc_and_id_desc', using: 'btree'
+
+ remove_concurrent_index_by_name :ci_runners, OLD_INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_runners, 'index_ci_runners_on_contacted_at_and_id_desc'
+ remove_concurrent_index_by_name :ci_runners, 'index_ci_runners_on_contacted_at_desc_and_id_desc'
+
+ add_concurrent_index :ci_runners, :contacted_at, name: OLD_INDEX_NAME, using: 'btree'
+ end
+end
diff --git a/db/schema_migrations/20210601125410 b/db/schema_migrations/20210601125410
new file mode 100644
index 00000000000..241a60e966a
--- /dev/null
+++ b/db/schema_migrations/20210601125410
@@ -0,0 +1 @@
+fc500e4dd555a6baad91ad3c9fb8a2f8541e1613dd64afdbdd28b19447a28caf \ No newline at end of file
diff --git a/db/schema_migrations/20210601133459 b/db/schema_migrations/20210601133459
new file mode 100644
index 00000000000..2f40fffa40f
--- /dev/null
+++ b/db/schema_migrations/20210601133459
@@ -0,0 +1 @@
+4dcf6277439e8abe52534540100fa621fedcecb3eaf71ad5685ac0230cd2e5bb \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 05cbb357513..3c96987bb5c 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -22904,7 +22904,13 @@ CREATE INDEX index_ci_runner_projects_on_project_id ON ci_runner_projects USING
CREATE INDEX index_ci_runner_projects_on_runner_id ON ci_runner_projects USING btree (runner_id);
-CREATE INDEX index_ci_runners_on_contacted_at ON ci_runners USING btree (contacted_at);
+CREATE INDEX index_ci_runners_on_contacted_at_and_id_desc ON ci_runners USING btree (contacted_at, id DESC);
+
+CREATE INDEX index_ci_runners_on_contacted_at_desc_and_id_desc ON ci_runners USING btree (contacted_at DESC, id DESC);
+
+CREATE INDEX index_ci_runners_on_created_at_and_id_desc ON ci_runners USING btree (created_at, id DESC);
+
+CREATE INDEX index_ci_runners_on_created_at_desc_and_id_desc ON ci_runners USING btree (created_at DESC, id DESC);
CREATE INDEX index_ci_runners_on_description_trigram ON ci_runners USING gin (description gin_trgm_ops);
diff --git a/doc/administration/file_hooks.md b/doc/administration/file_hooks.md
index 159f46a1146..f73c961f541 100644
--- a/doc/administration/file_hooks.md
+++ b/doc/administration/file_hooks.md
@@ -63,8 +63,11 @@ need to restart GitLab to apply a new file hook.
If a file hook executes with non-zero exit code or GitLab fails to execute it, a
message is logged to:
-- `gitlab-rails/plugin.log` in an Omnibus installation.
-- `log/plugin.log` in a source installation.
+- `gitlab-rails/file_hook.log` in an Omnibus installation.
+- `log/file_hook.log` in a source installation.
+
+NOTE:
+Before 14.0 release, the file name was `plugin.log`
## Creating file hooks
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index be544331e8b..843f5c2d413 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -766,6 +766,7 @@ Input type: `CiCdSettingsUpdateInput`
| ---- | ---- | ----------- |
| <a id="mutationcicdsettingsupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcicdsettingsupdatefullpath"></a>`fullPath` | [`ID!`](#id) | Full Path of the project the settings belong to. |
+| <a id="mutationcicdsettingsupdatejobtokenscopeenabled"></a>`jobTokenScopeEnabled` | [`Boolean`](#boolean) | Indicates CI job tokens generated in this project have restricted access to resources. |
| <a id="mutationcicdsettingsupdatekeeplatestartifact"></a>`keepLatestArtifact` | [`Boolean`](#boolean) | Indicates if the latest artifact should be kept for this project. |
| <a id="mutationcicdsettingsupdatemergepipelinesenabled"></a>`mergePipelinesEnabled` | [`Boolean`](#boolean) | Indicates if merge pipelines are enabled for the project. |
| <a id="mutationcicdsettingsupdatemergetrainsenabled"></a>`mergeTrainsEnabled` | [`Boolean`](#boolean) | Indicates if merge trains are enabled for the project. |
@@ -11853,6 +11854,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="projectcicdsettingjobtokenscopeenabled"></a>`jobTokenScopeEnabled` | [`Boolean`](#boolean) | Indicates CI job tokens generated in this project have restricted access to resources. |
| <a id="projectcicdsettingkeeplatestartifact"></a>`keepLatestArtifact` | [`Boolean`](#boolean) | Whether to keep the latest builds artifacts. |
| <a id="projectcicdsettingmergepipelinesenabled"></a>`mergePipelinesEnabled` | [`Boolean`](#boolean) | Whether merge pipelines are enabled. |
| <a id="projectcicdsettingmergetrainsenabled"></a>`mergeTrainsEnabled` | [`Boolean`](#boolean) | Whether merge trains are enabled. |
@@ -13841,7 +13843,9 @@ Values for sorting runners.
| Value | Description |
| ----- | ----------- |
| <a id="cirunnersortcontacted_asc"></a>`CONTACTED_ASC` | Ordered by contacted_at in ascending order. |
-| <a id="cirunnersortcreated_desc"></a>`CREATED_DESC` | Ordered by created_date in descending order. |
+| <a id="cirunnersortcontacted_desc"></a>`CONTACTED_DESC` | Ordered by contacted_at in descending order. |
+| <a id="cirunnersortcreated_asc"></a>`CREATED_ASC` | Ordered by created_at in ascending order. |
+| <a id="cirunnersortcreated_desc"></a>`CREATED_DESC` | Ordered by created_at in descending order. |
### `CiRunnerStatus`
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 3ac4e8bb6ab..53a981256aa 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -123,7 +123,6 @@ Parameters:
| `tag_name` | string | yes | The name of a tag |
| `ref` | string | yes | Create tag using commit SHA, another tag name, or branch name |
| `message` | string | no | Creates annotated tag |
-| `release_description` | string | no | This parameter is [deprecated](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41766) for use in GitLab 11.7, and is planned for [removal](https://gitlab.com/gitlab-org/gitlab/-/issues/290311) in GitLab 14.0. Use the [Releases API](../api/releases/index.md) instead. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/repository/tags?tag_name=test&ref=master"
@@ -149,10 +148,7 @@ Example response:
"committer_email": "jack@example.com",
"committed_date": "2012-05-28T04:42:42-07:00"
},
- "release": {
- "tag_name": "1.0.0",
- "description": "Amazing release. Wow"
- },
+ "release": null,
"name": "v1.0.0",
"target": "2695effb5807a22ff3d138d593fd856244e155e7",
"message": null,
@@ -182,82 +178,3 @@ Parameters:
| ---------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `tag_name` | string | yes | The name of a tag |
-
-## Create a new release
-
-WARNING:
-This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41766)
-for use in GitLab 11.7, and is planned for [removal](https://gitlab.com/gitlab-org/gitlab/-/issues/290311)
-in GitLab 14.0. Use the [Releases API](../api/releases/index.md) instead.
-
-Add release notes to the existing Git tag. If there
-already exists a release for the given tag, status code `409` is returned.
-
-```plaintext
-POST /projects/:id/repository/tags/:tag_name/release
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| ---------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `tag_name` | string | yes | The name of a tag |
-
-Request body:
-
-- `description` (required) - Release notes with Markdown support
-
-```json
-{
- "description": "Amazing release. Wow"
-}
-```
-
-Response:
-
-```json
-{
- "tag_name": "1.0.0",
- "description": "Amazing release. Wow"
-}
-```
-
-## Update a release
-
-WARNING:
-This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41766)
-for use in GitLab 11.7, and is planned for [removal](https://gitlab.com/gitlab-org/gitlab/-/issues/290311)
-in GitLab 14.0. Use the [Releases API](../api/releases/index.md) instead.
-
-Updates the release notes of a given release.
-
-```plaintext
-PUT /projects/:id/repository/tags/:tag_name/release
-```
-
-Parameters:
-
-| Attribute | Type | Required | Description |
-| ---------- | -------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `tag_name` | string | yes | The name of a tag |
-
-Request body:
-
-- `description` (required) - Release notes with Markdown support
-
-```json
-{
- "description": "Amazing release. Wow"
-}
-```
-
-Response:
-
-```json
-{
- "tag_name": "1.0.0",
- "description": "Amazing release. Wow"
-}
-```
diff --git a/doc/development/appsec/index.md b/doc/development/appsec/index.md
index e8ce885e75d..2ece3fdf4bf 100644
--- a/doc/development/appsec/index.md
+++ b/doc/development/appsec/index.md
@@ -20,7 +20,7 @@ the feature categories in the [Secure](https://about.gitlab.com/stages-devops-li
- `AppSec::ContainerScanning`: Container Scanning code.
- `AppSec::Dast`: DAST code.
- `AppSec::DependencyScanning`: Dependency Scanning code.
- - `AppSec::Fuzzing::Api`: API Fuzzing code.
+ - `AppSec::Fuzzing::API`: API Fuzzing code.
- `AppSec::Fuzzing::Coverage`: Coverage Fuzzing code.
- `AppSec::Fuzzing`: Shared fuzzing code.
- `AppSec::LicenseCompliance`: License Compliance code.
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index aae62801b62..92a4a13b27d 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -3288,15 +3288,15 @@ Tiers: `free`
### `counts.license_management_jobs`
-Name on the GitLab license
+Count of License Scanning jobs run
-[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/license/20210204124854_license_management_jobs.yml)
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210204124854_license_management_jobs.yml)
-Group: `group::product intelligence`
+Group: `group::composition analysis`
Status: `data_available`
-Tiers: `premium`, `ultimate`
+Tiers: `ultimate`
### `counts.licenses_list_views`
@@ -17320,7 +17320,7 @@ Tiers:
### `usage_activity_by_stage.secure.dependency_scanning_scans`
-Counts dependency scanning jobs
+Total number of users running Dependency Scanning Scans
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216175220_dependency_scanning_scans.yml)
@@ -17416,7 +17416,7 @@ Tiers: `free`
### `usage_activity_by_stage.secure.user_dependency_scanning_jobs`
-no idea, Count of Dependency Scanning jobs run, it implies user but AFAIK we don't track per user
+Total number of users running Dependency Scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216175216_user_dependency_scanning_jobs.yml)
@@ -17428,9 +17428,9 @@ Tiers: `ultimate`
### `usage_activity_by_stage.secure.user_license_management_jobs`
-no idea, Count of License Scanning jobs run, it implies user but AFAIK we don't track per user
+Total number of users running License Scanning jobs
-[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/license/20210216175218_user_license_management_jobs.yml)
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216175218_user_license_management_jobs.yml)
Group: `group::composition analysis`
@@ -19324,7 +19324,7 @@ Tiers: `free`
### `usage_activity_by_stage_monthly.secure.dependency_scanning_pipeline`
-no idea, what is this when did it get added? guess pipelines containing a DS job
+Count of pipelines with successful Dependency Scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216175226_dependency_scanning_pipeline.yml)
@@ -19336,15 +19336,15 @@ Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.dependency_scanning_scans`
-Missing description
+Monthly number of users running Dependency Scanning Scans
-[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml)
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216183828_dependency_scanning_scans.yml)
-Group: ``
+Group: `group::composition analysis`
Status: `data_available`
-Tiers: `free`
+Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.sast_pipeline`
@@ -19456,7 +19456,7 @@ Tiers: `free`
### `usage_activity_by_stage_monthly.secure.user_dependency_scanning_jobs`
-no idea, Count of Dependency Scanning jobs run, it implies user and monthly, but AFAIK we don't track per user
+Monthly number of users creating Dependency Scanning jobs
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216175222_user_dependency_scanning_jobs.yml)
@@ -19468,9 +19468,9 @@ Tiers: `ultimate`
### `usage_activity_by_stage_monthly.secure.user_license_management_jobs`
-no idea, Count of License Scanning jobs run, it implies user and monthly, but AFAIK we don't track per user
+Monthly number of users running License Scanning jobs
-[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/license/20210216175224_user_license_management_jobs.yml)
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210216175224_user_license_management_jobs.yml)
Group: `group::composition analysis`
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index c0d232ba491..b9410be791e 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -176,6 +176,7 @@ Users are notified of the following events:
| Event | Sent to | Settings level |
|------------------------------|---------------------|------------------------------|
| New SSH key added | User | Security email, always sent. |
+| SSH key has expired | User | Security email, always sent. |
| New email added | User | Security email, always sent. |
| Email changed | User | Security email, always sent. |
| Password changed | User | Security email, always sent when user changes their own password |
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index d27cc5498bd..6c332870228 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -23,7 +23,7 @@ module API
expose :issue_type,
as: :type,
format_with: :upcase,
- documentation: { type: "String", desc: "One of #{Issue.issue_types.keys.map(&:upcase)}" }
+ documentation: { type: "String", desc: "One of #{::Issue.issue_types.keys.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index dc9f4cda3d7..6c8e2c69a6d 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -51,14 +51,12 @@ module API
end
desc 'Create a new repository tag' do
- detail 'This optional release_description parameter was deprecated in GitLab 11.7.'
success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
requires :ref, type: String, desc: 'The commit sha or branch name'
optional :message, type: String, desc: 'Specifying a message creates an annotated tag'
- optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database (deprecated in GitLab 11.7)'
end
post ':id/repository/tags', :release_orchestration do
deprecate_release_notes unless params[:release_description].blank?
@@ -69,19 +67,6 @@ module API
.execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
- # Release creation with Tags API was deprecated in GitLab 11.7
- if params[:release_description].present?
- release_create_params = {
- tag: params[:tag_name],
- name: params[:tag_name], # Name can be specified in new API
- description: params[:release_description]
- }
-
- ::Releases::CreateService
- .new(user_project, current_user, release_create_params)
- .execute
- end
-
present result[:tag],
with: Entities::Tag,
project: user_project
@@ -111,82 +96,6 @@ module API
end
end
end
-
- desc 'Add a release note to a tag' do
- detail 'This feature was deprecated in GitLab 11.7.'
- success Entities::TagRelease
- end
- params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- requires :description, type: String, desc: 'Release notes with markdown support'
- end
- post ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :release_orchestration do
- deprecate_release_notes
- authorize_create_release!
-
- ##
- # Legacy API does not support tag auto creation.
- not_found!('Tag') unless user_project.repository.find_tag(params[:tag])
-
- release_create_params = {
- tag: params[:tag],
- name: params[:tag], # Name can be specified in new API
- description: params[:description]
- }
-
- result = ::Releases::CreateService
- .new(user_project, current_user, release_create_params)
- .execute
-
- if result[:status] == :success
- present result[:release], with: Entities::TagRelease
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
-
- desc "Update a tag's release note" do
- detail 'This feature was deprecated in GitLab 11.7.'
- success Entities::TagRelease
- end
- params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- requires :description, type: String, desc: 'Release notes with markdown support'
- end
- put ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS, feature_category: :release_orchestration do
- deprecate_release_notes
- authorize_update_release!
-
- result = ::Releases::UpdateService
- .new(user_project, current_user, declared_params(include_missing: false))
- .execute
-
- if result[:status] == :success
- present result[:release], with: Entities::TagRelease
- else
- render_api_error!(result[:message], result[:http_status])
- end
- end
- end
-
- helpers do
- def authorize_create_release!
- authorize! :create_release, user_project
- end
-
- def authorize_update_release!
- authorize! :update_release, release
- end
-
- def release
- @release ||= user_project.releases.find_by_tag(params[:tag])
- end
-
- def deprecate_release_notes
- return unless Feature.enabled?(:remove_release_notes_from_tags_api, user_project, default_enabled: :yaml)
-
- render_api_error!("Release notes modification via tags API is deprecated, see https://gitlab.com/gitlab-org/gitlab/-/issues/290311", 400)
- end
end
end
end
diff --git a/lib/gitlab/ci/config/external/file/artifact.rb b/lib/gitlab/ci/config/external/file/artifact.rb
index a8f78b62d8d..e6ff33d6f79 100644
--- a/lib/gitlab/ci/config/external/file/artifact.rb
+++ b/lib/gitlab/ci/config/external/file/artifact.rb
@@ -28,11 +28,6 @@ module Gitlab
end
end
- def matching?
- super &&
- Feature.enabled?(:ci_dynamic_child_pipeline, project, default_enabled: true)
- end
-
private
def project
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index d772024542c..fe69a170404 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -41,10 +41,6 @@ module Gitlab
def self.gldropdown_tags_enabled?
::Feature.enabled?(:gldropdown_tags, default_enabled: :yaml)
end
-
- def self.background_pipeline_retry_endpoint?(project)
- ::Feature.enabled?(:background_pipeline_retry_endpoint, project)
- end
end
end
end
diff --git a/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml b/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
index 4dc88418671..07d0de5f9e5 100644
--- a/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
@@ -16,7 +16,7 @@ build-job: # This job runs in the build stage, which runs first.
stage: build
script:
- echo "Compiling the code..."
- - echo "Compile complete.
+ - echo "Compile complete."
unit-test-job: # This job runs in the test stage.
stage: test # It only starts when the job in the build stage completes successfully.
diff --git a/lib/gitlab/cycle_analytics/stage_summary.rb b/lib/gitlab/cycle_analytics/stage_summary.rb
index 7559cd376bf..b309802f296 100644
--- a/lib/gitlab/cycle_analytics/stage_summary.rb
+++ b/lib/gitlab/cycle_analytics/stage_summary.rb
@@ -3,10 +3,9 @@
module Gitlab
module CycleAnalytics
class StageSummary
- def initialize(project, from:, to: nil, current_user:)
+ def initialize(project, options:, current_user:)
@project = project
- @from = from
- @to = to
+ @options = options
@current_user = current_user
end
@@ -20,15 +19,15 @@ module Gitlab
private
def issue_stats
- serialize(Summary::Issue.new(project: @project, from: @from, to: @to, current_user: @current_user))
+ serialize(Summary::Issue.new(project: @project, options: @options, current_user: @current_user))
end
def commit_stats
- serialize(Summary::Commit.new(project: @project, from: @from, to: @to))
+ serialize(Summary::Commit.new(project: @project, options: @options))
end
def deployments_summary
- @deployments_summary ||= Summary::Deploy.new(project: @project, from: @from, to: @to)
+ @deployments_summary ||= Summary::Deploy.new(project: @project, options: @options)
end
def deploy_stats
@@ -39,8 +38,7 @@ module Gitlab
serialize(
Summary::DeploymentFrequency.new(
deployments: deployments_summary.value.raw_value,
- from: @from,
- to: @to),
+ options: @options),
with_unit: true
)
end
@@ -50,8 +48,7 @@ module Gitlab
end
def serialize(summary_object, with_unit: false)
- AnalyticsSummarySerializer.new.represent(
- summary_object, with_unit: with_unit)
+ AnalyticsSummarySerializer.new.represent(summary_object, with_unit: with_unit)
end
end
end
diff --git a/lib/gitlab/cycle_analytics/summary/base.rb b/lib/gitlab/cycle_analytics/summary/base.rb
index 67ad75652b0..50a8f189df0 100644
--- a/lib/gitlab/cycle_analytics/summary/base.rb
+++ b/lib/gitlab/cycle_analytics/summary/base.rb
@@ -4,10 +4,9 @@ module Gitlab
module CycleAnalytics
module Summary
class Base
- def initialize(project:, from:, to: nil)
+ def initialize(project:, options:)
@project = project
- @from = from
- @to = to
+ @options = options
end
def title
diff --git a/lib/gitlab/cycle_analytics/summary/commit.rb b/lib/gitlab/cycle_analytics/summary/commit.rb
index 1dc9d5de966..fb55c3df869 100644
--- a/lib/gitlab/cycle_analytics/summary/commit.rb
+++ b/lib/gitlab/cycle_analytics/summary/commit.rb
@@ -21,7 +21,7 @@ module Gitlab
def commits_count
return unless ref
- @commits_count ||= gitaly_commit_client.commit_count(ref, after: @from, before: @to)
+ @commits_count ||= gitaly_commit_client.commit_count(ref, after: @options[:from], before: @options[:to])
end
def gitaly_commit_client
diff --git a/lib/gitlab/cycle_analytics/summary/deploy.rb b/lib/gitlab/cycle_analytics/summary/deploy.rb
index e5bf6ef616f..ea16226a865 100644
--- a/lib/gitlab/cycle_analytics/summary/deploy.rb
+++ b/lib/gitlab/cycle_analytics/summary/deploy.rb
@@ -16,7 +16,7 @@ module Gitlab
def deployments_count
DeploymentsFinder
- .new(project: @project, finished_after: @from, finished_before: @to, status: :success, order_by: :finished_at)
+ .new(project: @project, finished_after: @options[:from], finished_before: @options[:to], status: :success, order_by: :finished_at)
.execute
.count
end
diff --git a/lib/gitlab/cycle_analytics/summary/deployment_frequency.rb b/lib/gitlab/cycle_analytics/summary/deployment_frequency.rb
index 00676a02a6f..1947866d772 100644
--- a/lib/gitlab/cycle_analytics/summary/deployment_frequency.rb
+++ b/lib/gitlab/cycle_analytics/summary/deployment_frequency.rb
@@ -6,10 +6,10 @@ module Gitlab
class DeploymentFrequency < Base
include SummaryHelper
- def initialize(deployments:, from:, to: nil, project: nil)
+ def initialize(deployments:, options:, project: nil)
@deployments = deployments
- super(project: project, from: from, to: to)
+ super(project: project, options: options)
end
def title
@@ -17,7 +17,7 @@ module Gitlab
end
def value
- @value ||= frequency(@deployments, @from, @to || Time.now)
+ @value ||= frequency(@deployments, @options[:from], @options[:to] || Time.current)
end
def unit
diff --git a/lib/gitlab/cycle_analytics/summary/issue.rb b/lib/gitlab/cycle_analytics/summary/issue.rb
index 462fd4c2d3d..34e0d34b960 100644
--- a/lib/gitlab/cycle_analytics/summary/issue.rb
+++ b/lib/gitlab/cycle_analytics/summary/issue.rb
@@ -4,10 +4,9 @@ module Gitlab
module CycleAnalytics
module Summary
class Issue < Base
- def initialize(project:, from:, to: nil, current_user:)
+ def initialize(project:, options:, current_user:)
@project = project
- @from = from
- @to = to
+ @options = options
@current_user = current_user
end
@@ -23,10 +22,18 @@ module Gitlab
def issues_count
IssuesFinder
- .new(@current_user, project_id: @project.id, created_after: @from, created_before: @to)
+ .new(@current_user, finder_params)
.execute
.count
end
+
+ def finder_params
+ @options.dup.tap do |hash|
+ hash[:created_after] = hash.delete(:from)
+ hash[:created_before] = hash.delete(:to)
+ hash[:project_id] = @project.id
+ end
+ end
end
end
end
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index f655bb46023..a833bb8491f 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -176,6 +176,20 @@ module Gitlab
true
end
+ # Returns true if there was at least one host that has caught up with the given transaction.
+ # Similar to `#select_caught_up_hosts`, picks a random host, to rotate replicas we use.
+ # Unlike `#select_caught_up_hosts`, does not iterate over all hosts if finds any.
+ def select_up_to_date_host(location)
+ all_hosts = @host_list.hosts.shuffle
+ host = all_hosts.find { |host| host.caught_up?(location) }
+
+ return false unless host
+
+ RequestStore[CACHE_KEY] = host
+
+ true
+ end
+
def set_consistent_hosts_for_request(hosts)
RequestStore[VALID_HOSTS_CACHE_KEY] = hosts
end
diff --git a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
index 3f0d39b811f..9bd0adf8dbd 100644
--- a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
+++ b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
@@ -59,7 +59,11 @@ module Gitlab
end
def replica_caught_up?(location)
- load_balancer.host.caught_up?(location)
+ if Feature.enabled?(:sidekiq_load_balancing_rotate_up_to_date_replica)
+ load_balancer.select_up_to_date_host(location)
+ else
+ load_balancer.host.caught_up?(location)
+ end
end
end
end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 3a94e109d2a..d6cc4310438 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -5,7 +5,7 @@ module Gitlab
module MigrationHelpers
include Migrations::BackgroundMigrationHelpers
include DynamicModelHelpers
- include Migrations::RenameTableHelpers
+ include RenameTableHelpers
# https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
MAX_IDENTIFIER_NAME_LENGTH = 63
diff --git a/lib/gitlab/file_hook_logger.rb b/lib/gitlab/file_hook_logger.rb
index c5e69172016..4d6a650161f 100644
--- a/lib/gitlab/file_hook_logger.rb
+++ b/lib/gitlab/file_hook_logger.rb
@@ -3,7 +3,7 @@
module Gitlab
class FileHookLogger < Gitlab::Logger
def self.file_name_noext
- 'plugin'
+ 'file_hook'
end
end
end
diff --git a/lib/gitlab/graphql.rb b/lib/gitlab/graphql.rb
deleted file mode 100644
index 74c04e5380e..00000000000
--- a/lib/gitlab/graphql.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Graphql
- StandardGraphqlError = Class.new(StandardError)
- end
-end
diff --git a/lib/gitlab/graphql/standard_graphql_error.rb b/lib/gitlab/graphql/standard_graphql_error.rb
new file mode 100644
index 00000000000..8364c232af2
--- /dev/null
+++ b/lib/gitlab/graphql/standard_graphql_error.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+# rubocop:disable Cop/CustomErrorClass
+
+module Gitlab
+ module Graphql
+ class StandardGraphqlError < StandardError
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 12b52556a72..a320412f475 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11402,9 +11402,6 @@ msgstr ""
msgid "Didn't receive unlock instructions?"
msgstr ""
-msgid "Diff content limits"
-msgstr ""
-
msgid "Diff limits"
msgstr ""
@@ -23339,6 +23336,9 @@ msgstr ""
msgid "PackageRegistry|Copy Pip command"
msgstr ""
+msgid "PackageRegistry|Copy SHA"
+msgstr ""
+
msgid "PackageRegistry|Copy add Gradle Groovy DSL repository command"
msgstr ""
@@ -29645,6 +29645,9 @@ msgstr ""
msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication."
msgstr ""
+msgid "Set size limits for displaying diffs in the browser."
+msgstr ""
+
msgid "Set target branch"
msgstr ""
@@ -39511,6 +39514,9 @@ msgstr ""
msgid "view the source"
msgstr ""
+msgid "visibility"
+msgstr ""
+
msgid "vulnerability"
msgid_plural "vulnerabilities"
msgstr[0] ""
diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build
index 26f84cd81d3..e6afadccc7e 100755
--- a/scripts/gitaly-test-build
+++ b/scripts/gitaly-test-build
@@ -18,6 +18,8 @@ class GitalyTestBuild
# If we have the binaries from the cache, we can skip building them again
if File.exist?(tmp_tests_gitaly_bin_dir)
GitalySetup::LOGGER.debug "Gitaly binary already built. Skip building...\n"
+ # We still need to install the gems in that case
+ install_gitaly_gems
else
abort 'gitaly build failed' unless build_gitaly
end
diff --git a/spec/controllers/projects/analytics/cycle_analytics/summary_controller_spec.rb b/spec/controllers/projects/analytics/cycle_analytics/summary_controller_spec.rb
new file mode 100644
index 00000000000..1832b84ab6e
--- /dev/null
+++ b/spec/controllers/projects/analytics/cycle_analytics/summary_controller_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+
+ let(:params) { { namespace_id: project.namespace.to_param, project_id: project.to_param, created_after: '2010-01-01', created_before: '2010-01-02' } }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET "show"' do
+ subject { get :show, params: params }
+
+ it 'succeeds' do
+ project.add_reporter(user)
+
+ subject
+
+ expect(response).to be_successful
+ expect(response).to match_response_schema('analytics/cycle_analytics/summary')
+ end
+
+ context 'when analytics_disabled features are disabled' do
+ it 'renders 404' do
+ project.add_reporter(user)
+ project.project_feature.update!(analytics_access_level: ProjectFeature::DISABLED)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when user is not part of the project' do
+ it 'renders 404' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 19f9e8b780b..050d5e00670 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -878,19 +878,6 @@ RSpec.describe Projects::PipelinesController do
expect(::Ci::RetryPipelineWorker).to have_received(:perform_async).with(pipeline.id, user.id)
end
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(background_pipeline_retry_endpoint: false)
- end
-
- it 'retries the pipeline without returning any content' do
- post_retry
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(build.reload).to be_retried
- end
- end
-
context 'when builds are disabled' do
let(:feature) { ProjectFeature::DISABLED }
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 1ff1292c36e..73103956ee8 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -96,26 +96,7 @@ FactoryBot.define do
end
factory :clusters_applications_ingress, class: 'Clusters::Applications::Ingress' do
- modsecurity_enabled { false }
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
-
- trait :modsecurity_blocking do
- modsecurity_enabled { true }
- modsecurity_mode { :blocking }
- end
-
- trait :modsecurity_logging do
- modsecurity_enabled { true }
- modsecurity_mode { :logging }
- end
-
- trait :modsecurity_disabled do
- modsecurity_enabled { false }
- end
-
- trait :modsecurity_not_installed do
- modsecurity_enabled { nil }
- end
end
factory :clusters_applications_cert_manager, class: 'Clusters::Applications::CertManager' do
@@ -153,7 +134,6 @@ FactoryBot.define do
factory :clusters_applications_fluentd, class: 'Clusters::Applications::Fluentd' do
host { 'example.com' }
- waf_log_enabled { true }
cilium_log_enabled { true }
cluster factory: %i(cluster with_installed_helm provided_by_gcp)
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 3cb18f21a47..cc561ef65a2 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -47,6 +47,7 @@ FactoryBot.define do
import_last_error { nil }
forward_deployment_enabled { nil }
restrict_user_defined_variables { nil }
+ ci_job_token_scope_enabled { nil }
end
before(:create) do |project, evaluator|
@@ -88,6 +89,7 @@ FactoryBot.define do
project.merge_trains_enabled = evaluator.merge_trains_enabled unless evaluator.merge_trains_enabled.nil?
project.keep_latest_artifact = evaluator.keep_latest_artifact unless evaluator.keep_latest_artifact.nil?
project.restrict_user_defined_variables = evaluator.restrict_user_defined_variables unless evaluator.restrict_user_defined_variables.nil?
+ project.ci_job_token_scope_enabled = evaluator.ci_job_token_scope_enabled unless evaluator.ci_job_token_scope_enabled.nil?
if evaluator.import_status
import_state = project.import_state || project.build_import_state
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb
index 4df026f2f5f..250a85dde30 100644
--- a/spec/finders/ci/runners_finder_spec.rb
+++ b/spec/finders/ci/runners_finder_spec.rb
@@ -51,23 +51,55 @@ RSpec.describe Ci::RunnersFinder do
end
context 'sort' do
+ let_it_be(:runner1) { create :ci_runner, created_at: '2018-07-12 07:00', contacted_at: 1.minute.ago }
+ let_it_be(:runner2) { create :ci_runner, created_at: '2018-07-12 08:00', contacted_at: 3.minutes.ago }
+ let_it_be(:runner3) { create :ci_runner, created_at: '2018-07-12 09:00', contacted_at: 2.minutes.ago }
+
+ subject do
+ described_class.new(current_user: admin, params: params).execute
+ end
+
+ shared_examples 'sorts by created_at descending' do
+ it 'sorts by created_at descending' do
+ is_expected.to eq [runner3, runner2, runner1]
+ end
+ end
+
context 'without sort param' do
- it 'sorts by created_at' do
- runner1 = create :ci_runner, created_at: '2018-07-12 07:00'
- runner2 = create :ci_runner, created_at: '2018-07-12 08:00'
- runner3 = create :ci_runner, created_at: '2018-07-12 09:00'
+ let(:params) { {} }
+
+ it_behaves_like 'sorts by created_at descending'
+ end
+
+ %w(created_date created_at_desc).each do |sort|
+ context "with sort param equal to #{sort}" do
+ let(:params) { { sort: sort } }
+
+ it_behaves_like 'sorts by created_at descending'
+ end
+ end
+
+ context 'with sort param equal to created_at_asc' do
+ let(:params) { { sort: 'created_at_asc' } }
+
+ it 'sorts by created_at ascending' do
+ is_expected.to eq [runner1, runner2, runner3]
+ end
+ end
+
+ context 'with sort param equal to contacted_asc' do
+ let(:params) { { sort: 'contacted_asc' } }
- expect(described_class.new(current_user: admin, params: {}).execute).to eq [runner3, runner2, runner1]
+ it 'sorts by contacted_at ascending' do
+ is_expected.to eq [runner2, runner3, runner1]
end
end
- context 'with sort param' do
- it 'sorts by specified attribute' do
- runner1 = create :ci_runner, contacted_at: 1.minute.ago
- runner2 = create :ci_runner, contacted_at: 3.minutes.ago
- runner3 = create :ci_runner, contacted_at: 2.minutes.ago
+ context 'with sort param equal to contacted_desc' do
+ let(:params) { { sort: 'contacted_desc' } }
- expect(described_class.new(current_user: admin, params: { sort: 'contacted_asc' }).execute).to eq [runner2, runner3, runner1]
+ it 'sorts by contacted_at descending' do
+ is_expected.to eq [runner1, runner3, runner2]
end
end
end
@@ -246,8 +278,8 @@ RSpec.describe Ci::RunnersFinder do
subject { described_class.new(current_user: user, group: group, params: params).sort_key }
context 'no params' do
- it 'returns created_date' do
- expect(subject).to eq('created_date')
+ it 'returns created_at_desc' do
+ expect(subject).to eq('created_at_desc')
end
end
diff --git a/spec/fixtures/api/schemas/analytics/cycle_analytics/summary.json b/spec/fixtures/api/schemas/analytics/cycle_analytics/summary.json
new file mode 100644
index 00000000000..73904438ede
--- /dev/null
+++ b/spec/fixtures/api/schemas/analytics/cycle_analytics/summary.json
@@ -0,0 +1,21 @@
+{
+ "type": "array",
+ "items": {
+ "minItems": 2,
+ "maxItems": 3,
+ "type": "object",
+ "required": ["value", "title"],
+ "properties": {
+ "value": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "unit": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+ }
+}
diff --git a/spec/fixtures/api/schemas/cluster_status.json b/spec/fixtures/api/schemas/cluster_status.json
index f6db336fe65..c919cd54a28 100644
--- a/spec/fixtures/api/schemas/cluster_status.json
+++ b/spec/fixtures/api/schemas/cluster_status.json
@@ -42,7 +42,6 @@
"host": {"type": ["string", "null"]},
"port": {"type": ["integer", "514"]},
"protocol": {"type": ["integer", "0"]},
- "waf_log_enabled": {"type": ["boolean", "true"]},
"cilium_log_enabled": {"type": ["boolean", "true"]},
"update_available": { "type": ["boolean", "null"] },
"can_uninstall": { "type": "boolean" },
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index bffe108896a..305d3de3c53 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -471,6 +471,7 @@ describe('URL utility', () => {
${'notaurl'} | ${false}
${'../relative_url'} | ${false}
${'<a></a>'} | ${false}
+ ${'//other-host.test'} | ${false}
`('returns $valid for $url', ({ url, valid }) => {
expect(urlUtils.isRootRelative(url)).toBe(valid);
});
diff --git a/spec/frontend/packages/details/components/__snapshots__/file_sha_spec.js.snap b/spec/frontend/packages/details/components/__snapshots__/file_sha_spec.js.snap
new file mode 100644
index 00000000000..881d441e116
--- /dev/null
+++ b/spec/frontend/packages/details/components/__snapshots__/file_sha_spec.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FileSha renders 1`] = `
+<div
+ class="gl-display-flex gl-align-items-center gl-font-monospace gl-font-sm gl-word-break-all gl-py-2 gl-border-b-solid gl-border-gray-100 gl-border-b-1"
+>
+ <!---->
+
+ <span>
+ <div
+ class="gl-px-4"
+ >
+
+ bar:
+ foo
+
+ <gl-button-stub
+ aria-label="Copy this value"
+ buttontextclasses=""
+ category="tertiary"
+ data-clipboard-text="foo"
+ icon="copy-to-clipboard"
+ size="small"
+ title="Copy SHA"
+ variant="default"
+ />
+ </div>
+ </span>
+</div>
+`;
diff --git a/spec/frontend/packages/details/components/file_sha_spec.js b/spec/frontend/packages/details/components/file_sha_spec.js
new file mode 100644
index 00000000000..7bfcf78baab
--- /dev/null
+++ b/spec/frontend/packages/details/components/file_sha_spec.js
@@ -0,0 +1,33 @@
+import { shallowMount } from '@vue/test-utils';
+
+import FileSha from '~/packages/details/components/file_sha.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
+
+describe('FileSha', () => {
+ let wrapper;
+
+ const defaultProps = { sha: 'foo', title: 'bar' };
+
+ function createComponent() {
+ wrapper = shallowMount(FileSha, {
+ propsData: {
+ ...defaultProps,
+ },
+ stubs: {
+ ClipboardButton,
+ DetailsRow,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders', () => {
+ createComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/packages/details/components/package_files_spec.js b/spec/frontend/packages/details/components/package_files_spec.js
index 494aa631d9d..e8e5a24d3a3 100644
--- a/spec/frontend/packages/details/components/package_files_spec.js
+++ b/spec/frontend/packages/details/components/package_files_spec.js
@@ -1,5 +1,6 @@
-import { GlDropdown } from '@gitlab/ui';
+import { GlDropdown, GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue/';
import stubChildren from 'helpers/stub_children';
import component from '~/packages/details/components/package_files.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
@@ -20,6 +21,8 @@ describe('Package Files', () => {
const findFirstRowCreatedAt = () => findFirstRow().find(TimeAgoTooltip);
const findFirstActionMenu = () => findFirstRow().findComponent(GlDropdown);
const findActionMenuDelete = () => findFirstActionMenu().find('[data-testid="delete-file"]');
+ const findFirstToggleDetailsButton = () => findFirstRow().findComponent(GlButton);
+ const findFirstRowShaComponent = (id) => wrapper.find(`[data-testid="${id}"]`);
const createComponent = ({ packageFiles = npmFiles, canDelete = true } = {}) => {
wrapper = mount(component, {
@@ -181,4 +184,76 @@ describe('Package Files', () => {
});
});
});
+
+ describe('additional details', () => {
+ describe('details toggle button', () => {
+ it('exists', () => {
+ createComponent();
+
+ expect(findFirstToggleDetailsButton().exists()).toBe(true);
+ });
+
+ it('is hidden when no details is present', () => {
+ const [{ ...noShaFile }] = npmFiles;
+ noShaFile.file_sha256 = null;
+ noShaFile.file_md5 = null;
+ noShaFile.file_sha1 = null;
+ createComponent({ packageFiles: [noShaFile] });
+
+ expect(findFirstToggleDetailsButton().exists()).toBe(false);
+ });
+
+ it('toggles the details row', async () => {
+ createComponent();
+
+ expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down');
+
+ findFirstToggleDetailsButton().vm.$emit('click');
+ await nextTick();
+
+ expect(findFirstRowShaComponent('sha-256').exists()).toBe(true);
+ expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-up');
+
+ findFirstToggleDetailsButton().vm.$emit('click');
+ await nextTick();
+
+ expect(findFirstRowShaComponent('sha-256').exists()).toBe(false);
+ expect(findFirstToggleDetailsButton().props('icon')).toBe('angle-down');
+ });
+ });
+
+ describe('file shas', () => {
+ const showShaFiles = () => {
+ findFirstToggleDetailsButton().vm.$emit('click');
+ return nextTick();
+ };
+
+ it.each`
+ selector | title | sha
+ ${'sha-256'} | ${'SHA-256'} | ${'file_sha256'}
+ ${'md5'} | ${'MD5'} | ${'file_md5'}
+ ${'sha-1'} | ${'SHA-1'} | ${'file_sha1'}
+ `('has a $title row', async ({ selector, title, sha }) => {
+ createComponent();
+
+ await showShaFiles();
+
+ expect(findFirstRowShaComponent(selector).props()).toMatchObject({
+ title,
+ sha,
+ });
+ });
+
+ it('does not display a row when the data is missing', async () => {
+ const [{ ...missingMd5 }] = npmFiles;
+ missingMd5.file_md5 = null;
+
+ createComponent({ packageFiles: [missingMd5] });
+
+ await showShaFiles();
+
+ expect(findFirstRowShaComponent('md5').exists()).toBe(false);
+ });
+ });
+ });
});
diff --git a/spec/frontend/packages/mock_data.js b/spec/frontend/packages/mock_data.js
index 06009daba54..46ccf5994b9 100644
--- a/spec/frontend/packages/mock_data.js
+++ b/spec/frontend/packages/mock_data.js
@@ -79,6 +79,9 @@ export const npmFiles = [
pipelines: [
{ id: 1, project: { commit_url: 'http://foo.bar' }, git_commit_message: 'foo bar baz?' },
],
+ file_sha256: 'file_sha256',
+ file_md5: 'file_md5',
+ file_sha1: 'file_sha1',
},
];
diff --git a/spec/frontend/pages/projects/forks/new/components/app_spec.js b/spec/frontend/pages/projects/forks/new/components/app_spec.js
index e1820606704..a7b4b9c42bd 100644
--- a/spec/frontend/pages/projects/forks/new/components/app_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/app_spec.js
@@ -13,6 +13,7 @@ describe('App component', () => {
projectPath: 'project-name',
projectDescription: 'some project description',
projectVisibility: 'private',
+ restrictedVisibilityLevels: [],
};
const createComponent = (props = {}) => {
diff --git a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
index 03338b1930c..c80ccfa8256 100644
--- a/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/fork_form_spec.js
@@ -1,4 +1,5 @@
-import { GlFormInputGroup, GlFormInput, GlForm, GlFormRadio, GlFormSelect } from '@gitlab/ui';
+import { GlFormInputGroup, GlFormInput, GlForm, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
+import { getByRole, getAllByRole } from '@testing-library/dom';
import { mount, shallowMount } from '@vue/test-utils';
import axios from 'axios';
import AxiosMockAdapter from 'axios-mock-adapter';
@@ -44,6 +45,7 @@ describe('ForkForm component', () => {
projectPath: 'project-name',
projectDescription: 'some project description',
projectVisibility: 'private',
+ restrictedVisibilityLevels: [],
};
const mockGetRequest = (data = {}, statusCode = httpStatus.OK) => {
@@ -68,6 +70,7 @@ describe('ForkForm component', () => {
stubs: {
GlFormInputGroup,
GlFormInput,
+ GlFormRadioGroup,
GlFormRadio,
},
});
@@ -89,7 +92,7 @@ describe('ForkForm component', () => {
axiosMock.restore();
});
- const findFormSelect = () => wrapper.find(GlFormSelect);
+ const findFormSelectOptions = () => wrapper.find('select[name="namespace"]').findAll('option');
const findPrivateRadio = () => wrapper.find('[data-testid="radio-private"]');
const findInternalRadio = () => wrapper.find('[data-testid="radio-internal"]');
const findPublicRadio = () => wrapper.find('[data-testid="radio-public"]');
@@ -230,7 +233,7 @@ describe('ForkForm component', () => {
expect(wrapper.findAll(GlFormRadio)).toHaveLength(3);
});
- it('resets the visibility to default "private" when the namespace is changed', async () => {
+ describe('when the namespace is changed', () => {
const namespaces = [
{
visibility: 'private',
@@ -243,42 +246,114 @@ describe('ForkForm component', () => {
},
];
- mockGetRequest();
- createComponent(
- {
- projectVisibility: 'public',
- },
- {
- namespaces,
- },
- );
+ beforeEach(() => {
+ mockGetRequest();
+ });
- expect(wrapper.vm.form.fields.visibility.value).toBe('public');
- findFormSelect().vm.$emit('input', namespaces[1]);
+ it('resets the visibility to default "private"', async () => {
+ createFullComponent({ projectVisibility: 'public' }, { namespaces });
- await wrapper.vm.$nextTick();
+ expect(wrapper.vm.form.fields.visibility.value).toBe('public');
+ await findFormSelectOptions().at(1).setSelected();
+
+ await wrapper.vm.$nextTick();
+
+ expect(getByRole(wrapper.element, 'radio', { name: /private/i }).checked).toBe(true);
+ });
+
+ it('sets the visibility to be null when restrictedVisibilityLevels is set', async () => {
+ createFullComponent({ restrictedVisibilityLevels: [10] }, { namespaces });
+
+ await findFormSelectOptions().at(1).setSelected();
+
+ await wrapper.vm.$nextTick();
+
+ const container = getByRole(wrapper.element, 'radiogroup', { name: /visibility/i });
+ const visibilityRadios = getAllByRole(container, 'radio');
+ expect(visibilityRadios.filter((e) => e.checked)).toHaveLength(0);
+ });
+ });
+
+ it.each`
+ project | restrictedVisibilityLevels
+ ${'private'} | ${[]}
+ ${'internal'} | ${[]}
+ ${'public'} | ${[]}
+ ${'private'} | ${[0]}
+ ${'private'} | ${[10]}
+ ${'private'} | ${[20]}
+ ${'private'} | ${[0, 10]}
+ ${'private'} | ${[0, 20]}
+ ${'private'} | ${[10, 20]}
+ ${'private'} | ${[0, 10, 20]}
+ ${'internal'} | ${[0]}
+ ${'internal'} | ${[10]}
+ ${'internal'} | ${[20]}
+ ${'internal'} | ${[0, 10]}
+ ${'internal'} | ${[0, 20]}
+ ${'internal'} | ${[10, 20]}
+ ${'internal'} | ${[0, 10, 20]}
+ ${'public'} | ${[0]}
+ ${'public'} | ${[10]}
+ ${'public'} | ${[0, 10]}
+ ${'public'} | ${[0, 20]}
+ ${'public'} | ${[10, 20]}
+ ${'public'} | ${[0, 10, 20]}
+ `('checks the correct radio button', async ({ project, restrictedVisibilityLevels }) => {
+ mockGetRequest();
+ createFullComponent({
+ projectVisibility: project,
+ restrictedVisibilityLevels,
+ });
- expect(wrapper.vm.form.fields.visibility.value).toBe('private');
+ if (restrictedVisibilityLevels.length === 0) {
+ expect(wrapper.find('[name="visibility"]:checked').attributes('value')).toBe(project);
+ } else {
+ expect(wrapper.find('[name="visibility"]:checked').exists()).toBe(false);
+ }
});
it.each`
- project | namespace | privateIsDisabled | internalIsDisabled | publicIsDisabled
- ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'private'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'}
- ${'private'} | ${'public'} | ${undefined} | ${'true'} | ${'true'}
- ${'internal'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'}
- ${'internal'} | ${'public'} | ${undefined} | ${undefined} | ${'true'}
- ${'public'} | ${'private'} | ${undefined} | ${'true'} | ${'true'}
- ${'public'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'}
- ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${undefined}
+ project | namespace | privateIsDisabled | internalIsDisabled | publicIsDisabled | restrictedVisibilityLevels
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'private'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'private'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'internal'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'internal'} | ${'public'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'public'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[]}
+ ${'public'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[]}
+ ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${undefined} | ${[]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[0]}
+ ${'internal'} | ${'internal'} | ${'true'} | ${undefined} | ${'true'} | ${[0]}
+ ${'public'} | ${'public'} | ${'true'} | ${undefined} | ${undefined} | ${[0]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[10]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[10]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${undefined} | ${[10]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${undefined} | ${'true'} | ${[20]}
+ ${'public'} | ${'public'} | ${undefined} | ${undefined} | ${'true'} | ${[20]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[10, 20]}
+ ${'private'} | ${'private'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
+ ${'internal'} | ${'internal'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
+ ${'public'} | ${'public'} | ${undefined} | ${'true'} | ${'true'} | ${[0, 10, 20]}
`(
'sets appropriate radio button disabled state',
- async ({ project, namespace, privateIsDisabled, internalIsDisabled, publicIsDisabled }) => {
+ async ({
+ project,
+ namespace,
+ privateIsDisabled,
+ internalIsDisabled,
+ publicIsDisabled,
+ restrictedVisibilityLevels,
+ }) => {
mockGetRequest();
createComponent(
{
projectVisibility: project,
+ restrictedVisibilityLevels,
},
{
form: { fields: { namespace: { value: { visibility: namespace } } } },
diff --git a/spec/frontend/repository/log_tree_spec.js b/spec/frontend/repository/log_tree_spec.js
index d338af88ce3..8cabf902a4f 100644
--- a/spec/frontend/repository/log_tree_spec.js
+++ b/spec/frontend/repository/log_tree_spec.js
@@ -69,6 +69,16 @@ describe('fetchLogsTree', () => {
mock.restore();
});
+ it('persists the offset for a given page if offset is larger than maximum offset', async () => {
+ await fetchLogsTree(client, 'path', '1000', resolver, 900).then(() => {});
+
+ await fetchLogsTree(client, 'path', '1100', resolver, 1200).then(() => {
+ expect(axios.get).toHaveBeenCalledWith('/gitlab-org/gitlab-foss/-/refs/main/logs_tree/path', {
+ params: { format: 'json', offset: 975 },
+ });
+ });
+ });
+
it('does not call axios get if offset is larger than the maximum offset', () =>
fetchLogsTree(client, '', '1000', resolver, 900).then(() => {
expect(axios.get).not.toHaveBeenCalled();
diff --git a/spec/graphql/resolvers/ci/runners_resolver_spec.rb b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
index d89beb183f4..5ac15d5729f 100644
--- a/spec/graphql/resolvers/ci/runners_resolver_spec.rb
+++ b/spec/graphql/resolvers/ci/runners_resolver_spec.rb
@@ -50,13 +50,29 @@ RSpec.describe Resolvers::Ci::RunnersResolver do
it { is_expected.to eq([offline_project_runner, instance_runner, inactive_project_runner, group_runner]) }
end
- context "set to :created_date" do
+ context "set to :contacted_desc" do
let(:args) do
- { sort: :created_date }
+ { sort: :contacted_desc }
+ end
+
+ it { is_expected.to eq([offline_project_runner, instance_runner, inactive_project_runner, group_runner].reverse) }
+ end
+
+ context "set to :created_at_desc" do
+ let(:args) do
+ { sort: :created_at_desc }
end
it { is_expected.to eq([instance_runner, group_runner, offline_project_runner, inactive_project_runner]) }
end
+
+ context "set to :created_at_asc" do
+ let(:args) do
+ { sort: :created_at_asc }
+ end
+
+ it { is_expected.to eq([instance_runner, group_runner, offline_project_runner, inactive_project_runner].reverse) }
+ end
end
context 'when type is filtered' do
diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
index 2cdf95ea101..b9e0132badb 100644
--- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
@@ -4,14 +4,15 @@ require 'spec_helper'
RSpec.describe Gitlab::CycleAnalytics::StageSummary do
let(:project) { create(:project, :repository) }
- let(:options) { { from: 1.day.ago, current_user: user } }
+ let(:options) { { from: 1.day.ago } }
+ let(:args) { { options: options, current_user: user } }
let(:user) { create(:user, :admin) }
before do
project.add_maintainer(user)
end
- let(:stage_summary) { described_class.new(project, **options).data }
+ let(:stage_summary) { described_class.new(project, **args).data }
describe "#new_issues" do
subject { stage_summary.first }
@@ -117,11 +118,11 @@ RSpec.describe Gitlab::CycleAnalytics::StageSummary do
before do
project.add_guest(guest_user)
- options.merge!({ current_user: guest_user })
+ args.merge!({ current_user: guest_user })
end
it 'does not include commit stats' do
- data = described_class.new(project, **options).data
+ data = described_class.new(project, **args).data
expect(includes_commits?(data)).to be_falsy
end
diff --git a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
index 28d78c182ad..4705bb23885 100644
--- a/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/load_balancer_spec.rb
@@ -459,7 +459,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
expect(hosts).to all(receive(:caught_up?).with(location).and_return(false))
end
- it 'returns true and has does not set the valid hosts' do
+ it 'returns false and does not set the valid hosts' do
expect(subject).to be false
expect(valid_host_list).to be_nil
end
@@ -487,4 +487,36 @@ RSpec.describe Gitlab::Database::LoadBalancing::LoadBalancer, :request_store do
end
end
end
+
+ describe '#select_caught_up_hosts' do
+ let(:location) { 'AB/12345'}
+ let(:hosts) { lb.host_list.hosts }
+ let(:set_host) { RequestStore[described_class::CACHE_KEY] }
+
+ subject { lb.select_up_to_date_host(location) }
+
+ context 'when none of the replicas are caught up' do
+ before do
+ expect(hosts).to all(receive(:caught_up?).with(location).and_return(false))
+ end
+
+ it 'returns false and does not update the host thread-local variable' do
+ expect(subject).to be false
+ expect(set_host).to be_nil
+ end
+ end
+
+ context 'when any of the replicas is caught up' do
+ before do
+ # `allow` for non-caught up host, because we may not even check it, if will find the caught up one earlier
+ allow(hosts[0]).to receive(:caught_up?).with(location).and_return(false)
+ expect(hosts[1]).to receive(:caught_up?).with(location).and_return(true)
+ end
+
+ it 'returns true and sets host thread-local variable' do
+ expect(subject).to be true
+ expect(set_host).to eq(hosts[1])
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
index f1cd84b63c1..b7cd0caa922 100644
--- a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
@@ -126,7 +126,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
context 'when replica is not up to date' do
before do
allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :release_host)
- allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :host, :caught_up?).and_return(false)
+ allow(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :select_up_to_date_host).and_return(false)
end
around do |example|
@@ -157,6 +157,20 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware do
expect(job[:database_chosen]).to eq('primary')
end
end
+
+ context 'replica selection mechanism feature flag rollout' do
+ before do
+ stub_feature_flags(sidekiq_load_balancing_rotate_up_to_date_replica: false)
+ end
+
+ it 'uses different implmentation' do
+ expect(::Gitlab::Database::LoadBalancing).to receive_message_chain(:proxy, :load_balancer, :host, :caught_up?).and_return(false)
+
+ expect do
+ process_job(job)
+ end.to raise_error(Sidekiq::JobRetry::Skip)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/database/load_balancing_spec.rb b/spec/lib/gitlab/database/load_balancing_spec.rb
index f8aeafbf61a..e7de7f2b43b 100644
--- a/spec/lib/gitlab/database/load_balancing_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing_spec.rb
@@ -394,7 +394,7 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end
shared_context 'LoadBalancing setup' do
- let(:development_db_config) { ActiveRecord::Base.configurations.default_hash("development").with_indifferent_access }
+ let(:development_db_config) { ActiveRecord::Base.configurations.configs_for(env_name: 'development').first.configuration_hash }
let(:hosts) { [development_db_config[:host]] }
let(:model) do
Class.new(ApplicationRecord) do
diff --git a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
index 2da0e7df72f..6955fbcaf5a 100644
--- a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
@@ -38,22 +38,6 @@ RSpec.describe Gitlab::Usage::Metrics::NameSuggestion do
end
context 'joined relations' do
- context 'counted attribute comes from joined relation' do
- it_behaves_like 'name suggestion' do
- let(:operation) { :distinct_count }
- let(:column) { ::Deployment.arel_table[:environment_id] }
- let(:relation) do
- ::Clusters::Applications::Ingress.modsecurity_enabled.logging
- .joins(cluster: :deployments)
- .merge(::Clusters::Cluster.enabled)
- .merge(Deployment.success)
- end
-
- let(:constraints) { /'\(clusters_applications_ingress\.modsecurity_enabled = TRUE AND clusters_applications_ingress\.modsecurity_mode = \d+ AND clusters.enabled = TRUE AND deployments.status = \d+\)'/ }
- let(:name_suggestion) { /count_distinct_environment_id_from_<adjective describing\: #{constraints}>_deployments_<with>_<adjective describing\: #{constraints}>_clusters_<having>_<adjective describing\: #{constraints}>_clusters_applications_ingress/ }
- end
- end
-
context 'counted attribute comes from source relation' do
it_behaves_like 'name suggestion' do
# corresponding metric is collected with count(Issue.with_alert_management_alerts.not_authored_by(::User.alert_bot), start: issue_minimum_id, finish: issue_maximum_id)
diff --git a/spec/models/clusters/applications/fluentd_spec.rb b/spec/models/clusters/applications/fluentd_spec.rb
index ccdf6b0e40d..a4df44225f3 100644
--- a/spec/models/clusters/applications/fluentd_spec.rb
+++ b/spec/models/clusters/applications/fluentd_spec.rb
@@ -3,9 +3,8 @@
require 'spec_helper'
RSpec.describe Clusters::Applications::Fluentd do
- let(:waf_log_enabled) { true }
let(:cilium_log_enabled) { true }
- let(:fluentd) { create(:clusters_applications_fluentd, waf_log_enabled: waf_log_enabled, cilium_log_enabled: cilium_log_enabled) }
+ let(:fluentd) { create(:clusters_applications_fluentd, cilium_log_enabled: cilium_log_enabled) }
include_examples 'cluster application core specs', :clusters_applications_fluentd
include_examples 'cluster application status specs', :clusters_applications_fluentd
@@ -51,13 +50,11 @@ RSpec.describe Clusters::Applications::Fluentd do
end
describe '#values' do
- let(:modsecurity_log_path) { "/var/log/containers/*#{Clusters::Applications::Ingress::MODSECURITY_LOG_CONTAINER_NAME}*.log" }
let(:cilium_log_path) { "/var/log/containers/*#{described_class::CILIUM_CONTAINER_NAME}*.log" }
subject { fluentd.values }
- context 'with both logs variables set to false' do
- let(:waf_log_enabled) { false }
+ context 'with cilium_log_enabled set to false' do
let(:cilium_log_enabled) { false }
it "raises ActiveRecord::RecordInvalid" do
@@ -65,18 +62,8 @@ RSpec.describe Clusters::Applications::Fluentd do
end
end
- context 'with both logs variables set to true' do
- it { is_expected.to include("#{modsecurity_log_path},#{cilium_log_path}") }
- end
-
- context 'with waf_log_enabled set to true' do
- let(:cilium_log_enabled) { false }
-
- it { is_expected.to include(modsecurity_log_path) }
- end
-
context 'with cilium_log_enabled set to true' do
- let(:waf_log_enabled) { false }
+ let(:cilium_log_enabled) { true }
it { is_expected.to include(cilium_log_path) }
end
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index 1bc1a4343aa..e16d97c42d9 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -172,94 +172,4 @@ RSpec.describe Clusters::Applications::Ingress do
expect(values).to include('clusterIP')
end
end
-
- describe '#values' do
- subject { ingress }
-
- context 'when modsecurity_enabled is enabled' do
- before do
- allow(subject).to receive(:modsecurity_enabled).and_return(true)
- end
-
- it 'includes modsecurity module enablement' do
- expect(subject.values).to include("enable-modsecurity: 'true'")
- end
-
- it 'includes modsecurity core ruleset enablement set to false' do
- expect(subject.values).to include("enable-owasp-modsecurity-crs: 'false'")
- end
-
- it 'includes modsecurity snippet with information related to security rules' do
- expect(subject.values).to include("SecRuleEngine DetectionOnly")
- expect(subject.values).to include("Include #{described_class::MODSECURITY_OWASP_RULES_FILE}")
- end
-
- context 'when modsecurity_mode is set to :blocking' do
- before do
- subject.blocking!
- end
-
- it 'includes modsecurity snippet with information related to security rules' do
- expect(subject.values).to include("SecRuleEngine On")
- expect(subject.values).to include("Include #{described_class::MODSECURITY_OWASP_RULES_FILE}")
- end
- end
-
- it 'includes modsecurity.conf content' do
- expect(subject.values).to include('modsecurity.conf')
- # Includes file content from Ingress#modsecurity_config_content
- expect(subject.values).to include('SecAuditLog')
-
- expect(subject.values).to include('extraVolumes')
- expect(subject.values).to include('extraVolumeMounts')
- end
-
- it 'includes modsecurity sidecar container' do
- expect(subject.values).to include('modsecurity-log-volume')
-
- expect(subject.values).to include('extraContainers')
- end
-
- it 'executes command to tail modsecurity logs with -F option' do
- args = YAML.safe_load(subject.values).dig('controller', 'extraContainers', 0, 'args')
-
- expect(args).to eq(['/bin/sh', '-c', 'tail -F /var/log/modsec/audit.log'])
- end
-
- it 'includes livenessProbe for modsecurity sidecar container' do
- probe_config = YAML.safe_load(subject.values).dig('controller', 'extraContainers', 0, 'livenessProbe')
-
- expect(probe_config).to eq('exec' => { 'command' => ['ls', '/var/log/modsec/audit.log'] })
- end
- end
-
- context 'when modsecurity_enabled is disabled' do
- before do
- allow(subject).to receive(:modsecurity_enabled).and_return(false)
- end
-
- it 'excludes modsecurity module enablement' do
- expect(subject.values).not_to include('enable-modsecurity')
- end
-
- it 'excludes modsecurity core ruleset enablement' do
- expect(subject.values).not_to include('enable-owasp-modsecurity-crs')
- end
-
- it 'excludes modsecurity.conf content' do
- expect(subject.values).not_to include('modsecurity.conf')
- # Excludes file content from Ingress#modsecurity_config_content
- expect(subject.values).not_to include('SecAuditLog')
-
- expect(subject.values).not_to include('extraVolumes')
- expect(subject.values).not_to include('extraVolumeMounts')
- end
-
- it 'excludes modsecurity sidecar container' do
- expect(subject.values).not_to include('modsecurity-log-volume')
-
- expect(subject.values).not_to include('extraContainers')
- end
- end
- end
end
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 28dba3e7efa..8a7ffc315db 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -196,28 +196,6 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
end
end
- describe '.with_enabled_modsecurity' do
- subject { described_class.with_enabled_modsecurity }
-
- let_it_be(:cluster) { create(:cluster) }
-
- context 'cluster has ingress application with enabled modsecurity' do
- let!(:application) { create(:clusters_applications_ingress, :installed, :modsecurity_logging, cluster: cluster) }
-
- it { is_expected.to include(cluster) }
- end
-
- context 'cluster has ingress application with disabled modsecurity' do
- let!(:application) { create(:clusters_applications_ingress, :installed, :modsecurity_disabled, cluster: cluster) }
-
- it { is_expected.not_to include(cluster) }
- end
-
- context 'cluster does not have ingress application' do
- it { is_expected.not_to include(cluster) }
- end
- end
-
describe '.with_available_elasticstack' do
subject { described_class.with_available_elasticstack }
diff --git a/spec/models/members/last_group_owner_assigner_spec.rb b/spec/models/members/last_group_owner_assigner_spec.rb
index 3c9a7a11555..bb0f751e7d5 100644
--- a/spec/models/members/last_group_owner_assigner_spec.rb
+++ b/spec/models/members/last_group_owner_assigner_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Members::LastGroupOwnerAssigner do
+RSpec.describe LastGroupOwnerAssigner do
describe "#execute" do
let_it_be(:user, reload: true) { create(:user) }
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
index 99647d0fa3a..578a71a7272 100644
--- a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
+++ b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
@@ -47,6 +47,7 @@ RSpec.describe 'Getting Ci Cd Setting' do
expect(settings_data['mergePipelinesEnabled']).to eql project.ci_cd_settings.merge_pipelines_enabled?
expect(settings_data['mergeTrainsEnabled']).to eql project.ci_cd_settings.merge_trains_enabled?
expect(settings_data['keepLatestArtifact']).to eql project.keep_latest_artifacts_available?
+ expect(settings_data['jobTokenScopeEnabled']).to eql project.ci_cd_settings.job_token_scope_enabled?
end
end
end
diff --git a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
index 0dcae28ac5d..0d7571d91ca 100644
--- a/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/ci_cd_settings_update_spec.rb
@@ -5,8 +5,16 @@ require 'spec_helper'
RSpec.describe 'CiCdSettingsUpdate' do
include GraphqlHelpers
- let_it_be(:project) { create(:project, keep_latest_artifact: true) }
- let(:variables) { { full_path: project.full_path, keep_latest_artifact: false } }
+ let_it_be(:project) { create(:project, keep_latest_artifact: true, ci_job_token_scope_enabled: true) }
+
+ let(:variables) do
+ {
+ full_path: project.full_path,
+ keep_latest_artifact: false,
+ job_token_scope_enabled: false
+ }
+ end
+
let(:mutation) { graphql_mutation(:ci_cd_settings_update, variables) }
context 'when unauthorized' do
@@ -45,6 +53,26 @@ RSpec.describe 'CiCdSettingsUpdate' do
expect(project.keep_latest_artifact).to eq(false)
end
+ it 'updates job_token_scope_enabled' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ project.reload
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(project.ci_job_token_scope_enabled).to eq(false)
+ end
+
+ it 'does not update job_token_scope_enabled if not specified' do
+ variables.except!(:job_token_scope_enabled)
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ project.reload
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(project.ci_job_token_scope_enabled).to eq(true)
+ end
+
context 'when bad arguments are provided' do
let(:variables) { { full_path: '', keep_latest_artifact: false } }
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index ce7405201ab..1aa1ad87be9 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -358,26 +358,6 @@ RSpec.describe API::Tags do
expect(json_response['message']).to eq('Target foo is invalid')
end
- context 'when release_description is passed' do
- it 'returns error' do
- post api(route, current_user), params: { tag_name: tag_name, ref: 'master', release_description: 'Wow' }
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response["message"]).to eq("Release notes modification via tags API is deprecated, see https://gitlab.com/gitlab-org/gitlab/-/issues/290311")
- end
-
- it 'creates a new tag with release if feature is enabled' do
- stub_feature_flags(remove_release_notes_from_tags_api: false)
-
- post api(route, current_user), params: { tag_name: tag_name, ref: 'master', release_description: 'Wow' }
-
- expect(response).to have_gitlab_http_status(:created)
- expect(response).to match_response_schema('public_api/v4/tag')
- expect(json_response['name']).to eq(tag_name)
- expect(json_response['release']['description']).to eq('Wow')
- end
- end
-
context 'annotated tag' do
it 'creates a new annotated tag' do
# Identity must be set in .gitconfig to create annotated tag.
@@ -449,148 +429,4 @@ RSpec.describe API::Tags do
end
end
end
-
- describe 'POST /projects/:id/repository/tags/:tag_name/release' do
- let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}/release" }
- let(:description) { 'Awesome release!' }
-
- before do
- stub_feature_flags(remove_release_notes_from_tags_api: false)
- end
-
- shared_examples_for 'repository new release' do
- it 'creates description for existing git tag' do
- post api(route, user), params: { description: description }
-
- expect(response).to have_gitlab_http_status(:created)
- expect(response).to match_response_schema('public_api/v4/release/tag_release')
- expect(json_response['tag_name']).to eq(tag_name)
- expect(json_response['description']).to eq(description)
- end
-
- it 'returns error if feature is removed' do
- stub_feature_flags(remove_release_notes_from_tags_api: true)
-
- post api(route, user), params: { description: description }
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response["message"]).to eq("Release notes modification via tags API is deprecated, see https://gitlab.com/gitlab-org/gitlab/-/issues/290311")
- end
-
- context 'when tag does not exist' do
- let(:tag_name) { 'unknown' }
-
- it_behaves_like '404 response' do
- let(:request) { post api(route, current_user), params: { description: description } }
- let(:message) { '404 Tag Not Found' }
- end
- end
-
- context 'when repository is disabled' do
- include_context 'disabled repository'
-
- it_behaves_like '403 response' do
- let(:request) { post api(route, current_user), params: { description: description } }
- end
- end
- end
-
- context 'when authenticated', 'as a maintainer' do
- let(:current_user) { user }
-
- it_behaves_like 'repository new release'
-
- context 'requesting with the escaped project full path' do
- let(:project_id) { CGI.escape(project.full_path) }
-
- it_behaves_like 'repository new release'
- end
-
- context 'on tag with existing release' do
- let!(:release) { create(:release, :legacy, project: project, tag: tag_name, description: description) }
-
- it 'returns 409 if there is already a release' do
- post api(route, user), params: { description: description }
-
- expect(response).to have_gitlab_http_status(:conflict)
- expect(json_response['message']).to eq('Release already exists')
- end
- end
- end
- end
-
- describe 'PUT id/repository/tags/:tag_name/release' do
- let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}/release" }
- let(:description) { 'Awesome release!' }
- let(:new_description) { 'The best release!' }
-
- before do
- stub_feature_flags(remove_release_notes_from_tags_api: false)
- end
-
- shared_examples_for 'repository update release' do
- context 'on tag with existing release' do
- let!(:release) do
- create(:release,
- :legacy,
- project: project,
- tag: tag_name,
- description: description)
- end
-
- it 'updates the release description' do
- put api(route, current_user), params: { description: new_description }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['tag_name']).to eq(tag_name)
- expect(json_response['description']).to eq(new_description)
- end
-
- it 'returns error if feature is removed' do
- stub_feature_flags(remove_release_notes_from_tags_api: true)
-
- put api(route, current_user), params: { description: new_description }
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response["message"]).to eq("Release notes modification via tags API is deprecated, see https://gitlab.com/gitlab-org/gitlab/-/issues/290311")
- end
- end
-
- context 'when tag does not exist' do
- let(:tag_name) { 'unknown' }
-
- it_behaves_like '403 response' do
- let(:request) { put api(route, current_user), params: { description: new_description } }
- let(:message) { '403 Forbidden' }
- end
- end
-
- context 'when repository is disabled' do
- include_context 'disabled repository'
-
- it_behaves_like '403 response' do
- let(:request) { put api(route, current_user), params: { description: new_description } }
- end
- end
- end
-
- context 'when authenticated', 'as a maintainer' do
- let(:current_user) { user }
-
- it_behaves_like 'repository update release'
-
- context 'requesting with the escaped project full path' do
- let(:project_id) { CGI.escape(project.full_path) }
-
- it_behaves_like 'repository update release'
- end
-
- context 'when release does not exist' do
- it_behaves_like '403 response' do
- let(:request) { put api(route, current_user), params: { description: new_description } }
- let(:message) { '403 Forbidden' }
- end
- end
- end
- end
end
diff --git a/spec/serializers/analytics_summary_serializer_spec.rb b/spec/serializers/analytics_summary_serializer_spec.rb
index cd8be07827d..9429c9d571a 100644
--- a/spec/serializers/analytics_summary_serializer_spec.rb
+++ b/spec/serializers/analytics_summary_serializer_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe AnalyticsSummarySerializer do
let(:resource) do
Gitlab::CycleAnalytics::Summary::Issue
- .new(project: double, from: 1.day.ago, current_user: user)
+ .new(project: double, options: { from: 1.day.ago }, current_user: user)
end
before do
@@ -36,7 +36,7 @@ RSpec.describe AnalyticsSummarySerializer do
context 'when representing with unit' do
let(:resource) do
Gitlab::CycleAnalytics::Summary::DeploymentFrequency
- .new(deployments: 10, from: 1.day.ago)
+ .new(deployments: 10, options: { from: 1.day.ago })
end
subject { described_class.new.represent(resource, with_unit: true) }
diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb
index aa2bb25b17c..3941aad540a 100644
--- a/spec/serializers/cluster_application_entity_spec.rb
+++ b/spec/serializers/cluster_application_entity_spec.rb
@@ -85,7 +85,6 @@ RSpec.describe ClusterApplicationEntity do
expect(subject[:port]).to eq(514)
expect(subject[:host]).to eq("example.com")
expect(subject[:protocol]).to eq("tcp")
- expect(subject[:waf_log_enabled]).to be true
expect(subject[:cilium_log_enabled]).to be true
end
end
diff --git a/spec/serializers/member_serializer_spec.rb b/spec/serializers/member_serializer_spec.rb
index 687d69f86ea..bc256432c46 100644
--- a/spec/serializers/member_serializer_spec.rb
+++ b/spec/serializers/member_serializer_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe MemberSerializer do
it_behaves_like 'members.json'
it 'does not invoke group owner assignment' do
- expect(Members::LastGroupOwnerAssigner).not_to receive(:new)
+ expect(LastGroupOwnerAssigner).not_to receive(:new)
representation
end
diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb
index f3b420510a6..eb907377ca8 100644
--- a/spec/services/clusters/applications/create_service_spec.rb
+++ b/spec/services/clusters/applications/create_service_spec.rb
@@ -46,8 +46,7 @@ RSpec.describe Clusters::Applications::CreateService do
context 'ingress application' do
let(:params) do
{
- application: 'ingress',
- modsecurity_enabled: true
+ application: 'ingress'
}
end
@@ -64,10 +63,6 @@ RSpec.describe Clusters::Applications::CreateService do
cluster.reload
end.to change(cluster, :application_ingress)
end
-
- it 'sets modsecurity_enabled' do
- expect(subject.modsecurity_enabled).to eq(true)
- end
end
context 'cert manager application' do
diff --git a/spec/workers/ssh_keys/expired_notification_worker_spec.rb b/spec/workers/ssh_keys/expired_notification_worker_spec.rb
index 84f8f8d7b83..109d24f03ab 100644
--- a/spec/workers/ssh_keys/expired_notification_worker_spec.rb
+++ b/spec/workers/ssh_keys/expired_notification_worker_spec.rb
@@ -49,16 +49,6 @@ RSpec.describe SshKeys::ExpiredNotificationWorker, type: :worker do
perform_multiple(worker: worker)
end
end
-
- context 'when feature is not enabled' do
- before do
- stub_feature_flags(ssh_key_expiration_email_notification: false)
- end
-
- it 'does not update notified column' do
- expect { worker.perform }.not_to change { expired_today.reload.expiry_notification_delivered_at }
- end
- end
end
context 'when key has expired in the past' do
diff --git a/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb b/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
index f9276c86cdf..0a1d4a14ad0 100644
--- a/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
+++ b/spec/workers/ssh_keys/expiring_soon_notification_worker_spec.rb
@@ -35,16 +35,6 @@ RSpec.describe SshKeys::ExpiringSoonNotificationWorker, type: :worker do
perform_multiple(worker: worker)
end
end
-
- context 'when feature is not enabled' do
- before do
- stub_feature_flags(ssh_key_expiration_email_notification: false)
- end
-
- it 'does not update notified column' do
- expect { worker.perform }.not_to change { expiring_soon.reload.before_expiry_notification_delivered_at }
- end
- end
end
context 'when key has expired in the past' do
diff --git a/vendor/elastic_stack/values.yaml b/vendor/elastic_stack/values.yaml
index 65e9c4b683f..59a6037efeb 100644
--- a/vendor/elastic_stack/values.yaml
+++ b/vendor/elastic_stack/values.yaml
@@ -61,12 +61,6 @@ filebeat:
target_field: tie_breaker_id
- add_cloud_metadata: ~
- add_kubernetes_metadata: ~
- - decode_json_fields:
- fields: ["message"]
- when:
- equals:
- kubernetes.container.namespace: "gitlab-managed-apps"
- kubernetes.container.name: "modsecurity-log"
kibana:
enabled: false
elasticsearchHosts: "http://elastic-stack-elasticsearch-master:9200"
diff --git a/vendor/ingress/modsecurity.conf b/vendor/ingress/modsecurity.conf
deleted file mode 100644
index 3a6b5cee2e5..00000000000
--- a/vendor/ingress/modsecurity.conf
+++ /dev/null
@@ -1,274 +0,0 @@
-# -- GitLab Customization ----------------------------------------------
-# Based on https://github.com/SpiderLabs/ModSecurity/blob/v3.0.3/modsecurity.conf-recommended
-# Our base modsecurity.conf includes some minor customization:
-# - `SecRuleEngine` is disabled, defaulting to `DetectionOnly`. Overridable at project-level
-# - `SecAuditLogType` is disabled, defaulting to `Serial`. Overridable at project-level
-# - `SecStatusEngine` is disabled, to disallow usage reporting
-#
-# ----------------------------------------------------------------------------
-
-# -- Rule engine initialization ----------------------------------------------
-
-# Enable ModSecurity, attaching it to every transaction. Use detection
-# only to start with, because that minimises the chances of post-installation
-# disruption.
-#
-# SecRuleEngine DetectionOnly
-
-
-# -- Request body handling ---------------------------------------------------
-
-# Allow ModSecurity to access request bodies. If you don't, ModSecurity
-# won't be able to see any POST parameters, which opens a large security
-# hole for attackers to exploit.
-#
-SecRequestBodyAccess On
-
-
-# Enable XML request body parser.
-# Initiate XML Processor in case of xml content-type
-#
-SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
- "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
-
-# Enable JSON request body parser.
-# Initiate JSON Processor in case of JSON content-type; change accordingly
-# if your application does not use 'application/json'
-#
-SecRule REQUEST_HEADERS:Content-Type "application/json" \
- "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
-
-# Maximum request body size we will accept for buffering. If you support
-# file uploads then the value given on the first line has to be as large
-# as the largest file you are willing to accept. The second value refers
-# to the size of data, with files excluded. You want to keep that value as
-# low as practical.
-#
-SecRequestBodyLimit 13107200
-SecRequestBodyNoFilesLimit 131072
-
-# What do do if the request body size is above our configured limit.
-# Keep in mind that this setting will automatically be set to ProcessPartial
-# when SecRuleEngine is set to DetectionOnly mode in order to minimize
-# disruptions when initially deploying ModSecurity.
-#
-SecRequestBodyLimitAction Reject
-
-# Verify that we've correctly processed the request body.
-# As a rule of thumb, when failing to process a request body
-# you should reject the request (when deployed in blocking mode)
-# or log a high-severity alert (when deployed in detection-only mode).
-#
-SecRule REQBODY_ERROR "!@eq 0" \
-"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
-
-# By default be strict with what we accept in the multipart/form-data
-# request body. If the rule below proves to be too strict for your
-# environment consider changing it to detection-only. You are encouraged
-# _not_ to remove it altogether.
-#
-SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
-"id:'200003',phase:2,t:none,log,deny,status:400, \
-msg:'Multipart request body failed strict validation: \
-PE %{REQBODY_PROCESSOR_ERROR}, \
-BQ %{MULTIPART_BOUNDARY_QUOTED}, \
-BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
-DB %{MULTIPART_DATA_BEFORE}, \
-DA %{MULTIPART_DATA_AFTER}, \
-HF %{MULTIPART_HEADER_FOLDING}, \
-LF %{MULTIPART_LF_LINE}, \
-SM %{MULTIPART_MISSING_SEMICOLON}, \
-IQ %{MULTIPART_INVALID_QUOTING}, \
-IP %{MULTIPART_INVALID_PART}, \
-IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
-FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
-
-# Did we see anything that might be a boundary?
-#
-# Here is a short description about the ModSecurity Multipart parser: the
-# parser returns with value 0, if all "boundary-like" line matches with
-# the boundary string which given in MIME header. In any other cases it returns
-# with different value, eg. 1 or 2.
-#
-# The RFC 1341 descript the multipart content-type and its syntax must contains
-# only three mandatory lines (above the content):
-# * Content-Type: multipart/mixed; boundary=BOUNDARY_STRING
-# * --BOUNDARY_STRING
-# * --BOUNDARY_STRING--
-#
-# First line indicates, that this is a multipart content, second shows that
-# here starts a part of the multipart content, third shows the end of content.
-#
-# If there are any other lines, which starts with "--", then it should be
-# another boundary id - or not.
-#
-# After 3.0.3, there are two kinds of types of boundary errors: strict and permissive.
-#
-# If multipart content contains the three necessary lines with correct order, but
-# there are one or more lines with "--", then parser returns with value 2 (non-zero).
-#
-# If some of the necessary lines (usually the start or end) misses, or the order
-# is wrong, then parser returns with value 1 (also a non-zero).
-#
-# You can choose, which one is what you need. The example below contains the
-# 'strict' mode, which means if there are any lines with start of "--", then
-# ModSecurity blocked the content. But the next, commented example contains
-# the 'permissive' mode, then you check only if the necessary lines exists in
-# correct order. Whit this, you can enable to upload PEM files (eg "----BEGIN.."),
-# or other text files, which contains eg. HTTP headers.
-#
-# The difference is only the operator - in strict mode (first) the content blocked
-# in case of any non-zero value. In permissive mode (second, commented) the
-# content blocked only if the value is explicit 1. If it 0 or 2, the content will
-# allowed.
-#
-
-#
-# See #1747 and #1924 for further information on the possible values for
-# MULTIPART_UNMATCHED_BOUNDARY.
-#
-SecRule MULTIPART_UNMATCHED_BOUNDARY "@eq 1" \
- "id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
-
-
-# PCRE Tuning
-# We want to avoid a potential RegEx DoS condition
-#
-SecPcreMatchLimit 1000
-SecPcreMatchLimitRecursion 1000
-
-# Some internal errors will set flags in TX and we will need to look for these.
-# All of these are prefixed with "MSC_". The following flags currently exist:
-#
-# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
-#
-SecRule TX:/^MSC_/ "!@streq 0" \
- "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
-
-
-# -- Response body handling --------------------------------------------------
-
-# Allow ModSecurity to access response bodies.
-# You should have this directive enabled in order to identify errors
-# and data leakage issues.
-#
-# Do keep in mind that enabling this directive does increases both
-# memory consumption and response latency.
-#
-SecResponseBodyAccess On
-
-# Which response MIME types do you want to inspect? You should adjust the
-# configuration below to catch documents but avoid static files
-# (e.g., images and archives).
-#
-SecResponseBodyMimeType text/plain text/html text/xml
-
-# Buffer response bodies of up to 512 KB in length.
-SecResponseBodyLimit 524288
-
-# What happens when we encounter a response body larger than the configured
-# limit? By default, we process what we have and let the rest through.
-# That's somewhat less secure, but does not break any legitimate pages.
-#
-SecResponseBodyLimitAction ProcessPartial
-
-
-# -- Filesystem configuration ------------------------------------------------
-
-# The location where ModSecurity stores temporary files (for example, when
-# it needs to handle a file upload that is larger than the configured limit).
-#
-# This default setting is chosen due to all systems have /tmp available however,
-# this is less than ideal. It is recommended that you specify a location that's private.
-#
-SecTmpDir /tmp/
-
-# The location where ModSecurity will keep its persistent data. This default setting
-# is chosen due to all systems have /tmp available however, it
-# too should be updated to a place that other users can't access.
-#
-SecDataDir /tmp/
-
-
-# -- File uploads handling configuration -------------------------------------
-
-# The location where ModSecurity stores intercepted uploaded files. This
-# location must be private to ModSecurity. You don't want other users on
-# the server to access the files, do you?
-#
-#SecUploadDir /opt/modsecurity/var/upload/
-
-# By default, only keep the files that were determined to be unusual
-# in some way (by an external inspection script). For this to work you
-# will also need at least one file inspection rule.
-#
-#SecUploadKeepFiles RelevantOnly
-
-# Uploaded files are by default created with permissions that do not allow
-# any other user to access them. You may need to relax that if you want to
-# interface ModSecurity to an external program (e.g., an anti-virus).
-#
-#SecUploadFileMode 0600
-
-
-# -- Debug log configuration -------------------------------------------------
-
-# The default debug log configuration is to duplicate the error, warning
-# and notice messages from the error log.
-#
-#SecDebugLog /opt/modsecurity/var/log/debug.log
-#SecDebugLogLevel 3
-
-
-# -- Audit log configuration -------------------------------------------------
-
-# Log the transactions that are marked by a rule, as well as those that
-# trigger a server error (determined by a 5xx or 4xx, excluding 404,
-# level response status codes).
-#
-SecAuditEngine RelevantOnly
-SecAuditLogRelevantStatus "^(?:5|4(?!04))"
-
-# Log everything we know about a transaction.
-SecAuditLogParts ABIJDEFHZ
-
-# Use a single file for logging. This is much easier to look at, but
-# assumes that you will use the audit log only ocassionally.
-#
-# SecAuditLogType Serial
-SecAuditLogFormat JSON
-SecAuditLog /var/log/modsec/audit.log
-
-# Specify the path for concurrent audit logging.
-#SecAuditLogStorageDir /opt/modsecurity/var/audit/
-
-
-# -- Miscellaneous -----------------------------------------------------------
-
-# Use the most commonly used application/x-www-form-urlencoded parameter
-# separator. There's probably only one application somewhere that uses
-# something else so don't expect to change this value.
-#
-SecArgumentSeparator &
-
-# Settle on version 0 (zero) cookies, as that is what most applications
-# use. Using an incorrect cookie version may open your installation to
-# evasion attacks (against the rules that examine named cookies).
-#
-SecCookieFormat 0
-
-# Specify your Unicode Code Point.
-# This mapping is used by the t:urlDecodeUni transformation function
-# to properly map encoded data to your language. Properly setting
-# these directives helps to reduce false positives and negatives.
-#
-SecUnicodeMapFile unicode.mapping 20127
-
-# Improve the quality of ModSecurity by sharing information about your
-# current ModSecurity version and dependencies versions.
-# The following information will be shared: ModSecurity version,
-# Web Server version, APR version, PCRE version, Lua version, Libxml2
-# version, Anonymous unique id for host.
-# SecStatusEngine On
-
-