Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 06:09:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-20 06:09:08 +0300
commite83144f0eef1a161b69d2b991841674978014283 (patch)
tree58c2ab892ca053655d25e68f8416dfce104bb62a
parent69b1c09769fbb48258f5de06fd3b4955b0758c1f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue2
-rw-r--r--app/assets/javascripts/notes/components/notes_activity_header.vue2
-rw-r--r--app/assets/javascripts/runner/admin_runners/admin_runners_app.vue4
-rw-r--r--app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue58
-rw-r--r--app/assets/javascripts/runner/group_runners/group_runners_app.vue4
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue2
-rw-r--r--app/assets/stylesheets/framework/snippets.scss4
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss5
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/issues.scss5
-rw-r--r--app/helpers/json_helper.rb14
-rw-r--r--app/presenters/commit_status_presenter.rb2
-rw-r--r--app/views/admin/groups/show.html.haml5
-rw-r--r--app/views/award_emoji/_awards_block.html.haml2
-rw-r--r--app/views/projects/merge_requests/_awards_block.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml6
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/shared/_file_picker_button.html.haml3
-rw-r--r--app/views/shared/issue_type/_emoji_block.html.haml4
-rw-r--r--app/views/shared/labels/_form.html.haml8
-rw-r--r--app/views/users/show.html.haml39
-rw-r--r--config/gitlab.yml.example10
-rw-r--r--config/initializers/1_settings.rb2
-rw-r--r--config/initializers/sidekiq.rb1
-rw-r--r--doc/administration/geo/index.md2
-rw-r--r--doc/administration/reference_architectures/index.md8
-rw-r--r--doc/administration/troubleshooting/linux_cheat_sheet.md4
-rw-r--r--doc/api/deployments.md2
-rw-r--r--doc/api/graphql/reference/index.md50
-rw-r--r--doc/api/projects.md2
-rw-r--r--doc/ci/environments/deployment_safety.md44
-rw-r--r--doc/ci/environments/index.md2
-rw-r--r--doc/ci/jobs/index.md2
-rw-r--r--doc/ci/pipelines/settings.md26
-rw-r--r--doc/ci/resource_groups/index.md2
-rw-r--r--doc/development/fips_compliance.md2
-rw-r--r--doc/development/service_ping/index.md2
-rw-r--r--doc/development/testing_guide/contract/consumer_tests.md2
-rw-r--r--doc/development/testing_guide/frontend_testing.md2
-rw-r--r--doc/user/application_security/api_fuzzing/index.md228
-rw-r--r--doc/user/application_security/dast_api/index.md225
-rw-r--r--doc/user/application_security/dependency_scanning/index.md8
-rw-r--r--lib/api/helpers/projects_helpers.rb2
-rw-r--r--lib/api/release/links.rb6
-rw-r--r--lib/gitlab/patch/sidekiq_cron_poller.rb28
-rw-r--r--locale/gitlab.pot17
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb2
-rw-r--r--spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap4
-rw-r--r--spec/frontend/runner/admin_runners/admin_runners_app_spec.js7
-rw-r--r--spec/frontend/runner/components/runner_stacked_layout_banner_spec.js41
-rw-r--r--spec/frontend/runner/group_runners/group_runners_app_spec.js7
-rw-r--r--spec/helpers/json_helper_spec.rb36
70 files changed, 723 insertions, 266 deletions
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index fba73cd4bec..ab003fb2879 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -349,7 +349,7 @@ export default {
<template>
<div
data-testid="designs-root"
- class="gl-mt-5"
+ class="gl-mt-4"
@mouseenter="toggleOnPasteListener"
@mouseleave="toggleOffPasteListener"
>
diff --git a/app/assets/javascripts/notes/components/notes_activity_header.vue b/app/assets/javascripts/notes/components/notes_activity_header.vue
index e4f88962731..9c3b2139a5d 100644
--- a/app/assets/javascripts/notes/components/notes_activity_header.vue
+++ b/app/assets/javascripts/notes/components/notes_activity_header.vue
@@ -27,7 +27,7 @@ export default {
<template>
<div
- class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5 gl-mt-5 gl-border-t"
+ class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5"
>
<h2 class="gl-font-size-h1 gl-m-0">{{ __('Activity') }}</h2>
<div class="gl-display-flex gl-gap-3 gl-w-full gl-sm-w-auto gl-mt-3 gl-sm-mt-0">
diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
index dbaabb35cde..27c9d95bf09 100644
--- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
+++ b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
@@ -15,7 +15,6 @@ import allRunnersQuery from 'ee_else_ce/runner/graphql/list/all_runners.query.gr
import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql';
import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
-import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue';
import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
@@ -41,7 +40,6 @@ export default {
components: {
GlLink,
RegistrationDropdown,
- RunnerStackedLayoutBanner,
RunnerFilteredSearchBar,
RunnerList,
RunnerListEmptyState,
@@ -162,8 +160,6 @@ export default {
</script>
<template>
<div>
- <runner-stacked-layout-banner />
-
<div
class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0"
>
diff --git a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
deleted file mode 100644
index e3a9a9fd8a4..00000000000
--- a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import allChangesCommittedSvg from '@gitlab/svgs/dist/illustrations/multi-editor_all_changes_committed_empty.svg';
-import { GlBanner } from '@gitlab/ui';
-
-import { s__ } from '~/locale';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-
-const I18N_TITLE = s__("Runners|We've made some changes and want your feedback");
-const I18N_DESCRIPTION = s__(
- "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!",
-);
-const I18N_LINK = s__('Runners|Add your feedback in the issue');
-
-// use a data url instead getting it from via HTML data-* attributes to simplify removal of this feature flag
-const ILLUSTRATION_URL = `data:image/svg+xml;utf8,${encodeURIComponent(allChangesCommittedSvg)}`;
-const ISSUE_URL = 'https://gitlab.com/gitlab-org/gitlab/-/issues/371621';
-const STORAGE_KEY = 'runner_list_stacked_layout_feedback_dismissed';
-
-export default {
- components: {
- GlBanner,
- LocalStorageSync,
- },
- data() {
- return {
- isDismissed: false,
- };
- },
- methods: {
- onClose() {
- this.isDismissed = true;
- },
- },
- I18N_TITLE,
- I18N_DESCRIPTION,
- I18N_LINK,
- ILLUSTRATION_URL,
- ISSUE_URL,
- STORAGE_KEY,
-};
-</script>
-
-<template>
- <div>
- <local-storage-sync v-model="isDismissed" :storage-key="$options.STORAGE_KEY" />
- <gl-banner
- v-if="!isDismissed"
- :svg-path="$options.ILLUSTRATION_URL"
- :title="$options.I18N_TITLE"
- :button-text="$options.I18N_LINK"
- :button-link="$options.ISSUE_URL"
- class="gl-my-5"
- @close="onClose"
- >
- <p>{{ $options.I18N_DESCRIPTION }}</p>
- </gl-banner>
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/runner/group_runners/group_runners_app.vue
index 7f56d895682..9f80f3a8a53 100644
--- a/app/assets/javascripts/runner/group_runners/group_runners_app.vue
+++ b/app/assets/javascripts/runner/group_runners/group_runners_app.vue
@@ -15,7 +15,6 @@ import groupRunnersQuery from 'ee_else_ce/runner/graphql/list/group_runners.quer
import groupRunnersCountQuery from 'ee_else_ce/runner/graphql/list/group_runners_count.query.graphql';
import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
-import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue';
import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
import RunnerList from '../components/runner_list.vue';
import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
@@ -43,7 +42,6 @@ export default {
components: {
GlLink,
RegistrationDropdown,
- RunnerStackedLayoutBanner,
RunnerFilteredSearchBar,
RunnerList,
RunnerListEmptyState,
@@ -201,8 +199,6 @@ export default {
<template>
<div>
- <runner-stacked-layout-banner />
-
<div class="gl-display-flex gl-align-items-center">
<runner-type-tabs
ref="runner-type-tabs"
diff --git a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
index 0d3e951de7e..9a866ca23c2 100644
--- a/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
+++ b/app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue
@@ -247,7 +247,7 @@ export default {
<template>
<div
- class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-5"
+ class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-4"
data-testid="work-item-links"
>
<div
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index 39786aa0138..14971e3b2ee 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -24,6 +24,10 @@
+ .snippet-file-content {
@include gl-mt-5;
}
+
+ &:last-of-type {
+ margin-bottom: 0;
+ }
}
.snippet-header {
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index b2fbce7cb4b..8bd068b758b 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -875,9 +875,12 @@ $tabs-holder-z-index: 250;
}
.mr-widget-workflow {
- margin-top: $gl-padding;
position: relative;
+ &:not(:first-child) {
+ margin-top: $gl-padding;
+ }
+
&:not(:last-child)::before {
content: '';
border-left: 2px solid var(--gray-10, $gray-10);
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 6070311dcb6..1b6e7954366 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -76,10 +76,6 @@
.btn-edit {
margin-left: auto;
}
-
- .emoji-block {
- padding: $gl-padding-4 0;
- }
}
.issuable-show-labels {
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index c88834c088f..32e5547f5d0 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -123,9 +123,6 @@ ul.related-merge-requests > li gl-emoji {
}
.new-branch-col {
- @include gl-pb-3;
- @include gl-my-2;
-
.discussion-filter-container {
&:not(:last-child) {
margin-right: $gl-spacing-scale-3;
@@ -225,7 +222,7 @@ ul.related-merge-requests > li gl-emoji {
.new-branch-col {
@include gl-pb-0;
- align-self: center;
+ align-self: flex-end;
}
}
diff --git a/app/helpers/json_helper.rb b/app/helpers/json_helper.rb
new file mode 100644
index 00000000000..e61c789fd08
--- /dev/null
+++ b/app/helpers/json_helper.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module JsonHelper
+ # These two JSON helpers are short-form wrappers for the Gitlab::Json
+ # class, which should be used in place of .to_json calls or calls to
+ # the JSON class.
+ def json_generate(*args)
+ Gitlab::Json.generate(*args)
+ end
+
+ def json_parse(*args)
+ Gitlab::Json.parse(*args)
+ end
+end
diff --git a/app/presenters/commit_status_presenter.rb b/app/presenters/commit_status_presenter.rb
index 059d6d06be2..f6720546fab 100644
--- a/app/presenters/commit_status_presenter.rb
+++ b/app/presenters/commit_status_presenter.rb
@@ -41,7 +41,7 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
TROUBLESHOOTING_DOC = {
environment_creation_failure: { path: 'ci/environments/index', anchor: 'a-deployment-job-failed-with-this-job-could-not-be-executed-because-it-would-create-an-environment-with-an-invalid-parameter-error' },
- failed_outdated_deployment_job: { path: 'ci/environments/deployment_safety', anchor: 'skip-outdated-deployment-jobs' }
+ failed_outdated_deployment_job: { path: 'ci/environments/deployment_safety', anchor: 'prevent-outdated-deployment-jobs' }
}.freeze
private_constant :CALLOUT_FAILURE_MESSAGES
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 6d370919460..c8b0704c35d 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -7,8 +7,9 @@
%h1.page-title.gl-font-size-h-display
= _('Group: %{group_name}') % { group_name: @group.full_name }
- = link_to admin_group_edit_path(@group), class: "btn btn-default gl-button float-right", data: { qa_selector: 'edit_group_link' } do
- = sprite_icon('pencil', css_class: 'gl-icon gl-mr-2')
+ = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group),
+ button_options: { class: 'gl-float-right', data: { qa_selector: 'edit_group_link' }},
+ icon: 'pencil') do
= _('Edit')
%hr
.row
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 3952a450c4a..5062599c261 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -1,7 +1,7 @@
- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
- if api_awards_path
- .gl-display-flex.gl-flex-wrap.gl-justify-content-space-between.gl-py-3
+ .gl-display-flex.gl-flex-wrap.gl-justify-content-space-between.gl-pt-3
#js-vue-awards-block{ data: { path: api_awards_path, can_award_emoji: can?(current_user, :award_emoji, awardable).to_s } }
= yield
- else
diff --git a/app/views/projects/merge_requests/_awards_block.html.haml b/app/views/projects/merge_requests/_awards_block.html.haml
index 820927fdd1a..c1952793e72 100644
--- a/app/views/projects/merge_requests/_awards_block.html.haml
+++ b/app/views/projects/merge_requests/_awards_block.html.haml
@@ -1,2 +1,2 @@
-.content-block.emoji-block.emoji-list-container.js-noteable-awards
+.emoji-block.emoji-list-container.js-noteable-awards
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true, api_awards_path: award_emoji_merge_request_api_path(@merge_request)
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 51d28411b30..68dc7f2be8d 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -1,6 +1,6 @@
- help_link_public_pipelines = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'change-which-users-can-view-your-pipelines'), target: '_blank', rel: 'noopener noreferrer'
- help_link_auto_canceling = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'auto-cancel-redundant-pipelines'), target: '_blank', rel: 'noopener noreferrer'
-- help_link_skip_outdated = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'skip-outdated-deployment-jobs'), target: '_blank', rel: 'noopener noreferrer'
+- help_link_skip_outdated = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'prevent-outdated-deployment-jobs'), target: '_blank', rel: 'noopener noreferrer'
- help_link_separated_caches = link_to sprite_icon('question-o'), help_page_path('ci/caching/index', anchor: 'cache-key-names'), target: '_blank', rel: 'noopener noreferrer'
.row.gl-mt-3
@@ -22,8 +22,8 @@
.form-group
= f.fields_for :ci_cd_settings_attributes, @project.ci_cd_settings do |form|
- = form.gitlab_ui_checkbox_component :forward_deployment_enabled, _("Skip outdated deployment jobs"),
- help_text: (_('When a deployment job is successful, skip older deployment jobs that are still pending.') + ' ' + help_link_skip_outdated).html_safe
+ = form.gitlab_ui_checkbox_component :forward_deployment_enabled, _("Prevent outdated deployment jobs"),
+ help_text: (_('When a deployment job is successful, prevent older deployment jobs that are still pending.') + ' ' + help_link_skip_outdated).html_safe
.form-group
= f.gitlab_ui_checkbox_component :ci_separated_caches,
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index ddebc19be15..7c4492fb901 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -5,7 +5,7 @@
#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id, 'report-abuse-path': snippet_report_abuse_path(@snippet), 'can-report-spam': @snippet.submittable_as_spam_by?(current_user).to_s } }
-.row-content-block.top-block.content-component-block.gl-px-0.gl-py-2
+.gl-px-0.gl-py-2
= render 'award_emoji/awards_block', awardable: @snippet, inline: true, api_awards_path: project_snippets_award_api_path(@snippet)
#notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true
diff --git a/app/views/shared/_file_picker_button.html.haml b/app/views/shared/_file_picker_button.html.haml
index 1d688e7f4b0..8d76e9c1b7d 100644
--- a/app/views/shared/_file_picker_button.html.haml
+++ b/app/views/shared/_file_picker_button.html.haml
@@ -1,7 +1,8 @@
- classes = local_assigns.fetch(:classes, '')
%span.js-filepicker
- %button.gl-button.btn.btn-default.js-filepicker-button{ type: 'button', class: classes }= _("Choose file…")
+ = render Pajamas::ButtonComponent.new(button_options: { class: "js-filepicker-button #{classes}" }) do
+ = _("Choose file…")
%span.file_name.js-filepicker-filename= _("No file chosen.")
= f.file_field field, class: "js-filepicker-input hidden"
- if help_text.present?
diff --git a/app/views/shared/issue_type/_emoji_block.html.haml b/app/views/shared/issue_type/_emoji_block.html.haml
index a5c71fb1d24..7eb3c0f5c9f 100644
--- a/app/views/shared/issue_type/_emoji_block.html.haml
+++ b/app/views/shared/issue_type/_emoji_block.html.haml
@@ -1,8 +1,8 @@
- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
-.content-block.emoji-block.emoji-block-sticky
+.emoji-block.emoji-block-sticky
.row.gl-m-0.gl-justify-content-space-between
.js-noteable-awards
= render 'award_emoji/awards_block', awardable: issuable, inline: true, api_awards_path: api_awards_path
- .new-branch-col.gl-font-size-0
+ .new-branch-col.gl-font-size-0.gl-my-2
= render 'new_branch' if show_new_branch_button?
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index c6932d49d33..9ef4b9e084d 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -29,8 +29,10 @@
= f.submit _('Save changes'), class: 'js-save-button gl-mr-2', pajamas_button: true
- else
= f.submit _('Create label'), class: 'js-save-button gl-mr-2', data: { qa_selector: 'label_create_button' }, pajamas_button: true
- = link_to _('Cancel'), back_path, class: 'btn gl-button btn-default btn-cancel gl-mr-2'
+ = render Pajamas::ButtonComponent.new(href: back_path) do
+ = _('Cancel')
+
- if @label.persisted?
- presented_label = @label.present
- %button.btn.btn-danger.gl-button.btn-danger-secondary.js-delete-label-modal-button{ type: 'button', data: { label_name: presented_label.name, subject_name: presented_label.subject_name, destroy_path: presented_label.destroy_path } }
- %span.gl-button-text= _('Delete')
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, button_options: { class: 'js-delete-label-modal-button', data: { label_name: presented_label.name, subject_name: presented_label.subject_name, destroy_path: presented_label.destroy_path } }) do
+ = _('Delete')
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 952023b3745..ad4d609a1dc 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -14,33 +14,31 @@
.cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] }
= render layout: 'users/cover_controls' do
- if @user == current_user
- = link_to profile_path, class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip',
- title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('pencil')
+ = render Pajamas::ButtonComponent.new(href: profile_path,
+ icon: 'pencil',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- elsif current_user
- if @user.abuse_report
- %button{ class: link_classes + 'btn gl-button btn-danger btn-icon', title: s_('UserProfile|Already reported for abuse'),
- data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } }>
- = sprite_icon('error')
+ = render Pajamas::ButtonComponent.new(variant: :danger,
+ icon: 'error',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Already reported for abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- else
- = link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referer), class: link_classes + 'btn gl-button btn-default btn-icon',
- title: s_('UserProfile|Report abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('error')
+ = render Pajamas::ButtonComponent.new(href: new_abuse_report_path(user_id: @user.id, ref_url: request.referer),
+ icon: 'error',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Report abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- verified_gpg_keys = @user.gpg_keys.select(&:verified?)
- if verified_gpg_keys.any?
- = link_to user_gpg_keys_path,
- class: link_classes + 'btn btn-default btn-md gl-button btn-icon has-tooltip',
- title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length),
- data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('key', css_class: 'gl-button-icon gl-icon')
+ = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path,
+ icon: 'key',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- if can?(current_user, :read_user_profile, @user)
- = link_to user_path(@user, rss_url_options), class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip',
- title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('rss')
+ = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options),
+ icon: 'rss',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- if current_user && current_user.admin?
- = link_to [:admin, @user], class: link_classes + 'btn gl-button btn-default btn-icon', title: s_('UserProfile|View user in admin area'),
- data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = sprite_icon('user')
+ = render Pajamas::ButtonComponent.new(href: [:admin, @user],
+ icon: 'user',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}})
- if current_user && current_user.id != @user.id
- if current_user.following?(@user)
= form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
@@ -133,7 +131,6 @@
.profile-user-bio
= @user.bio
-
- unless profile_tabs.empty?
.scrolling-tabs-container
.fade-left= sprite_icon('chevron-lg-left', size: 12)
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 050d112843f..732d46d284b 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -505,11 +505,11 @@ production: &base
# Periodically executed jobs, to self-heal GitLab, do external synchronizations, etc.
# Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
cron_jobs:
- # Interval, in seconds, for each Sidekiq process to check for scheduled cron jobs that need to be enqueued. If set
- # to 0, disable polling for cron jobs entirely. This is useful in setups with multiple Sidekiq processes if you want
- # to limit which ones perform this task. Note that at least one process in your instance needs to have polling
- # enabled for cron jobs to be executed.
- poll_interval: 30
+ # Interval, in seconds, for each Sidekiq process to check for scheduled cron jobs that need to be enqueued. If not
+ # set, the interval scales dynamically with the number of Sidekiq processes. If set to 0, disable polling for cron
+ # jobs entirely.
+ # poll_interval: 30
+
# Flag stuck CI jobs as failed
stuck_ci_jobs_worker:
cron: "0 * * * *"
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 45307c3454b..ea22b6fdbc0 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -457,7 +457,7 @@ if Gitlab.ee? && Settings['ee_cron_jobs']
Settings.cron_jobs.merge!(Settings.ee_cron_jobs)
end
-Settings.cron_jobs['poll_interval'] ||= 30
+Settings.cron_jobs['poll_interval'] ||= nil
Settings.cron_jobs['stuck_ci_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_ci_jobs_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['stuck_ci_jobs_worker']['job_class'] = 'StuckCiJobsWorker'
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index cef34425bf4..d1b734fb4bc 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -114,3 +114,4 @@ end
Sidekiq::Scheduled::Poller.prepend Gitlab::Patch::SidekiqPoller
Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqPoller
+Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqCronPoller
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index a336f5ff8bc..df54ea402bd 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -124,7 +124,7 @@ The following are required to run Geo:
- Git 2.9 or later
- Git-lfs 2.4.2 or later on the user side when using LFS
- All sites must run [the same GitLab and PostgreSQL versions](setup/database.md#postgresql-replication).
-- If using different operating system versions between Geo sites, [check OS locale data compatibility](replication/troubleshooting.md#check-os-locale-data-compatibility) across Geo sites.
+- If using different operating system versions between Geo sites, [check OS locale data compatibility](replication/troubleshooting.md#check-os-locale-data-compatibility) across Geo sites.
Additionally, check the GitLab [minimum requirements](../../install/requirements.md),
and we recommend you use the latest version of GitLab for a better experience.
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 2cf9f2a1e83..897cd478252 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -109,18 +109,18 @@ Below you can find the above guidance in the form of a decision tree. It's recom
```mermaid
%%{init: { 'theme': 'base' } }%%
-graph TD
+graph TD
L1A(<b>What Reference Architecture should I use?</b>) --> L2A(More than 3000 users?)
L2A -->|No| L3A("<a href=#do-you-need-high-availability-ha>Do you need HA?</a><br>(or Zero-Downtime Upgrades)") --> |Yes| L4A><b>Recommendation</b><br><br>3K architecture with HA<br>including supported modifications]
L3A -->|No| L4B><b>Recommendation</b><br><br>Architecture closest to user<br>count with Backups]
L2A -->|Yes| L3B[Do you have experience with<br/>and want additional resilience<br/>with select components in Kubernetes?]
L3B -->|No| L4C><b>Recommendation</b><br><br>Architecture closest to user<br>count with HA]
L3B -->|Yes| L4D><b>Recommendation</b><br><br>Cloud Native Hybrid architecture<br>closest to user count]
-
+
L5A("<a href=#gitlab-geo-cross-regional-distribution-disaster-recovery>Do you need cross regional distribution or disaster recovery?"</a>) --> |Yes| L6A><b>Additional Recommendation</b><br><br> GitLab Geo]
L4A -.- L5A
- L4B -.- L5A
- L4C -.- L5A
+ L4B -.- L5A
+ L4C -.- L5A
L4D -.- L5A
classDef default fill:#FCA326
diff --git a/doc/administration/troubleshooting/linux_cheat_sheet.md b/doc/administration/troubleshooting/linux_cheat_sheet.md
index 0c6fcd31d1d..90cd1e24c79 100644
--- a/doc/administration/troubleshooting/linux_cheat_sheet.md
+++ b/doc/administration/troubleshooting/linux_cheat_sheet.md
@@ -210,7 +210,7 @@ using the `-s` or `--sort` flag. The number of results defaults to 25 processes,
can be changed using the `-c`/`--count` option. See `--help` for full details.
```shell
-$ ./strace-parser sidekiq_trace.txt summary -c15 -s=pid
+$ ./strace-parser sidekiq_trace.txt summary -c15 -s=pid
Top 15 PIDs by PID #
-----------
@@ -244,7 +244,7 @@ processes using the `-p`/`--pid` for a specific process, or `-s`/`--stats` flags
a sorted list. `--stats` takes the same sorting and count options as summary.
```shell
-./strace-parser sidekiq_trace.txt p 16815
+./strace-parser sidekiq_trace.txt p 16815
PID 16815
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index 9618d57013f..2c5161c44f5 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -133,7 +133,7 @@ Example response:
"tag": false,
"project": {
"ci_job_token_scope_enabled": false
- },
+ },
"user": {
"id": 1,
"name": "Administrator",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 11a60671008..64ac83ef46e 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -13373,6 +13373,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`. |
| <a id="groupscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Group.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupscanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
##### `Group.timelogs`
Time logged on issues and merge requests in the group and its subgroups.
@@ -15469,6 +15485,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="namespacescanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`. |
| <a id="namespacescanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Namespace.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="namespacescanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
### `NamespaceBan`
#### Fields
@@ -16226,7 +16258,6 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectrequestaccessenabled"></a>`requestAccessEnabled` | [`Boolean`](#boolean) | Indicates if users can request member access to the project. |
| <a id="projectrequirementstatescount"></a>`requirementStatesCount` | [`RequirementStatesCount`](#requirementstatescount) | Number of requirements for the project by their state. |
| <a id="projectsastciconfiguration"></a>`sastCiConfiguration` | [`SastCiConfiguration`](#sastciconfiguration) | SAST CI configuration for the project. |
-| <a id="projectscanresultpolicies"></a>`scanResultPolicies` | [`ScanResultPolicyConnection`](#scanresultpolicyconnection) | Scan Result Policies of the project. (see [Connections](#connections)) |
| <a id="projectsecuritydashboardpath"></a>`securityDashboardPath` | [`String`](#string) | Path to project's security dashboard. |
| <a id="projectsecurityscanners"></a>`securityScanners` | [`SecurityScanners`](#securityscanners) | Information about security analyzers used in the project. |
| <a id="projectsentryerrors"></a>`sentryErrors` | [`SentryErrorCollection`](#sentryerrorcollection) | Paginated collection of Sentry errors on the project. |
@@ -17171,6 +17202,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectscanexecutionpoliciesactionscantypes"></a>`actionScanTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filters policies by the action scan type. Only these scan types are supported: `dast`, `secret_detection`, `cluster_image_scanning`, `container_scanning`, `sast`. |
| <a id="projectscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Project.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectscanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
##### `Project.securityTrainingProviders`
List of security training providers for the project.
@@ -18064,6 +18111,7 @@ Represents the scan result policy.
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` | [`[Group!]`](#group) | Approvers of the group type. |
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
+| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
| <a id="scanresultpolicyuserapprovers"></a>`userApprovers` | [`[UserCore!]`](#usercore) | Approvers of the user type. |
| <a id="scanresultpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 470b3721b23..0eab8e485a8 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1385,7 +1385,7 @@ Supported attributes:
| `builds_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `ci_config_path` | string | **{dotted-circle}** No | The path to CI configuration file. |
| `ci_default_git_depth` | integer | **{dotted-circle}** No | Default number of revisions for [shallow cloning](../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone). |
-| `ci_forward_deployment_enabled` | boolean | **{dotted-circle}** No | When a new deployment job starts, [skip older deployment jobs](../ci/pipelines/settings.md#skip-outdated-deployment-jobs) that are still pending |
+| `ci_forward_deployment_enabled` | boolean | **{dotted-circle}** No | Enable or disable [prevent outdated deployment jobs](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
| `ci_allow_fork_pipelines_to_run_in_parent_project` | boolean | **{dotted-circle}** No | Enable or disable [running pipelines in the parent project for merge requests from forks](../ci/pipelines/merge_request_pipelines.md#run-pipelines-in-the-parent-project). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325189) in GitLab 15.3.)_ |
| `ci_separated_caches` | boolean | **{dotted-circle}** No | Set whether or not caches should be [separated](../ci/caching/index.md#cache-key-names) by branch protection status. |
| `container_expiration_policy_attributes` | hash | **{dotted-circle}** No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). |
diff --git a/doc/ci/environments/deployment_safety.md b/doc/ci/environments/deployment_safety.md
index 665aeb23d28..03965800bd4 100644
--- a/doc/ci/environments/deployment_safety.md
+++ b/doc/ci/environments/deployment_safety.md
@@ -22,7 +22,7 @@ You can:
If you are using a continuous deployment workflow and want to ensure that concurrent deployments to the same environment do not happen, you should enable the following options:
- [Ensure only one deployment job runs at a time](#ensure-only-one-deployment-job-runs-at-a-time)
-- [Skip outdated deployment jobs](#skip-outdated-deployment-jobs)
+- [Prevent outdated deployment jobs](#prevent-outdated-deployment-jobs)
## Restrict write access to a critical environment
@@ -63,7 +63,10 @@ The improved pipeline flow **after** using the resource group:
For more information, see [Resource Group documentation](../resource_groups/index.md).
-## Skip outdated deployment jobs
+## Prevent outdated deployment jobs
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - In GitLab 15.5, the behavior was [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/363328) to prevent outdated job runs.
The effective execution order of pipeline jobs can vary from run to run, which
could cause undesired behavior. For example, a [deployment job](../jobs/index.md#deployment-jobs)
@@ -71,22 +74,45 @@ in a newer pipeline could finish before a deployment job in an older pipeline.
This creates a race condition where the older deployment finishes later,
overwriting the "newer" deployment.
-You can ensure that older deployment jobs are cancelled automatically when a newer deployment
-job is started by enabling the [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) feature.
+You can prevent older deployment jobs from running when a newer deployment
+job is started by enabling the [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) feature.
+
+When an older deployment job starts, it fails and is labeled:
+
+- `failed outdated deployment job` in the pipeline view.
+- `The deployment job is older than the latest deployment, and therefore failed.`
+ when viewing the completed job.
+
+When an older deployment job is manual, the play button is disabled with a message
+`This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.`.
+
+Job age is determined by the job start time, not the commit time, so a newer commit
+can be prevented in some circumstances.
+
+### How to rollback to an outdated deployment
+
+In some cases, you need to rollback to an outdated deployment. Current workarounds are:
+
+- Temporarily disable this feature, rollback and re-enable.
+- Run a new pipeline with previous commit. It contains newer deployment jobs than the latest deployment.
+
+Please see [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/378359) for more information about improving the usability.
+
+### Example
-Example of a problematic pipeline flow **before** enabling Skip outdated deployment jobs:
+Example of a problematic pipeline flow **before** enabling Prevent outdated deployment jobs:
1. Pipeline-A is created on the default branch.
1. Later, Pipeline-B is created on the default branch (with a newer commit SHA).
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
1. The `deploy` job in Pipeline-A finished later, and deploys the older code, **overwriting** the newer (latest) deployment.
-The improved pipeline flow **after** enabling Skip outdated deployment jobs:
+The improved pipeline flow **after** enabling Prevent outdated deployment jobs:
1. Pipeline-A is created on the default branch.
1. Later, Pipeline-B is created on the default branch (with a newer SHA).
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
-1. The `deploy` job in Pipeline-A was automatically cancelled, so that it doesn't overwrite the deployment from the newer pipeline.
+1. The `deploy` job in Pipeline-A fails, so that it doesn't overwrite the deployment from the newer pipeline.
## Prevent deployments during deploy freeze windows
@@ -153,7 +179,7 @@ Before promoting a deployment to a production environment, cross-verifying it wi
### Pipelines jobs fail with `The deployment job is older than the previously succeeded deployment job...`
-This is caused by the [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) feature.
+This is caused by the [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) feature.
If you have multiple jobs for the same environment (including non-deployment jobs), you might encounter this problem, for example:
```yaml
@@ -166,5 +192,5 @@ build:service-b:
name: production
```
-The [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) might
+The [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) might
not work well with this configuration, and must be disabled.
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 63641a9b7c3..2a92503f5c9 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -721,7 +721,7 @@ build:
```
This gives you access to environment-scoped variables, and can be used to protect builds from unauthorized access. Also,
-it's effective to avoid the [skip outdated deployment jobs](deployment_safety.md#skip-outdated-deployment-jobs) feature.
+it's effective to avoid the [prevent outdated deployment jobs](deployment_safety.md#prevent-outdated-deployment-jobs) feature.
### Group similar environments
diff --git a/doc/ci/jobs/index.md b/doc/ci/jobs/index.md
index d1a4f1e35bf..492eac9b250 100644
--- a/doc/ci/jobs/index.md
+++ b/doc/ci/jobs/index.md
@@ -389,5 +389,5 @@ deploy me:
The behavior of deployment jobs can be controlled with
[deployment safety](../environments/deployment_safety.md) settings like
-[skipping outdated deployment jobs](../environments/deployment_safety.md#skip-outdated-deployment-jobs)
+[preventing outdated deployment jobs](../environments/deployment_safety.md#prevent-outdated-deployment-jobs)
and [ensuring only one deployment job runs at a time](../environments/deployment_safety.md#ensure-only-one-deployment-job-runs-at-a-time).
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index d7155004359..246285eedcb 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -82,9 +82,10 @@ You can set pending or running pipelines to cancel automatically when a new pipe
Use the [`interruptible`](../yaml/index.md#interruptible) keyword to indicate if a
running job can be cancelled before it completes.
-## Skip outdated deployment jobs
+## Prevent outdated deployment jobs
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - In GitLab 15.5, the behavior was [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/363328) to prevent outdated job runs.
Your project may have multiple concurrent deployment jobs that are
scheduled to run in the same time frame.
@@ -97,28 +98,9 @@ To avoid this scenario:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **General pipelines**.
-1. Select the **Skip outdated deployment jobs** checkbox.
+1. Select the **Prevent outdated deployment jobs** checkbox.
1. Select **Save changes**.
-When a new deployment starts, older deployment jobs are skipped. Skipped jobs are labeled:
-
-- `forward deployment failure` in the pipeline view.
-- `The deployment job is older than the previously succeeded deployment job, and therefore cannot be run`
- when viewing the completed job.
-
-Job age is determined by the job start time, not the commit time, so a newer commit
-can be skipped in some circumstances.
-
-For more information, see [Deployment safety](../environments/deployment_safety.md).
-
-## Retry outdated jobs
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211339) in GitLab 13.6.
-
-A deployment job can fail because a newer one has run. If you retry the failed deployment job, the
-environment could be overwritten with older source code. If you select **Retry**, a modal warns you
-about this and asks for confirmation.
-
For more information, see [Deployment safety](../environments/deployment_safety.md).
## Specify a custom CI/CD configuration file
diff --git a/doc/ci/resource_groups/index.md b/doc/ci/resource_groups/index.md
index 2803ddba828..92808a2806c 100644
--- a/doc/ci/resource_groups/index.md
+++ b/doc/ci/resource_groups/index.md
@@ -89,7 +89,7 @@ The following modes are supported:
that are sorted by pipeline ID in descending order.
This mode is efficient when you want to ensure that the jobs are executed from the newest pipeline and
- cancel all of the old deploy jobs with the [skip outdated deployment jobs](../environments/deployment_safety.md#skip-outdated-deployment-jobs) feature.
+ prevent all of the old deploy jobs with the [prevent outdated deployment jobs](../environments/deployment_safety.md#prevent-outdated-deployment-jobs) feature.
This is the most efficient option in terms of the pipeline efficiency, but you must ensure that each deployment job is idempotent.
### Change the process mode
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 475c1a49000..c976f057d02 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -67,7 +67,7 @@ listed here that also do not work properly in FIPS mode:
- [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
supports a reduced set of [analyzers](../user/application_security/sast/index.md#fips-enabled-images)
when operating in FIPS-compliant mode.
-- Advanced Search is currently not included in FIPS mode. It must not be enabled to be FIPS-compliant.
+- Advanced Search is currently not included in FIPS mode. It must not be enabled to be FIPS-compliant.
- [Gravatar or Libravatar-based profile images](../administration/libravatar.md) are not FIPS-compliant.
Additionally, these package repositories are disabled in FIPS mode:
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index 0a4e5998345..5baf1a6d38d 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -115,7 +115,7 @@ sequenceDiagram
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/295289) in GitLab 15.2. [Feature flag `measure_service_ping_metric_collection`](https://gitlab.com/gitlab-org/gitlab/-/issues/358128) removed.
```ruby
- {
+ {
"metadata"=>
{
"uuid"=>"0000000-0000-0000-0000-000000000000",
diff --git a/doc/development/testing_guide/contract/consumer_tests.md b/doc/development/testing_guide/contract/consumer_tests.md
index 67bb7160749..9c72e6835bd 100644
--- a/doc/development/testing_guide/contract/consumer_tests.md
+++ b/doc/development/testing_guide/contract/consumer_tests.md
@@ -213,7 +213,7 @@ pactWith(
const discussions = await getDiscussions({
url: provider.mockService.baseUrl,
});
-
+
expect(discussions).toEqual(Matchers.eachLike({
id: 'fd73763cbcbf7b29eb8765d969a38f7d735e222a',
project_id: 6954442,
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index d7627e2064f..256675e23b7 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -458,7 +458,7 @@ If you cannot register handlers to the `Promise`, for example because it is exec
```javascript
it('waits for an Ajax call', async () => {
synchronousFunction();
-
+
await waitForPromises();
expect(something).toBe('done');
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index d542c2d4be5..a6ea20767db 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -2211,9 +2211,235 @@ Setting `SECURE_ANALYZERS_PREFIX` changes the Docker image registry location for
For more information, see [Offline environments](../offline_deployments/index.md).
+## Performance tuning and testing speed
+
+Security tools that perform API fuzz testing, such as API Fuzzing, perform testing by sending requests to an instance of your running application. The requests are mutated by our fuzzing engine to trigger unexpected behavior that might exist in your application. The speed of an API fuzzing test depends on the following:
+
+- How many requests per second can be sent to your application by our tooling
+- How fast your application responds to requests
+- How many requests must be sent to test the application
+ - How many operations your API is comprised of
+ - How many fields are in each operation (think JSON bodies, headers, query string, cookies, etc.)
+
+If API Fuzzing testing job still takes longer than expected after following the advice in this performance guide, reach out to support for further assistance.
+
+### Diagnosing performance issues
+
+The first step to resolving performance issues is to understand what is contributing to the slower-than-expected testing time. Some common issues we see are:
+
+- API Fuzzing is running on a slow or single-CPU GitLab Runner (GitLab Shared Runners are single-CPU)
+- The application deployed to a slow/single-CPU instance and is not able to keep up with the testing load
+- The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+- The application contains an operation that returns a large amount of data (> 500K+)
+- The application contains a large number of operations (> 40)
+
+#### The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+
+The API Fuzzing job output contains helpful information about how fast we are testing, how fast each operation being tested responds, and summary information. Let's take a look at some sample output to see how it can be used in tracking down performance issues:
+
+```shell
+API Security: Loaded 10 operations from: assets/har-large-response/large_responses.har
+API Security:
+API Security: Testing operation [1/10]: 'GET http://target:7777/api/large_response_json'.
+API Security: - Parameters: (Headers: 4, Query: 0, Body: 0)
+API Security: - Request body size: 0 Bytes (0 bytes)
+API Security:
+API Security: Finished testing operation 'GET http://target:7777/api/large_response_json'.
+API Security: - Excluded Parameters: (Headers: 0, Query: 0, Body: 0)
+API Security: - Performed 767 requests
+API Security: - Average response body size: 130 MB
+API Security: - Average call time: 2 seconds and 82.69 milliseconds (2.082693 seconds)
+API Security: - Time to complete: 14 minutes, 8 seconds and 788.36 milliseconds (848.788358 seconds)
+```
+
+This job console output snippet starts by telling us how many operations were found (10), followed by notifications that testing has started on a specific operation and a summary of the operation has been completed. The summary is the most interesting part of this log output. In the summary, we can see that it took API Fuzzing 767 requests to fully test this operation and its related fields. We can also see that the average response time was 2 seconds and the time to complete was 14 minutes for this one operation.
+
+An average response time of 2 seconds is a good initial indicator that this specific operation takes a long time to test. Further, we can see that the response body size is quite large. The large body size is the culprit here, transferring that much data on each request is what takes the majority of that 2 seconds.
+
+For this issue, the team might decide to:
+
+- Use a multi-CPU runner. Using a multi-CPU runner allows API Fuzzing to parallelize the work being performed. This helps lower the test time, but getting the test down under 10 minutes might still be problematic without moving to a high CPU machine due to how long the operation takes to test.
+ - Trade off between how many CPUs and cost.
+- [Exclude this operation](#excluding-slow-operations) from the API Fuzzing test. While this is the simplest, it has the downside of a gap in security test coverage.
+- [Exclude the operation from feature branch API Fuzzing tests, but include it in the default branch test](#excluding-operations-in-feature-branches-but-not-default-branch).
+- [Split up the API Fuzzing testing into multiple jobs](#splitting-a-test-into-multiple-jobs).
+
+The likely solution is to use a combination of these solutions to reach an acceptable test time, assuming your team's requirements are in the 5-7 minute range.
+
+### Addressing performance issues
+
+The following sections document various options for addressing performance issues for API Fuzzing:
+
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding slow operations](#excluding-slow-operations)
+- [Splitting a test into multiple jobs](#splitting-a-test-into-multiple-jobs)
+- [Excluding operations in feature branches, but not default branch](#excluding-operations-in-feature-branches-but-not-default-branch)
+
+#### Using a multi-CPU Runner
+
+One of the easiest performance boosts can be achieved using a multi-CPU runner with API Fuzzing. This table shows statistics collected during benchmarking of a Java Spring Boot REST API. In this benchmark, the target and API Fuzzing share a single runner instance.
+
+| CPU Count | Request per Second |
+|----------------------|--------------------|
+| 1 CPU (Shared Runner)| 75 |
+| 4 CPU | 255 |
+| 8 CPU | 400 |
+
+As we can see from this table, increasing the CPU count of the runner can have a large impact on testing speed/performance.
+
+To use a multi-CPU typically requires deploying a self-managed GitLab Runner onto a multi-CPU machine or cloud compute instance.
+
+When multiple types of GitLab Runners are available for use, the various instances are commonly set up with tags that can be used in the job definition to select a type of runner.
+
+Here is an example job definition for API Fuzzing that adds a `tags` section with the tag `multi-cpu`. The job automatically extends the job definition included through the API Fuzzing template.
+
+```yaml
+apifuzzer_fuzz:
+ tags:
+ - multi-cpu
+```
+
+To verify that API Fuzzing can detect multiple CPUs in the runner, download the `gl-api-security-scanner.log` file from a completed job's artifacts. Search the file for the string `Starting work item processor` and inspect the reported max DOP (degree of parallelism). The max DOP should be greater than or equal to the number of CPUs assigned to the runner. The value is never lower than 2, even on single CPU runners, unless forced through a configuration variable. If the value reported is less than the number of CPUs assigned to the runner, then something is wrong with the runner deployment. If unable to identify the problem, open a ticket with support to assist.
+
+Example log entry:
+
+`17:00:01.084 [INF] <Peach.Web.Core.Services.WebRunnerMachine> Starting work item processor with 2 max DOP`
+
+#### Excluding slow operations
+
+In the case of one or two slow operations, the team might decide to skip testing the operations. Excluding the operation is done using the `FUZZAPI_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `FUZZAPI_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`.
+
+To verify the operation is excluded, run the API Fuzzing job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+apifuzzer_fuzz:
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/large_response_json
+```
+
+Excluding operations from testing could allow some vulnerabilities to go undetected.
+{: .alert .alert-warning}
+
+#### Splitting a test into multiple jobs
+
+Splitting a test into multiple jobs is supported by API Fuzzing through the use of [`FUZZAPI_EXCLUDE_PATHS`](#exclude-paths) and [`FUZZAPI_EXCLUDE_URLS`](#exclude-urls). When splitting a test up, a good pattern is to disable the `apifuzzer_fuzz` job and replace it with two jobs with identifying names. In this example we have two jobs, each job is testing a version of the API, so our names reflect that. However, this technique can be applied to any situation, not just with versions of an API.
+
+The rules we are using in the `apifuzzer_v1` and `apifuzzer_v2` jobs are copied from the [API Fuzzing template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST-API.gitlab-ci.yml).
+
+```yaml
+# Disable the main apifuzzer_fuzz job
+apifuzzer_fuzz:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+apifuzzer_v1:
+ extends: apifuzzer_fuzz
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/v1/**
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+
+apifuzzer_v2:
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/v2/**
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+```
+
+#### Excluding operations in feature branches, but not default branch
+
+In the case of one or two slow operations, the team might decide to skip testing the operations, or exclude them from feature branch tests, but include them for default branch tests. Excluding the operation is done using the `FUZZAPI_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `FUZZAPI_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`. Our configuration disables the main `apifuzzer_fuzz` job and creates two new jobs `apifuzzer_main` and `apifuzzer_branch`. The `apifuzzer_branch` is set up to exclude the long operation and only run on non-default branches (e.g. feature branches). The `apifuzzer_main` branch is set up to only execute on the default branch (`main` in this example). The `apifuzzer_branch` jobs run faster, allowing for quick development cycles, while the `apifuzzer_main` job which only runs on default branch builds, takes longer to run.
+
+To verify the operation is excluded, run the API Fuzzing job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+# Disable the main job so we can create two jobs with
+# different names
+apifuzzer_fuzz:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+# API Fuzzing for feature branch work, excludes /api/large_response_json
+apifuzzer_branch:
+ extends: apifuzzer_fuzz
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/large_response_json
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ when: never
+ - if: $CI_COMMIT_BRANCH
+
+# API Fuzzing for default branch (main in our case)
+# Includes the long running operations
+apifuzzer_main:
+ extends: apifuzzer_fuzz
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+```
+
## Troubleshooting
-### `Error waiting for API Security 'http://127.0.0.1:5000' to become available`
+### API Fuzzing job times out after N hours
+
+The top two reasons for the API Fuzzing job timing out are slow operations (> 1 second) and using a single-CPU runner for API Fuzzing (GitLab shared runners are single-CPU). Before you can diagnose the problem further, the job must complete so the output can be analyzed. We recommend to start with a multi-CPU runner first, then exclude portions of your API operations until the job completes and the output can be further reviewed.
+
+See the following documentation sections for assistance:
+
+- [Performance tuning and testing speed](#performance-tuning-and-testing-speed)
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding operations by path](#exclude-paths)
+- [Excluding slow operations](#excluding-slow-operations)
+
+### API Fuzzing job takes too long to complete
+
+See [Performance Tuning and Testing Speed](#performance-tuning-and-testing-speed)
+
+### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the API Fuzzing analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the API Fuzzing analyzer.
diff --git a/doc/user/application_security/dast_api/index.md b/doc/user/application_security/dast_api/index.md
index eae32f789b8..d109aaec170 100644
--- a/doc/user/application_security/dast_api/index.md
+++ b/doc/user/application_security/dast_api/index.md
@@ -2057,9 +2057,232 @@ Setting `SECURE_ANALYZERS_PREFIX` changes the Docker image registry location for
For more information, see [Offline environments](../offline_deployments/index.md).
+## Performance tuning and testing speed
+
+Security tools that perform dynamic analysis testing, such as DAST API, perform testing by sending requests to an instance of your running application. The requests are engineered to test for specific vulnerabilities that might exist in your application. The speed of a dynamic analysis test depends on the following:
+
+- How many requests per second can be sent to your application by our tooling
+- How fast your application responds to requests
+- How many requests must be sent to test the application
+ - How many operations your API is comprised of
+ - How many fields are in each operation (think JSON bodies, headers, query string, cookies, etc.)
+
+If the DAST API testing job still takes longer than expected reach after following the advice in this performance guide, reach out to support for further assistance.
+
+### Diagnosing performance issues
+
+The first step to resolving performance issues is to understand what is contributing to the slower-than-expected testing time. Some common issues we see are:
+
+- DAST API is running on a slow or single-CPU GitLab Runner (GitLab Shared Runners are single-CPU)
+- The application deployed to a slow/single-CPU instance and is not able to keep up with the testing load
+- The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+- The application contains an operation that returns a large amount of data (> 500K+)
+- The application contains a large number of operations (> 40)
+
+#### The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+
+The DAST API job output contains helpful information about how fast we are testing, how fast each operation being tested responds, and summary information. Let's take a look at some sample output to see how it can be used in tracking down performance issues:
+
+```shell
+API Security: Loaded 10 operations from: assets/har-large-response/large_responses.har
+API Security:
+API Security: Testing operation [1/10]: 'GET http://target:7777/api/large_response_json'.
+API Security: - Parameters: (Headers: 4, Query: 0, Body: 0)
+API Security: - Request body size: 0 Bytes (0 bytes)
+API Security:
+API Security: Finished testing operation 'GET http://target:7777/api/large_response_json'.
+API Security: - Excluded Parameters: (Headers: 0, Query: 0, Body: 0)
+API Security: - Performed 767 requests
+API Security: - Average response body size: 130 MB
+API Security: - Average call time: 2 seconds and 82.69 milliseconds (2.082693 seconds)
+API Security: - Time to complete: 14 minutes, 8 seconds and 788.36 milliseconds (848.788358 seconds)
+```
+
+This job console output snippet starts by telling us how many operations were found (10), followed by notifications that testing has started on a specific operation and a summary of the operation has been completed. The summary is the most interesting part of this log output. In the summary, we can see that it took DAST API 767 requests to fully test this operation and its related fields. We can also see that the average response time was 2 seconds and the time to complete was 14 minutes for this one operation.
+
+An average response time of 2 seconds is a good initial indicator that this specific operation takes a long time to test. Further, we can see that the response body size is quite large. The large body size is the culprit here, transferring that much data on each request is what takes the majority of that 2 seconds.
+
+For this issue, the team might decide to:
+
+- Use a multi-CPU runner. Using a multi-CPU runner allows DAST API to parallelize the work being performed. This helps lower the test time, but getting the test down under 10 minutes might still be problematic without moving to a high CPU machine due to how long the operation takes to test.
+ - Trade off between how many CPUs and cost.
+- [Exclude this operation](#excluding-slow-operations) from the DAST API test. While this is the simplest, it has the downside of a gap in security test coverage.
+- [Exclude the operation from feature branch DAST API tests, but include it in the default branch test](#excluding-operations-in-feature-branches-but-not-default-branch).
+- [Split up the DAST API testing into multiple jobs](#splitting-a-test-into-multiple-jobs).
+
+The likely solution is to use a combination of these solutions to reach an acceptable test time, assuming your team's requirements are in the 5-7 minute range.
+
+### Addressing performance issues
+
+The following sections document various options for addressing performance issues for DAST API:
+
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding slow operations](#excluding-slow-operations)
+- [Splitting a test into multiple jobs](#splitting-a-test-into-multiple-jobs)
+- [Excluding operations in feature branches, but not default branch](#excluding-operations-in-feature-branches-but-not-default-branch)
+
+#### Using a multi-CPU Runner
+
+One of the easiest performance boosts can be achieved using a multi-CPU runner with DAST API. This table shows statistics collected during benchmarking of a Java Spring Boot REST API. In this benchmark, the target and DAST API share a single runner instance.
+
+| CPU Count | Request per Second |
+|----------------------|--------------------|
+| 1 CPU (Shared Runner)| 75 |
+| 4 CPU | 255 |
+| 8 CPU | 400 |
+
+As we can see from this table, increasing the CPU count of the runner can have a large impact on testing speed/performance.
+
+To use a multi-CPU typically requires deploying a self-managed GitLab Runner onto a multi-CPU machine or cloud compute instance.
+
+When multiple types of GitLab Runners are available for use, the various instances are commonly set up with tags that can be used in the job definition to select a type of runner.
+
+Here is an example job definition for DAST API that adds a `tags` section with the tag `multi-cpu`. The job automatically extends the job definition included through the DAST API template.
+
+```yaml
+dast_api:
+ tags:
+ - multi-cpu
+```
+
+To verify that DAST API can detect multiple CPUs in the runner, download the `gl-api-security-scanner.log` file from a completed job's artifacts. Search the file for the string `Starting work item processor` and inspect the reported max DOP (degree of parallelism). The max DOP should be greater than or equal to the number of CPUs assigned to the runner. The value is never lower than 2, even on single CPU runners, unless forced through a configuration variable. If the value reported is less than the number of CPUs assigned to the runner, then something is wrong with the runner deployment. If unable to identify the problem, open a ticket with support to assist.
+
+Example log entry:
+
+`17:00:01.084 [INF] <Peach.Web.Core.Services.WebRunnerMachine> Starting work item processor with 2 max DOP`
+
+#### Excluding slow operations
+
+In the case of one or two slow operations, the team might decide to skip testing the operations. Excluding the operation is done using the `DAST_API_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `DAST_API_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`.
+
+To verify the operation is excluded, run the DAST API job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+dast_api:
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/large_response_json
+```
+
+Excluding operations from testing could allow some vulnerabilities to go undetected.
+{: .alert .alert-warning}
+
+#### Splitting a test into multiple jobs
+
+Splitting a test into multiple jobs is supported by DAST API through the use of [`DAST_API_EXCLUDE_PATHS`](#exclude-paths) and [`DAST_API_EXCLUDE_URLS`](#exclude-urls). When splitting a test up, a good pattern is to disable the `dast_api` job and replace it with two jobs with identifying names. In this example we have two jobs, each job is testing a version of the API, so our names reflect that. However, this technique can be applied to any situation, not just with versions of an API.
+
+The rules we are using in the `dast_api_v1` and `dast_api_v2` jobs are copied from the [DAST API template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST-API.gitlab-ci.yml).
+
+```yaml
+# Disable the main dast_api job
+dast_api:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+dast_api_v1:
+ extends: dast_api
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/v1/**
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+
+dast_api_v2:
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/v2/**
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+```
+
+#### Excluding operations in feature branches, but not default branch
+
+In the case of one or two slow operations, the team might decide to skip testing the operations, or exclude them from feature branch tests, but include them for default branch tests. Excluding the operation is done using the `DAST_API_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `DAST_API_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`. Our configuration disables the main `dast_api` job and creates two new jobs `dast_api_main` and `dast_api_branch`. The `dast_api_branch` is set up to exclude the long operation and only run on non-default branches (e.g. feature branches). The `dast_api_main` branch is set up to only execute on the default branch (`main` in this example). The `dast_api_branch` jobs run faster, allowing for quick development cycles, while the `dast_api_main` job which only runs on default branch builds, takes longer to run.
+
+To verify the operation is excluded, run the DAST API job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+# Disable the main job so we can create two jobs with
+# different names
+dast_api:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+# DAST API for feature branch work, excludes /api/large_response_json
+dast_api_branch:
+ extends: dast_api
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/large_response_json
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ when: never
+ - if: $CI_COMMIT_BRANCH
+
+# DAST API for default branch (main in our case)
+# Includes the long running operations
+dast_api_main:
+ extends: dast_api
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+```
+
## Troubleshooting
-### `Error waiting for API Security 'http://127.0.0.1:5000' to become available`
+### DAST API job times out after N hours
+
+The top two reasons for the DAST API job timing out are slow operations (> 1 second) and using a single-CPU runner for DAST API (GitLab shared runners are single-CPU). Before you can diagnose the problem further, the job must complete so the output can be analyzed. We recommend to start with a multi-CPU runner first, then exclude portions of your API operations until the job completes and the output can be further reviewed.
+
+See the following documentation sections for assistance:
+
+- [Performance tuning and testing speed](#performance-tuning-and-testing-speed)
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding operations by path](#exclude-paths)
+- [Excluding slow operations](#excluding-slow-operations)
+
+### DAST API job takes too long to complete
+
+See [Performance Tuning and Testing Speed](#performance-tuning-and-testing-speed)
+
+### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the DAST API analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the DAST API analyzer.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index a3c6c46b081..54c1927e23b 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -501,11 +501,11 @@ From GitLab 14.8 the `gemnasium` analyzer scans supported JavaScript projects fo
#### Go
-When scanning a Go project, gemnasium invokes a builder and attempts to generate a [build list](https://go.dev/ref/mod#glos-build-list) using
-[Minimal Version Selection](https://go.dev/ref/mod#glos-minimal-version-selection). If a non-fatal error is encountered, the build process signals
-that the execution should proceed and falls back to parsing the available `go.sum` file.
+Multiple files are supported. When a `go.mod` file is detected, the analyzer attempts to generate a [build list](https://go.dev/ref/mod#glos-build-list) using
+[Minimal Version Selection](https://go.dev/ref/mod#glos-minimal-version-selection). If a non-fatal error is encountered, the analyzer falls back to parsing the
+available `go.sum` file. The process is repeated for every detected `go.mod` and `go.sum` file.
-#### PHP, Go, C, C++, .NET, C&#35;, Ruby, JavaScript
+#### PHP, C, C++, .NET, C&#35;, Ruby, JavaScript
The analyzer for these languages supports multiple lockfiles.
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 9839828a5b4..07b19742c2e 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -96,7 +96,7 @@ module API
end
params :optional_update_params_ce do
- optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Skip older deployment jobs that are still pending'
+ optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Prevent older deployment jobs that are still pending'
optional :ci_allow_fork_pipelines_to_run_in_parent_project, type: Boolean, desc: 'Allow fork merge request pipelines to run in parent project'
optional :ci_separated_caches, type: Boolean, desc: 'Enable or disable separated caches based on branch protection.'
optional :restrict_user_defined_variables, type: Boolean, desc: 'Restrict use of user-defined variables when triggering a pipeline'
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index 8b9380b332e..1616b143ceb 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -44,7 +44,8 @@ module API
requires :name, type: String, desc: 'The name of the link'
requires :url, type: String, desc: 'The URL of the link'
optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ optional :link_type, type: String, values: %w[other runbook image package], default: 'other',
+ desc: 'The link type, one of: "runbook", "image", "package" or "other"'
end
route_setting :authentication, job_token_allowed: true
post 'links' do
@@ -82,7 +83,8 @@ module API
optional :name, type: String, desc: 'The name of the link'
optional :url, type: String, desc: 'The URL of the link'
optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type'
+ optional :link_type, type: String, values: %w[other runbook image package], default: 'other',
+ desc: 'The link type, one of: "runbook", "image", "package" or "other"'
at_least_one_of :name, :url
end
route_setting :authentication, job_token_allowed: true
diff --git a/lib/gitlab/patch/sidekiq_cron_poller.rb b/lib/gitlab/patch/sidekiq_cron_poller.rb
new file mode 100644
index 00000000000..87d6c8f324e
--- /dev/null
+++ b/lib/gitlab/patch/sidekiq_cron_poller.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# Patch to address https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1932
+# It restores the behavior of `poll_internal_average` to the one from Sidekiq 6.4.2
+# (see https://github.com/mperham/sidekiq/blob/v6.4.2/lib/sidekiq/scheduled.rb#L173-L175)
+require 'sidekiq/version'
+require 'sidekiq/cron/version'
+
+if Gem::Version.new(Sidekiq::VERSION) != Gem::Version.new('6.4.2')
+ raise 'New version of sidekiq detected, please remove or update this patch'
+end
+
+if Gem::Version.new(Sidekiq::Cron::VERSION) != Gem::Version.new('1.8.0')
+ raise 'New version of sidekiq-cron detected, please remove or update this patch'
+end
+
+module Gitlab
+ module Patch
+ module SidekiqCronPoller
+ def poll_interval_average
+ # Note: This diverges from the Sidekiq implementation in 6.4.2 to address a bug where the poll interval wouldn't
+ # scale properly when the process count changes, and to take into account the `cron_poll_interval` setting. See
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99030#note_1117078517 for more details
+ Sidekiq.options[:cron_poll_interval] || Sidekiq.options[:poll_interval_average] || scaled_poll_interval
+ end
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 545a2ca4855..a31b04ec47b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -30719,6 +30719,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -34760,9 +34763,6 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
-
msgid "Runners|Administrator"
msgstr ""
@@ -35240,12 +35240,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -37801,9 +37795,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -45493,7 +45484,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
index ab9af872753..a1060c1d890 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
index 6eb3060fb59..0a82c5d6736 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
index 708dd7aa8af..11328c2f517 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
index 97d461c5113..eb7d3da0f97 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
index 9d534e9ea6b..dd297f47975 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
index 413c530116c..8f99644bd24 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Cherry picking from a merge request' do
+ describe 'Cherry picking from a merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
index d6e9c1a13df..111adf32a69 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Cherry picking a commit' do
+ describe 'Cherry picking a commit', product_group: :code_review do
let(:file_name) { "secret_file.md" }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
index 10d7e0b071f..509714fb5a4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Create a new merge request from the event notification after a push' do
+ describe 'Create a new merge request from the event notification after a push', product_group: :code_review do
let(:branch_name) { "merge-request-test-#{SecureRandom.hex(8)}" }
let(:title) { "Merge from push event notification test #{SecureRandom.hex(8)}" }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
index 25dec82b74c..630be7763f3 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Create a new merge request' do
+ describe 'Create a new merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
index d975e18e962..1ce9430290f 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
describe 'Merge request custom templates' do
let(:template_name) { 'custom_merge_request_template' }
let(:template_content) { 'This is a custom merge request template test' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
index 109cf7b73c3..d27ec32fdda 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request creation from fork' do
+ describe 'Merge request creation from fork', product_group: :code_review do
let(:merge_request) do
Resource::MergeRequestFromFork.fabricate_via_browser_ui! do |merge_request|
merge_request.fork_branch = 'feature-branch'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
index ac53357a86f..257021b158a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :runner do
+ RSpec.describe 'Create', :runner, product_group: :code_review do
describe 'Merge requests' do
shared_examples 'merge when pipeline succeeds' do |repeat: 1|
let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
index c7296b6eea2..330cae575e4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request rebasing' do
+ describe 'Merge request rebasing', product_group: :code_review do
let(:merge_request) { Resource::MergeRequest.fabricate_via_api! }
before do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
index 205ff12ff03..a79c56bd051 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
describe 'Reverting a commit' do
let(:file_name) { "secret_file.md" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
index 948aedf5aae..82e2136cd22 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merged merge request' do
+ describe 'Merged merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'revert'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
index fa129f39a4c..a127b846eb9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request squashing' do
+ describe 'Merge request squashing', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = "squash-before-merge"
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
index b20d0929e9c..829b7bab829 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
context 'Add batch suggestions to a Merge Request' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
index aa637ac4d55..433ef90d9aa 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- context 'Add suggestions to a Merge Request' do
+ context 'Add suggestions to a Merge Request', product_group: :code_review do
let(:commit_message) { 'Applying suggested change for testing purposes.' }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index 18aa6bfe78a..a969b48f0fc 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Download merge request patch and diff' do
+ describe 'Download merge request patch and diff', product_group: :code_review do
let(:merge_request) do
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.title = 'This is a merge request'
diff --git a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
index 8cfe11c9040..ef1ed9bee51 100644
--- a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Design management index page designs renders error 1`] = `
<div
- class="gl-mt-5"
+ class="gl-mt-4"
data-testid="designs-root"
>
<!---->
@@ -34,7 +34,7 @@ exports[`Design management index page designs renders error 1`] = `
exports[`Design management index page designs renders loading icon 1`] = `
<div
- class="gl-mt-5"
+ class="gl-mt-4"
data-testid="designs-root"
>
<!---->
diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
index 7afde3bdc96..d9587380d7c 100644
--- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
+++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
@@ -17,7 +17,6 @@ import { updateHistory } from '~/lib/utils/url_utility';
import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
import { createLocalState } from '~/runner/graphql/list/local_state';
import AdminRunnersApp from '~/runner/admin_runners/admin_runners_app.vue';
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue';
import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
import RunnerList from '~/runner/components/runner_list.vue';
@@ -84,7 +83,6 @@ describe('AdminRunnersApp', () => {
let wrapper;
let showToast;
- const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner);
const findRunnerStats = () => wrapper.findComponent(RunnerStats);
const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
@@ -142,11 +140,6 @@ describe('AdminRunnersApp', () => {
wrapper.destroy();
});
- it('shows the feedback banner', () => {
- createComponent();
- expect(findRunnerStackedLayoutBanner().exists()).toBe(true);
- });
-
it('shows the runner setup instructions', () => {
createComponent();
diff --git a/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js b/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js
deleted file mode 100644
index d1f04f0ee37..00000000000
--- a/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { nextTick } from 'vue';
-import { GlBanner } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-
-describe('RunnerStackedLayoutBanner', () => {
- let wrapper;
-
- const findBanner = () => wrapper.findComponent(GlBanner);
- const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
-
- const createComponent = ({ ...options } = {}, mountFn = shallowMount) => {
- wrapper = mountFn(RunnerStackedLayoutBanner, {
- ...options,
- });
- };
-
- it('Displays a banner', () => {
- createComponent();
-
- expect(findBanner().props()).toMatchObject({
- svgPath: expect.stringContaining('data:image/svg+xml;utf8,'),
- title: expect.any(String),
- buttonText: expect.any(String),
- buttonLink: expect.stringContaining('https://gitlab.com/gitlab-org/gitlab/-/issues/'),
- });
- expect(findLocalStorageSync().exists()).toBe(true);
- });
-
- it('Does not display a banner when dismissed', async () => {
- createComponent();
-
- findLocalStorageSync().vm.$emit('input', true);
-
- await nextTick();
-
- expect(findBanner().exists()).toBe(false);
- expect(findLocalStorageSync().exists()).toBe(true); // continues syncing after removal
- });
-});
diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js
index 7482926e151..06487d8bba2 100644
--- a/spec/frontend/runner/group_runners/group_runners_app_spec.js
+++ b/spec/frontend/runner/group_runners/group_runners_app_spec.js
@@ -16,7 +16,6 @@ import { updateHistory } from '~/lib/utils/url_utility';
import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
import { createLocalState } from '~/runner/graphql/list/local_state';
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue';
import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
import RunnerList from '~/runner/components/runner_list.vue';
@@ -83,7 +82,6 @@ jest.mock('~/lib/utils/url_utility', () => ({
describe('GroupRunnersApp', () => {
let wrapper;
- const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner);
const findRunnerStats = () => wrapper.findComponent(RunnerStats);
const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
@@ -142,11 +140,6 @@ describe('GroupRunnersApp', () => {
wrapper.destroy();
});
- it('shows the feedback banner', () => {
- createComponent();
- expect(findRunnerStackedLayoutBanner().exists()).toBe(true);
- });
-
it('shows the runner tabs with a runner count for each type', async () => {
await createComponent({ mountFn: mountExtended });
diff --git a/spec/helpers/json_helper_spec.rb b/spec/helpers/json_helper_spec.rb
new file mode 100644
index 00000000000..b9dfabb1b23
--- /dev/null
+++ b/spec/helpers/json_helper_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe JsonHelper do
+ let(:hash) { { "foo" => "bar" } }
+ let(:json) { '{"foo":"bar"}' }
+
+ describe ".json_generate" do
+ subject { helper.json_generate(hash) }
+
+ it "generates JSON" do
+ expect(subject).to eq(json)
+ end
+
+ it "calls the Gitlab::Json class" do
+ expect(Gitlab::Json).to receive(:generate).with(hash)
+
+ subject
+ end
+ end
+
+ describe ".json_parse" do
+ subject { helper.json_parse(json) }
+
+ it "parses JSON" do
+ expect(subject).to eq(hash)
+ end
+
+ it "calls the Gitlab::Json class" do
+ expect(Gitlab::Json).to receive(:parse).with(json)
+
+ subject
+ end
+ end
+end