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>2023-08-15 06:10:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-15 06:10:52 +0300
commitb291dca0e5062e05572e0f106ea499b47d908d35 (patch)
tree158d3cdae42b2d5a55e9c90193cdabe6ec06f60d
parent3677bb721df3c9ae898b6665a8b2ae0b95a9d62f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/boards/components/board_app.vue22
-rw-r--r--app/assets/javascripts/boards/components/board_filtered_search.vue3
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue29
-rw-r--r--app/assets/javascripts/boards/index.js2
-rw-r--r--app/assets/javascripts/graphql_shared/issuable_client.js10
-rw-r--r--app/finders/autocomplete/routes_finder.rb1
-rw-r--r--app/graphql/mutations/ci/pipeline_trigger/base.rb18
-rw-r--r--app/graphql/mutations/ci/pipeline_trigger/update.rb32
-rw-r--r--app/graphql/types/mutation_type.rb1
-rw-r--r--app/models/concerns/routable.rb4
-rw-r--r--app/models/project.rb2
-rw-r--r--app/services/merge_requests/create_ref_service.rb2
-rw-r--r--app/views/groups/edit.html.haml4
-rw-r--r--app/views/groups/settings/_advanced.html.haml47
-rw-r--r--app/views/groups/settings/_export.html.haml67
-rw-r--r--app/views/groups/settings/_permanent_deletion.html.haml20
-rw-r--r--app/views/groups/settings/_remove_button.html.haml2
-rw-r--r--app/views/groups/settings/_transfer.html.haml39
-rw-r--r--db/docs/projects.yml2
-rw-r--r--db/docs/upcoming_reconciliations.yml2
-rw-r--r--doc/administration/compliance.md2
-rw-r--r--doc/api/graphql/reference/index.md30
-rw-r--r--doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.pngbin0 -> 129675 bytes
-rw-r--r--doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md372
-rw-r--r--doc/ci/index.md2
-rw-r--r--doc/ci/testing/index.md2
-rw-r--r--doc/ci/yaml/artifacts_reports.md13
-rw-r--r--doc/development/fips_compliance.md1
-rw-r--r--doc/development/go_guide/index.md3
-rw-r--r--doc/development/integrations/secure.md12
-rw-r--r--doc/development/sec/analyzer_development_guide.md2
-rw-r--r--doc/install/openshift_and_gitlab/index.md3
-rw-r--r--doc/raketasks/index.md2
-rw-r--r--doc/raketasks/spdx.md2
-rw-r--r--doc/user/application_security/configuration/index.md3
-rw-r--r--doc/user/application_security/dast/proxy-based.md11
-rw-r--r--doc/user/application_security/dependency_list/index.md13
-rw-r--r--doc/user/application_security/index.md1
-rw-r--r--doc/user/application_security/offline_deployments/index.md2
-rw-r--r--doc/user/compliance/license_compliance/index.md843
-rw-r--r--doc/user/compliance/license_list.md6
-rw-r--r--doc/user/permissions.md8
-rw-r--r--doc/user/project/merge_requests/index.md2
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb1
-rw-r--r--lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects.rb8
-rw-r--r--lib/gitlab/background_migration/populate_projects_star_count.rb31
-rw-r--r--lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb3
-rw-r--r--qa/lib/gitlab/page/trials/new.rb4
-rw-r--r--qa/lib/gitlab/page/trials/new.stub.rb241
-rw-r--r--qa/lib/gitlab/page/trials/select.rb1
-rw-r--r--qa/lib/gitlab/page/trials/select.stub.rb129
-rw-r--r--qa/qa/flow/trial.rb8
-rw-r--r--spec/lib/gitlab/database/gitlab_schema_spec.rb2
-rw-r--r--spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb4
-rw-r--r--spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb6
-rw-r--r--spec/models/concerns/cross_database_modification_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_trigger/update_spec.rb71
-rw-r--r--spec/services/merge_requests/create_ref_service_spec.rb12
58 files changed, 1154 insertions, 1013 deletions
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue
index 43b33acc045..37128fcde33 100644
--- a/app/assets/javascripts/boards/components/board_app.vue
+++ b/app/assets/javascripts/boards/components/board_app.vue
@@ -91,7 +91,6 @@ export default {
computed: {
...mapGetters(['isSidebarOpen']),
listQueryVariables() {
- if (this.filterParams.groupBy) delete this.filterParams.groupBy;
return {
...(this.isIssueBoard && {
isGroup: this.isGroupBoard,
@@ -99,7 +98,7 @@ export default {
}),
fullPath: this.fullPath,
boardId: this.boardId,
- filters: this.filterParams,
+ filters: this.formattedFilterParams,
};
},
isSwimlanesOn() {
@@ -114,6 +113,15 @@ export default {
activeList() {
return this.activeListId ? this.boardListsApollo[this.activeListId] : undefined;
},
+ formattedFilterParams() {
+ if (this.filterParams.groupBy) delete this.filterParams.groupBy;
+ return filterVariables({
+ filters: this.filterParams,
+ issuableType: this.issuableType,
+ filterInfo: FiltersInfo,
+ filterFields: FilterFields,
+ });
+ },
},
created() {
window.addEventListener('popstate', refreshCurrentPage);
@@ -136,13 +144,7 @@ export default {
},
setFilters(filters) {
const filterParams = { ...filters };
- if (filterParams.groupBy) delete filterParams.groupBy;
- this.filterParams = filterVariables({
- filters: filterParams,
- issuableType: this.issuableType,
- filterInfo: FiltersInfo,
- filterFields: FilterFields,
- });
+ this.filterParams = filterParams;
},
},
};
@@ -163,7 +165,7 @@ export default {
:board-id="boardId"
:add-column-form-visible="addColumnFormVisible"
:is-swimlanes-on="isSwimlanesOn"
- :filter-params="filterParams"
+ :filter-params="formattedFilterParams"
:board-lists-apollo="boardListsApollo"
:apollo-error="error"
:list-query-variables="listQueryVariables"
diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue
index b5d3613ca27..b37a973c976 100644
--- a/app/assets/javascripts/boards/components/board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/board_filtered_search.vue
@@ -342,7 +342,8 @@ export default {
);
},
formattedFilterParams() {
- const filtersCopy = { ...this.filterParams };
+ const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true });
+ const filtersCopy = convertObjectPropsToCamelCase(rawFilterParams, {});
if (this.filterParams?.iterationId) {
filtersCopy.iterationId = convertToGraphQLId(
TYPENAME_ITERATION,
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index e0a05480c70..6dc90075390 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -11,6 +11,7 @@ import {
import { mapActions, mapState } from 'vuex';
import { isListDraggable } from '~/boards/boards_util';
import { isScopedLabel, parseBoolean } from '~/lib/utils/common_utils';
+import { fetchPolicies } from '~/lib/graphql';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { n__, s__ } from '~/locale';
import sidebarEventHub from '~/sidebar/event_hub';
@@ -18,7 +19,6 @@ import Tracking from '~/tracking';
import { TYPE_ISSUE } from '~/issues/constants';
import { formatDate } from '~/lib/utils/datetime_utility';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
import setActiveBoardItemMutation from 'ee_else_ce/boards/graphql/client/set_active_board_item.mutation.graphql';
import AccessorUtilities from '~/lib/utils/accessor';
import {
@@ -28,6 +28,7 @@ import {
toggleFormEventPrefix,
updateListQueries,
toggleCollapsedMutations,
+ listsDeferredQuery,
} from 'ee_else_ce/boards/constants';
import eventHub from '../eventhub';
import { setError } from '../graphql/cache_updates';
@@ -188,8 +189,16 @@ export default {
userCanDrag() {
return !this.disabled && isListDraggable(this.list);
},
+ // due to the issues with cache-and-network, we need this hack to check if there is any data for the query in the cache.
+ // if we have cached data, we disregard the loading state
isLoading() {
- return this.$apollo.queries.boardList.loading;
+ return (
+ this.$apollo.queries.boardList.loading &&
+ !this.$apollo.provider.clients.defaultClient.readQuery({
+ query: listsDeferredQuery[this.issuableType].query,
+ variables: this.countQueryVariables,
+ })
+ );
},
totalWeight() {
return this.boardList?.totalWeight;
@@ -197,15 +206,21 @@ export default {
canShowTotalWeight() {
return this.weightFeatureAvailable && !this.isLoading;
},
+ countQueryVariables() {
+ return {
+ id: this.list.id,
+ filters: this.filterParams,
+ };
+ },
},
apollo: {
boardList: {
- query: listQuery,
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ query() {
+ return listsDeferredQuery[this.issuableType].query;
+ },
variables() {
- return {
- id: this.list.id,
- filters: this.filterParams,
- };
+ return this.countQueryVariables;
},
context: {
isSingleRequest: true,
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 67388284d31..a03ec9193ea 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -29,7 +29,7 @@ function mountBoardApp(el) {
const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true });
const initialFilterParams = {
- ...convertObjectPropsToCamelCase(rawFilterParams),
+ ...convertObjectPropsToCamelCase(rawFilterParams, {}),
};
const boardType = el.dataset.parent;
diff --git a/app/assets/javascripts/graphql_shared/issuable_client.js b/app/assets/javascripts/graphql_shared/issuable_client.js
index 08733bbe620..eb807bc7540 100644
--- a/app/assets/javascripts/graphql_shared/issuable_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_client.js
@@ -203,6 +203,16 @@ export const config = {
};
},
},
+ Query: {
+ fields: {
+ boardList: {
+ keyArgs: ['id'],
+ },
+ epicBoardList: {
+ keyArgs: ['id'],
+ },
+ },
+ },
}
: {}),
},
diff --git a/app/finders/autocomplete/routes_finder.rb b/app/finders/autocomplete/routes_finder.rb
index 8504d8cf678..ed807d3a295 100644
--- a/app/finders/autocomplete/routes_finder.rb
+++ b/app/finders/autocomplete/routes_finder.rb
@@ -19,6 +19,7 @@ module Autocomplete
.for_routable(routables)
.sort_by_path_length
.fuzzy_search(@search, [:path])
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
.limit(LIMIT) # rubocop: disable CodeReuse/ActiveRecord
end
diff --git a/app/graphql/mutations/ci/pipeline_trigger/base.rb b/app/graphql/mutations/ci/pipeline_trigger/base.rb
new file mode 100644
index 00000000000..23be70e7754
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_trigger/base.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module PipelineTrigger
+ class Base < BaseMutation
+ authorize :admin_build
+ authorize :admin_trigger
+
+ PipelineTriggerID = ::Types::GlobalIDType[::Ci::Trigger]
+
+ argument :id, PipelineTriggerID,
+ required: true,
+ description: 'ID of the pipeline trigger token to mutate.'
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/pipeline_trigger/update.rb b/app/graphql/mutations/ci/pipeline_trigger/update.rb
new file mode 100644
index 00000000000..fa68593eb09
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_trigger/update.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module PipelineTrigger
+ class Update < Base
+ graphql_name 'PipelineTriggerUpdate'
+
+ argument :description, GraphQL::Types::String,
+ required: true,
+ description: 'Description of the pipeline trigger token.'
+
+ field :pipeline_trigger, Types::Ci::PipelineTriggerType,
+ null: true,
+ description: 'Mutated pipeline trigger token.'
+
+ def resolve(id:, description:)
+ trigger = authorized_find!(id: id)
+
+ trigger.description = description
+
+ trigger.save
+
+ {
+ pipeline_trigger: trigger,
+ errors: trigger.errors.full_messages
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index a9fce9e212d..4df7a76e233 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -144,6 +144,7 @@ module Types
mount_mutation Mutations::Ci::PipelineSchedule::Create
mount_mutation Mutations::Ci::PipelineSchedule::Update
mount_mutation Mutations::Ci::PipelineTrigger::Create, alpha: { milestone: '16.3' }
+ mount_mutation Mutations::Ci::PipelineTrigger::Update, alpha: { milestone: '16.3' }
mount_mutation Mutations::Ci::ProjectCiCdSettingsUpdate
mount_mutation Mutations::Ci::Job::ArtifactsDestroy
mount_mutation Mutations::Ci::Job::Play
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 2f77a7947ca..f2badfe48dd 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -48,7 +48,9 @@ module Routable
validates :route, presence: true, unless: -> { is_a?(Namespaces::ProjectNamespace) }
- scope :with_route, -> { includes(:route) }
+ scope :with_route, -> do
+ includes(:route).allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
+ end
after_validation :set_path_errors
diff --git a/app/models/project.rb b/app/models/project.rb
index 5c0a30503f7..d3e2db2bb2a 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -710,6 +710,7 @@ class Project < ApplicationRecord
# includes(:route) which we use in ProjectsFinder.
joins("INNER JOIN routes rs ON rs.source_id = projects.id AND rs.source_type = 'Project'")
.where('rs.path LIKE ?', "#{sanitize_sql_like(path)}/%")
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
end
scope :with_feature_enabled, ->(feature) {
@@ -939,6 +940,7 @@ class Project < ApplicationRecord
if include_namespace
joins(:route).fuzzy_search(query, [Route.arel_table[:path], Route.arel_table[:name], :description],
use_minimum_char_limit: use_minimum_char_limit)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
else
fuzzy_search(query, [:path, :name, :description], use_minimum_char_limit: use_minimum_char_limit)
end
diff --git a/app/services/merge_requests/create_ref_service.rb b/app/services/merge_requests/create_ref_service.rb
index 7aa27e57405..e0f10183bac 100644
--- a/app/services/merge_requests/create_ref_service.rb
+++ b/app/services/merge_requests/create_ref_service.rb
@@ -88,7 +88,7 @@ module MergeRequests
def maybe_merge!(commit_sha, source_sha, expected_old_oid)
unless target_project.merge_requests_ff_only_enabled
- source_sha = safe_gitaly_operation do
+ commit_sha = safe_gitaly_operation do
repository.merge_to_ref(
current_user,
source_sha: source_sha,
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 13aedd6e4e0..1c256bd57c5 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -47,6 +47,7 @@
= render_if_exists 'groups/compliance_frameworks', expanded: expanded
= render_if_exists 'groups/custom_project_templates_setting'
= render_if_exists 'groups/templates_setting', expanded: expanded
+= render_if_exists 'shared/groups/max_pages_size_setting'
%section.settings.gs-advanced.no-animate#js-advanced-settings{ class: ('expanded' if expanded), data: { qa_selector: 'advanced_settings_content' } }
.settings-header
@@ -58,6 +59,3 @@
= _('Perform advanced options such as changing path, transferring, exporting, or removing the group.')
.settings-content
= render 'groups/settings/advanced'
-
-= render_if_exists 'shared/groups/max_pages_size_setting'
-
diff --git a/app/views/groups/settings/_advanced.html.haml b/app/views/groups/settings/_advanced.html.haml
index d92a6b08b60..45ee6ea6ad7 100644
--- a/app/views/groups/settings/_advanced.html.haml
+++ b/app/views/groups/settings/_advanced.html.haml
@@ -1,29 +1,32 @@
- remove_form_id = 'js-remove-group-form'
= render 'groups/settings/export', group: @group
-.sub-section
- %h4.warning-title= s_('GroupSettings|Change group URL')
- = gitlab_ui_form_for @group, html: { multipart: true, class: 'gl-show-field-errors' }, authenticity_token: true do |f|
- = form_errors(@group)
- .form-group
- %p
- = s_("GroupSettings|Changing a group's URL can have unintended side effects.")
- = link_to _('Learn more.'), help_page_path('user/group/manage', anchor: 'change-a-groups-path'), target: '_blank', rel: 'noopener noreferrer'
+= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c|
+ - c.with_header do
+ .gl-new-card-title-wrapper
+ %h4.gl-new-card-title.warning-title= s_('GroupSettings|Change group URL')
+ %p.gl-new-card-description
+ = s_("GroupSettings|Changing a group's URL can have unintended side effects.")
+ = link_to _('Learn more.'), help_page_path('user/group/manage', anchor: 'change-a-groups-path'), target: '_blank', rel: 'noopener noreferrer'
- .input-group.gl-field-error-anchor
- .group-root-path.input-group-prepend.has-tooltip{ title: group_path(@group), :'data-placement' => 'bottom' }
- .input-group-text
- %span>= root_url
- - if @group.parent
- %strong= @group.parent.full_path + '/'
- = f.hidden_field :parent_id
- = f.text_field :path, placeholder: 'open-source', class: 'form-control',
- autofocus: local_assigns[:autofocus] || false, required: true,
- pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
- title: group_url_error_message,
- maxlength: ::Namespace::URL_MAX_LENGTH,
- "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
- = f.submit s_('GroupSettings|Change group URL'), class: 'btn-danger', pajamas_button: true
+ - c.with_body do
+ = gitlab_ui_form_for @group, html: { multipart: true, class: 'gl-show-field-errors' }, authenticity_token: true do |f|
+ = form_errors(@group)
+ .form-group
+ .input-group.gl-field-error-anchor
+ .group-root-path.input-group-prepend.has-tooltip{ title: group_path(@group), :'data-placement' => 'bottom' }
+ .input-group-text
+ %span>= root_url
+ - if @group.parent
+ %strong= @group.parent.full_path + '/'
+ = f.hidden_field :parent_id
+ = f.text_field :path, placeholder: 'open-source', class: 'form-control',
+ autofocus: local_assigns[:autofocus] || false, required: true,
+ pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
+ title: group_url_error_message,
+ maxlength: ::Namespace::URL_MAX_LENGTH,
+ "data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
+ = f.submit s_('GroupSettings|Change group URL'), class: 'btn-danger', pajamas_button: true
= render 'groups/settings/transfer', group: @group
= render 'groups/settings/remove', group: @group, remove_form_id: remove_form_id
diff --git a/app/views/groups/settings/_export.html.haml b/app/views/groups/settings/_export.html.haml
index 1e80c1846a4..8eb9f8fc5f1 100644
--- a/app/views/groups/settings/_export.html.haml
+++ b/app/views/groups/settings/_export.html.haml
@@ -1,33 +1,38 @@
- group = local_assigns.fetch(:group)
-.sub-section
- %h4= s_('GroupSettings|Export group')
- %p= _('Export this group with all related data.')
- = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c|
- - c.with_body do
- - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') }
- - docs_link_end = '</a>'.html_safe
- = s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
- %p
- - export_information = _('After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance.') % { strong_text_start: '<strong>'.html_safe, strong_text_end: '</strong>'.html_safe}
- = export_information.html_safe
- = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
- - c.with_body do
- %p.gl-mb-0
- %p= _('The following items will be exported:')
- %ul
- - group_export_descriptions.each do |description|
- %li= description
- %p= _('The following items will NOT be exported:')
- %ul
- %li= _('Projects')
- %li= _('Runner tokens')
- %li= _('SAML discovery tokens')
- - if group.export_file_exists?
- = render Pajamas::ButtonComponent.new(href: download_export_group_path(group), button_options: { rel: 'nofollow', data: { method: :get, qa_selector: 'download_export_link' } }) do
- = _('Download export')
- = render Pajamas::ButtonComponent.new(href: export_group_path(group), button_options: { data: { method: :post, qa_selector: 'regenerate_export_group_link' } }) do
- = _('Regenerate export')
- - else
- = render Pajamas::ButtonComponent.new(href: export_group_path(group), button_options: { data: { method: :post, qa_selector: 'export_group_link' } }) do
- = _('Export group')
+= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c|
+ - c.with_header do
+ .gl-new-card-title-wrapper
+ %h4.gl-new-card-title= s_('GroupSettings|Export group')
+ %p.gl-new-card-description
+ = _('Export this group with all related data.')
+
+ - c.with_body do
+ = render Pajamas::AlertComponent.new(variant: :warning, dismissible: false, alert_options: { class: 'gl-mb-4' }) do |c|
+ - c.with_body do
+ - docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('user/group/import/index', anchor: 'migrate-groups-by-direct-transfer-recommended') }
+ - docs_link_end = '</a>'.html_safe
+ = s_('GroupsNew|This feature is deprecated and replaced by group migration by direct transfer. %{docs_link_start}Learn more%{docs_link_end}.').html_safe % { docs_link_start: docs_link_start, docs_link_end: docs_link_end }
+ %p
+ - export_information = _('After the export is complete, download the data file from a notification email or from this page. You can then import the data file from the %{strong_text_start}Create new group%{strong_text_end} page of another GitLab instance.') % { strong_text_start: '<strong>'.html_safe, strong_text_end: '</strong>'.html_safe}
+ = export_information.html_safe
+ = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
+ - c.with_body do
+ %p.gl-mb-0
+ %p= _('The following items will be exported:')
+ %ul
+ - group_export_descriptions.each do |description|
+ %li= description
+ %p= _('The following items will NOT be exported:')
+ %ul
+ %li= _('Projects')
+ %li= _('Runner tokens')
+ %li= _('SAML discovery tokens')
+ - if group.export_file_exists?
+ = render Pajamas::ButtonComponent.new(href: download_export_group_path(group), button_options: { rel: 'nofollow', data: { method: :get, qa_selector: 'download_export_link' } }) do
+ = _('Download export')
+ = render Pajamas::ButtonComponent.new(href: export_group_path(group), button_options: { data: { method: :post, qa_selector: 'regenerate_export_group_link' } }) do
+ = _('Regenerate export')
+ - else
+ = render Pajamas::ButtonComponent.new(href: export_group_path(group), button_options: { data: { method: :post, qa_selector: 'export_group_link' } }) do
+ = _('Export group')
diff --git a/app/views/groups/settings/_permanent_deletion.html.haml b/app/views/groups/settings/_permanent_deletion.html.haml
index 152cdfc1411..ae440636294 100644
--- a/app/views/groups/settings/_permanent_deletion.html.haml
+++ b/app/views/groups/settings/_permanent_deletion.html.haml
@@ -1,11 +1,15 @@
- remove_form_id = local_assigns.fetch(:remove_form_id, nil)
-.sub-section
- %h4.danger-title= _('Remove group')
- = form_tag(group, method: :delete, id: remove_form_id) do
- %p
- = _('Removing this group also removes all child projects, including archived projects, and their resources.')
- %br
- %strong= _('Removed group can not be restored!')
+= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card' }, header_options: { class: 'gl-new-card-header' }, body_options: { class: 'gl-new-card-body gl-bg-red-50 gl-px-5 gl-py-4' }) do |c|
+ - c.with_header do
+ .gl-new-card-title-wrapper
+ %h4.gl-new-card-title.danger-title= _('Remove group')
- = render 'groups/settings/remove_button', group: group, remove_form_id: remove_form_id
+ - c.with_body do
+ = form_tag(group, method: :delete, id: remove_form_id) do
+ %p
+ = _('Removing this group also removes all child projects, including archived projects, and their resources.')
+ %br
+ %strong= _('Removed group can not be restored!')
+
+ = render 'groups/settings/remove_button', group: group, remove_form_id: remove_form_id
diff --git a/app/views/groups/settings/_remove_button.html.haml b/app/views/groups/settings/_remove_button.html.haml
index acf11fd8858..6085bcc149f 100644
--- a/app/views/groups/settings/_remove_button.html.haml
+++ b/app/views/groups/settings/_remove_button.html.haml
@@ -1,7 +1,7 @@
- remove_form_id = local_assigns.fetch(:remove_form_id, nil)
- if group.prevent_delete?
- = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5', data: { testid: 'group-has-linked-subscription-alert' }}) do |c|
+ = render Pajamas::AlertComponent.new(variant: :tip, dismissible: false, alert_options: { class: 'gl-mb-5', data: { testid: 'group-has-linked-subscription-alert' }}) do |c|
- c.with_body do
= html_escape(_("This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
diff --git a/app/views/groups/settings/_transfer.html.haml b/app/views/groups/settings/_transfer.html.haml
index 9ebe3a740b3..368e4a981bc 100644
--- a/app/views/groups/settings/_transfer.html.haml
+++ b/app/views/groups/settings/_transfer.html.haml
@@ -1,20 +1,25 @@
- form_id = "transfer-group-form"
- initial_data = { button_text: s_('GroupSettings|Transfer group'), group_full_path: @group.full_path, group_name: @group.name, group_id: @group.id, target_form_id: form_id, is_paid_group: group.paid?.to_s }
-.sub-section{ data: { qa_selector: 'transfer_group_content' } }
- %h4.warning-title= s_('GroupSettings|Transfer group')
- %p= _('Transfer group to another parent group.')
- = form_for group, url: transfer_group_path(group), method: :put, html: { id: form_id, class: 'js-group-transfer-form' } do |f|
- %ul
- - learn_more_link = help_page_url('user/project/repository/index', anchor: 'what-happens-when-a-repository-path-changes')
- - learn_more_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learn_more_link }
- - warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}") % { learn_more_link_start: learn_more_link_start, learn_more_link_end: '</a>'.html_safe }
- %li= warning_text.html_safe
- %li= s_('GroupSettings|You must have the Owner role in the target group')
- %li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
- %li= s_("GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
- - if group.paid?
- = render Pajamas::AlertComponent.new(dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
- - c.with_body do
- = html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
- .js-transfer-group-form{ data: initial_data }
+= render Pajamas::CardComponent.new(card_options: { class: 'gl-new-card', data: { qa_selector: 'transfer_group_content' } }, header_options: { class: 'gl-new-card-header gl-flex-direction-column' }, body_options: { class: 'gl-new-card-body gl-px-5 gl-py-4' }) do |c|
+ - c.with_header do
+ .gl-new-card-title-wrapper
+ %h4.gl-new-card-title.warning-title= s_('GroupSettings|Transfer group')
+ %p.gl-new-card-description
+ = _('Transfer group to another parent group.')
+
+ - c.with_body do
+ = form_for group, url: transfer_group_path(group), method: :put, html: { id: form_id, class: 'js-group-transfer-form' } do |f|
+ %ul
+ - learn_more_link = help_page_url('user/project/repository/index', anchor: 'what-happens-when-a-repository-path-changes')
+ - learn_more_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learn_more_link }
+ - warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended side effects. %{learn_more_link_start}Learn more.%{learn_more_link_end}") % { learn_more_link_start: learn_more_link_start, learn_more_link_end: '</a>'.html_safe }
+ %li= warning_text.html_safe
+ %li= s_('GroupSettings|You must have the Owner role in the target group')
+ %li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
+ %li= s_("GroupSettings|If the parent group's visibility is lower than the group's current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
+ - if group.paid?
+ = render Pajamas::AlertComponent.new(variant: :tip, dismissible: false, alert_options: { class: 'gl-mb-5' }) do |c|
+ - c.with_body do
+ = html_escape(_("This group can't be transferred because it is linked to a subscription. To transfer this group, %{linkStart}link the subscription%{linkEnd} with a different group.")) % { linkStart: "<a href=\"#{help_page_path('subscriptions/gitlab_com/index', anchor: 'change-the-linked-namespace')}\">".html_safe, linkEnd: '</a>'.html_safe }
+ .js-transfer-group-form{ data: initial_data }
diff --git a/db/docs/projects.yml b/db/docs/projects.yml
index 44ac68d891d..84c0aa3373f 100644
--- a/db/docs/projects.yml
+++ b/db/docs/projects.yml
@@ -7,4 +7,4 @@ feature_categories:
description: Stores project records
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9ba1224867665844b117fa037e1465bb706b3685
milestone: "<6.0"
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/db/docs/upcoming_reconciliations.yml b/db/docs/upcoming_reconciliations.yml
index 9e89bb1a57f..75254a524c5 100644
--- a/db/docs/upcoming_reconciliations.yml
+++ b/db/docs/upcoming_reconciliations.yml
@@ -7,4 +7,4 @@ feature_categories:
description: Stores the data needed to notify a user of an upcoming reconciliation
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63054
milestone: '14.0'
-gitlab_schema: gitlab_main
+gitlab_schema: gitlab_main_cell
diff --git a/doc/administration/compliance.md b/doc/administration/compliance.md
index 7889bc9f4ff..3f4d781e2a2 100644
--- a/doc/administration/compliance.md
+++ b/doc/administration/compliance.md
@@ -69,7 +69,7 @@ These features can also help with compliance requirements:
| [Enforce ToS acceptance](settings/terms.md) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Enforce your users accepting new terms of service by blocking GitLab traffic. |
| [External Status Checks](../user/project/merge_requests/status_checks.md) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Interface with third-party systems you already use during development to ensure you remain compliant. |
| [Generate reports on permission<br/>levels of users](../administration/admin_area.md#user-permission-export) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Generate a report listing all users' access permissions for groups and projects in the instance. |
-| [License compliance](../user/compliance/license_compliance/index.md) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Search dependencies for their licenses. This lets you determine if the licenses of your project's dependencies are compatible with your project's license. |
+| [License approval policies](../user/compliance/license_approval_policies.md) | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Search dependencies for their licenses. This lets you determine if the licenses of your project's dependencies are compatible with your project's license. |
| [Lock project membership to group](../user/group/access_and_permissions.md#prevent-members-from-being-added-to-projects-in-a-group) | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Group owners can prevent new members from being added to projects in a group. |
| [LDAP group sync](auth/ldap/ldap_synchronization.md#group-sync) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Automatically synchronize groups and manage SSH keys, permissions, and authentication, so you can focus on building your product, not configuring your tools. |
| [LDAP group sync filters](auth/ldap/ldap_synchronization.md#group-sync) | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Gives more flexibility to synchronize with LDAP based on filters, meaning you can leverage LDAP attributes to map GitLab permissions. |
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 5d54f1abf3b..d5920b2969e 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -5382,6 +5382,30 @@ Input type: `PipelineTriggerCreateInput`
| <a id="mutationpipelinetriggercreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationpipelinetriggercreatepipelinetrigger"></a>`pipelineTrigger` | [`PipelineTrigger`](#pipelinetrigger) | Mutated pipeline trigger token. |
+### `Mutation.pipelineTriggerUpdate`
+
+WARNING:
+**Introduced** in 16.3.
+This feature is an Experiment. It can be changed or removed at any time.
+
+Input type: `PipelineTriggerUpdateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationpipelinetriggerupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationpipelinetriggerupdatedescription"></a>`description` | [`String!`](#string) | Description of the pipeline trigger token. |
+| <a id="mutationpipelinetriggerupdateid"></a>`id` | [`CiTriggerID!`](#citriggerid) | ID of the pipeline trigger token to mutate. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationpipelinetriggerupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationpipelinetriggerupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationpipelinetriggerupdatepipelinetrigger"></a>`pipelineTrigger` | [`PipelineTrigger`](#pipelinetrigger) | Mutated pipeline trigger token. |
+
### `Mutation.projectCiCdSettingsUpdate`
Input type: `ProjectCiCdSettingsUpdateInput`
@@ -28224,6 +28248,12 @@ A `CiStageID` is a global ID. It is encoded as a string.
An example `CiStageID` is: `"gid://gitlab/Ci::Stage/1"`.
+### `CiTriggerID`
+
+A `CiTriggerID` is a global ID. It is encoded as a string.
+
+An example `CiTriggerID` is: `"gid://gitlab/Ci::Trigger/1"`.
+
### `ClustersAgentID`
A `ClustersAgentID` is a global ID. It is encoded as a string.
diff --git a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png
new file mode 100644
index 00000000000..0475a32e933
--- /dev/null
+++ b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/adaptive_concurrency_limit_flow.png
Binary files differ
diff --git a/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md
new file mode 100644
index 00000000000..89606cdc8fa
--- /dev/null
+++ b/doc/architecture/blueprints/gitaly_adaptive_concurrency_limit/index.md
@@ -0,0 +1,372 @@
+---
+status: proposed
+creation-date: "2023-05-30"
+authors: [ "@qmnguyen0711" ]
+approvers: [ ]
+owning-stage: "~devops::enablement"
+---
+
+# Gitaly Adaptive Concurrency Limit
+
+## Summary
+
+Gitaly, a Git server, needs to push back on its clients to reduce the risk of
+incidents. In the past, we introduced per-RPC concurrency limit and pack-objects
+concurrency limit. Both systems were successful, but the configurations were
+static, leading to some serious drawbacks. This blueprint proposes an adaptive
+concurrency limit system to overcome the drawbacks of static limits. The
+algorithm primarily uses the [Additive Increase/Multiplicative Decrease](https://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease)
+approach to gradually increase the limit during normal processing but quickly
+reduce it during an incident. The algorithm focuses on lack of resources and
+serious latency degradation as criteria for determining when Gitaly is in
+trouble.
+
+## Motivation
+
+To reduce the risk of incidents and protect itself, Gitaly should be able to
+push back on its clients when it determines some limits have been reached. In
+the [prior attempt](https://Gitlab.com/groups/Gitlab-org/-/epics/7891), we laid
+out some foundations for [backpressure](https://Gitlab.com/Gitlab-org/Gitaly/-/blob/382d1e57b2cf02763d3d65e31ff4d38f467b797c/doc/backpressure.md)
+by introducing two systems: per-RPC concurrency limits and pack-objects
+concurrency limits.
+
+Per-RPC concurrency limits allows us to configure a maximum amount of in-flight
+requests simultaneously. It scopes the limit by RPC and repository. Pack-objects
+concurrency limit restricts the concurrent Git data transfer request by IP. One
+note, the pack-objects concurrency limit is applied on cache misses, only. If
+this limit is exceeded, the request is either put in a queue or rejected if the
+queue is full. If the request remains in the queue for too long, it will also be
+rejected.
+
+Although both of them yielded promising results on GitLab.com, the
+configurations, especially the value of the concurrency limit, are static. There
+are some drawbacks to this:
+
+- It's tedious to maintain a sane value for the concurrency limit. Looking at
+this [production configuration](https://gitlab.com/gitlab-com/gl-infra/chef-repo/-/blob/db11ef95859e42d656bb116c817402635e946a32/roles/gprd-base-stor-gitaly-common.json),
+each limit is heavily calibrated based on clues from different sources. When the
+overall scene changes, we need to tweak them again.
+- Static limits are not good for all usage patterns. It's not feasible to pick a
+fit-them-all value. If the limit is too low, big users will be affected. If the
+value is too loose, the protection effect is lost.
+- A request may be rejected even though the server is idle as the rate is not
+necessarily an indicator of the load induced on the server.
+
+To overcome all of those drawbacks while keeping the benefits of concurrency
+limiting, one promising solution is to make the concurrency limit adaptive to
+the currently available processing capacity of the node. We call this proposed
+new mode "Adaptive Concurrency Limit".
+
+## Goals
+
+- Make Gitaly smarter in push-back traffic when it's under heavy load, thus enhancing the reliability and resiliency of Gitaly.
+- Minimize the occurrences of Gitaly saturation incidents.
+- Decrease the possibility of clients inaccurately reaching the concurrency limit, thereby reducing the ResourceExhausted error rate.
+- Facilitate seamless or fully automated calibration of the concurrency limit.
+
+## Non-goals
+
+- Increase the workload or complexity of the system for users or administrators. The adaptiveness proposed here aims for the opposite.
+
+## Proposal
+
+The proposed Adaptive Concurrency Limit algorithm primarily uses the Additive
+Increase/Multiplicative Decrease ([AIMD](https://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease))
+approach. This method involves gradually increasing the limit during normal
+process functioning but quickly reducing it when an issue (backoff event)
+occurs. There are various criteria for determining whether Gitaly is in trouble.
+In this proposal, we focus on two things:
+
+- Lack of resources, particularly memory and CPU, which are essential for
+handling Git processes.
+- Serious latency degradation.
+
+The proposed solution is heavily inspired by many materials about this subject
+shared by folks from other companies in the industry, especially the following:
+
+- TCP Congestion Control ([RFC-2581](https://www.rfc-editor.org/rfc/rfc2581), [RFC-5681](https://www.rfc-editor.org/rfc/rfc5681),
+[RFC-9293](https://www.rfc-editor.org/rfc/rfc9293.html#name-tcp-congestion-control), [Computer Networks: A Systems Approach](https://book.systemsapproach.org/congestion/tcpcc.html)).
+- Netflix adaptive concurrency limit ([blog post](https://tech.olx.com/load-shedding-with-nginx-using-adaptive-concurrency-control-part-1-e59c7da6a6df)
+and [implementation](https://github.com/Netflix/concurrency-limits))
+- Envoy Adaptive Concurrency
+([doc](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/adaptive_concurrency_filter#config-http-filters-adaptive-concurrency))
+
+We cannot blindly apply a solution without careful consideration and expect it
+to function flawlessly. The suggested approach considers Gitaly's specific
+constraints and distinguishing features, including cgroup utilization and
+upload-pack RPC, among others.
+
+The proposed solution does not aim to replace the existing [Gitaly concurrency
+limit][Gitlay-backpressure], but automatically tweak its parameters. This means
+that other aspects, such as queuing, in-queue timeout, queue length,
+partitioning, and scoping, will remain unchanged. The proposed solution only
+focuses on modifying the current **value** of the concurrency limit.
+
+## Design and implementation details
+
+### AIMD Algorithm
+
+The Adaptive Concurrency Limit algorithm primarily uses the Additive
+Increase/Multiplicative Decrease ([AIMD](https://en.wikipedia.org/wiki/Additive_increase/multiplicative_decrease))
+approach. This method involves gradually increasing the limit during normal
+process functioning but quickly reducing it when an issue occurs.
+
+During initialization, we configure the following parameters:
+
+- `initialLimit`: Concurrency limit to start with. This value is essentially
+equal to the current static concurrency limit.
+- `maxLimit`: Maximum concurrency limit.
+- `minLimit`: Minimum concurrency limit so that the process is considered as
+functioning. If it's equal to 0, it rejects all upcoming requests.
+- `backoffFactor`: how fast the limit decreases when a backoff event occurs (`0
+< backoff < 1`, default to `0.75`)
+
+When the Gitaly process starts, it sets `limit = initialLimit`, in which `limit`
+is the maximum in-flight requests allowed at a time.
+
+Periodically, maybe once per 15 seconds, the value of the `limit` is
+re-calibrated:
+
+- `limit = limit + 1` if there is no backoff event since the last
+calibration. The new limit cannot exceed `maxLimit`.
+- `limit = limit * backoffFactor` otherwise. The new limit cannot be lower than
+`minLimit`.
+
+When a process can no longer handle requests or will not be able to handle them
+soon, it is referred to as a back-off event. Ideally, we would love to see the
+efficient state as long as possible. It's the state where Gitaly is at its
+maximum capacity.
+
+![Adaptive Concurrency Limit Flow](adaptive_concurrency_limit_flow.png)
+
+Ideally, min/max values are safeguards that aren't ever meant to be hit during
+operation, even overload. In fact, hitting either probably means that something
+is wrong and the dynamic algorithms aren't working well enough.
+
+### How requests are handled
+
+The concurrency limit restricts the total number of in-flight requests (IFR) at
+a time.
+
+- When `IFR < limit`, Gitaly handles new requests without waiting. After an
+increment, Gitaly immediately handles the subsequent request in the queue, if
+any.
+- When `IFR = limit`, it means the limit is reached. Subsequent requests are
+queued, waiting for their turn. If the queue length reaches a configured limit,
+Gitaly rejects new requests immediately. When a request stays in the queue long
+enough, it is also automatically dropped by Gitaly.
+- When `IRF > limit`, it's appropriately a consequence of backoff events. It
+means Gitaly handles more requests than the newly appointed limits. In addition
+to queueing upcoming requests similarly to the above case, Gitaly may start
+load-shedding in-flight requests if this situation is not resolved long enough.
+
+At several points in time we have discussed whether we want to change queueing
+semantics. Right now we admit queued processes from the head of the queue
+(FIFO), whereas it was proposed several times that it might be preferable to
+admit processes from the back (LIFO).
+
+Regardless of the rejection reason, the client received a `ResourceExhausted`
+response code as a signal that they would back off and retry later. Since most
+direct clients of Gitaly are internal, especially GitLab Shell and Workhorse,
+the actual users received some friendly messages. Gitaly can attach
+[exponential pushback headers](https://Gitlab.com/Gitlab-org/Gitaly/-/issues/5023)
+to force internal clients to back off. However, that's a bit brutal and may lead
+to unexpected results. We can consider that later.
+
+### Backoff events
+
+Each system has its own set of signals, and in the case of Gitaly, there are two
+aspects to consider:
+
+- Lack of resources, particularly memory and CPU, which are essential for
+handling Git processes like `git-pack-objects(1)`. When these resources are limited
+or depleted, it doesn't make sense for Gitaly to accept more requests. Doing so
+would worsen the saturation, and Gitaly addresses this issue by applying cgroups
+extensively. The following section outlines how accounting can be carried out
+using cgroup.
+- Serious latency degradation. Gitaly offers various RPCs for different purposes
+besides serving Git data that is hard to reason about latencies. A significant
+overall latency decline is an indication that Gitaly should not accept more
+requests. Another section below describes how to assert latency degradation
+reasonably.
+
+Apart from the above signals, we can consider adding more signals in the future
+to make the system smarter. Some examples are Go garbage collector statistics,
+networking stats, file descriptors, etc. Some companies have clever tricks, such
+as [using time drifting to estimate CPU saturation](https://engineering.linkedin.com/blog/2022/hodor--detecting-and-addressing-overload-in-linkedin-microservic).
+
+#### Backoff events of Upload Pack RPCs
+
+Upload Pack RPCs and their siblings PackObjects RPC are unique to Gitaly. They
+are for the heaviest operations: transferring large volumes of Git data. Each
+operation may take minutes or even hours to finish. The time span of each
+operation depends on multiple factors, most notably the number of requested
+objects and the internet speed of clients.
+
+Thus, latency is a poor signal for determining the backoff event. This type of
+RPC should only depend on resource accounting at this stage.
+
+#### Backoff events of other RPCs
+
+As stated above, Gitaly serves various RPCs for different purposes. They can
+also vary in terms of acceptable latency as well as when to recognize latency
+degradation. Fortunately, the current RPC concurrency limits implementation
+scopes the configuration by RPC and repository individually. The latency signal
+makes sense in this setting.
+
+Apart from latency, resource usage also plays an important role. Hence, other
+RPCs should use both latency measurement and resource accounting signals.
+
+### Resource accounting with cgroup
+
+The issue with saturation is typically not caused by Gitaly, itself but rather by the
+spawned Git processes that handle most of the work. These processes are contained
+within a [cgroup](https://Gitlab.com/Gitlab-org/Gitaly/-/blob/382d1e57b2cf02763d3d65e31ff4d38f467b797c/doc/cgroups.md),
+and the algorithm for bucketing cgroup can be
+found [here](https://Gitlab.com/Gitlab-org/Gitaly/-/blob/382d1e57b2cf02763d3d65e31ff4d38f467b797c/internal/cgroups/v1_linux.go#L166-166).
+Typically, Gitaly selects the appropriate cgroup for a request based on the
+target repository. There is also a parent cgroup to which all repository-level
+cgroups belong to.
+
+Cgroup statistics are widely accessible. Gitaly can trivially fetch both
+resource capacity and current resource consumption via the following information
+in [cgroup control file](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt):
+
+- `memory.limit_in_bytes`
+- `memory.usage_in_bytes`
+- `cpu.cfs_period_us`
+- `cpu.cfs_quota_us`
+- `cpuacct.usage`
+
+Fetching those statistics may imply some overheads. It's not necessary to keep
+them updated in real-time. Thus, they can be processed periodically in the limit
+adjustment cycle.
+
+In the past, cgroup has been reliable in preventing spawned processes from
+exceeding their limits. It is generally safe to trust cgroup and allow processes
+to run without interference. However, when the limits set by cgroup are reached
+(at 100%), overloading can occur. This often leads to a range of issues such as
+an increase in page faults, slow system calls, memory allocation problems, and
+even out-of-memory kills. The consequences of such incidents are
+highlighted in
+[this example](https://Gitlab.com/Gitlab-com/gl-infra/production/-/issues/8713#note_1352403481). Inflight requests are significantly impacted, resulting in unacceptable delays,
+timeouts, and even cancellations.
+
+Besides, through various observations in the past, some Git processes such as
+`git-pack-objects(1)` build up memory over time. When a wave of `git-pull(1)`
+requests comes, the node can be easily filled up with various memory-hungry
+processes. It's much better to stop this accumulation in the first place.
+
+As a result, to avoid overloading, Gitaly employs a set of soft limits, such as
+utilizing only 75% of memory capacity and 90% of CPU capacity instead of relying
+on hard limits. Once these soft limits are reached, the concurrency adjuster
+reduces the concurrency limit in a multiplicative manner. This strategy ensures
+that the node has enough headroom to handle potential overloading events.
+
+In theory, the cgroup hierarchy allows us to determine the overloading status
+individually. Thus, Gitaly can adjust the concurrency limit for each repository
+separately. However, this approach would be unnecessarily complicated in
+practice. In contrast, it may lead to confusion for operators later.
+
+As a good start, Gitaly recognizes an overloading event in _either_ condition:
+
+- Soft limits of the parent cgroup are reached.
+- Soft limits of **any** of the repository cgroup are reached
+
+It is logical for the second condition to be in place since a repository's
+capacity limit can be significant to the parent cgroup's capacity. This means
+that when the repository cgroup reaches its limit, fewer resources are available
+for other cgroups. As a result, reducing the concurrency limit delays the
+occurrence of overloading.
+
+#### Latency measurement
+
+When re-calibrate the concurrency limit, latency is taken into account for RPCs
+other than Upload Pack. Two things to consider when measuring latencies:
+
+- How to record latencies
+- How to recognize a latency degradation
+
+It is clear that a powerful gRPC server such as Gitaly has the capability to
+manage numerous requests per second per node. A production server can serve up
+to thousands of requests per second. Keeping track and storing response times in
+a precise manner is not practical.
+
+The heuristic determining whether the process is facing latency degradation is
+interesting. The most naive solution is to pre-define a static latency
+threshold. Each RPC may have a different threshold. Unfortunately, similar to
+static concurrency limiting, it's challenging and tedious to pick a reasonable
+up-to-date value.
+
+Fortunately, there are some famous algorithms for this line of problems, mainly
+applied in the world of TCP Congestion Control:
+
+- Vegas Algorithm ([CN: ASA - Chapter 6.4](https://book.systemsapproach.org/congestion/avoidance.html), [Reference implementation](https://Github.com/Netflix/concurrency-limits/blob/master/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/VegasLimit.java))
+- Gradient Algorithm ([Paper](https://link.springer.com/chapter/10.1007/978-3-642-20798-3_25), [Reference implementation](https://Github.com/Netflix/concurrency-limits/blob/master/concurrency-limits-core/src/main/java/com/netflix/concurrency/limits/limit/Gradient2Limit.java))
+
+The two algorithms are capable of automatically determining the latency
+threshold without any pre-defined configuration. They are highly efficient and
+statistically reliable for real-world scenarios. In my opinion, both algorithms
+are equally suitable for our specific use case.
+
+### Load-shedding
+
+Gitaly being stuck in the overloaded situation for too long can be denoted by
+two signs:
+
+- A certain amount of consecutive backoff events
+- More in-flight requests than concurrency limit for a certain amount of them
+
+In such cases, a particular cgroup or the whole Gitaly node may become
+unavailable temporarily. In-flight requests are likely to either be canceled or
+timeout. On GitLab.com production, an incident is triggered and called for human
+intervention. We can improve this situation by load-shedding.
+
+This mechanism deliberately starts to kill in-flight requests selectively. The
+main purpose is to prevent cascading failure of all inflight requests.
+Hopefully, after some of them are dropped, the cgroup/node can recover back to
+the normal situation fast without human intervention. As a result, it leads to
+net availability and resilience improvement.
+
+Picking which request to kill is tricky. In many systems, request criticality is
+considered. A request from downstream is assigned with a criticality point.
+Requests with lower points are targeted first. Unfortunately, GitLab doesn't
+have a similar system. We have an
+[Urgency system](https://docs.Gitlab.com/ee/development/application_slis/rails_request.html),
+but it is used for response time committing rather than criticality.
+
+As a replacement, we can prioritize requests harming the system the most. Some
+criteria to consider:
+
+- Requests consuming a significant percentage of memory
+- Requests consuming a significant of CPU over time
+- Slow clients
+- Requests from IPs dominating the traffic recently
+- In-queue requests/requests at an early stage. We don’t want to reject requests that are almost finished.
+
+To get started, we can pick the first two criteria first. The list can be
+reinforced when learning from production later.
+
+## References
+
+- Linkedin HODOR system
+ - [https://www.youtube.com/watch?v=-haM4ZpYNko](https://www.youtube.com/watch?v=-haM4ZpYNko)
+ - [https://engineering.linkedin.com/blog/2022/hodor--detecting-and-addressing-overload-in-linkedin-microservic](https://engineering.linkedin.com/blog/2022/hodor--detecting-and-addressing-overload-in-linkedin-microservic)
+- [https://engineering.linkedin.com/blog/2023/hodor--overload-scenarios-and-the-evolution-of-their-detection-a](https://engineering.linkedin.com/blog/2023/hodor--overload-scenarios-and-the-evolution-of-their-detection-a)
+- Google SRE chapters about load balancing and overload:
+ - [https://sre.google/sre-book/load-balancing-frontend/](https://sre.google/sre-book/load-balancing-frontend/)
+ - [https://sre.google/sre-book/load-balancing-datacenter/](https://sre.google/sre-book/load-balancing-datacenter/)
+ - [https://sre.google/sre-book/handling-overload/](https://sre.google/sre-book/handling-overload/)
+ - [https://sre.google/sre-book/addressing-cascading-failures/](https://sre.google/sre-book/addressing-cascading-failures/)
+ - [https://sre.google/workbook/managing-load/](https://sre.google/workbook/managing-load/)
+- [Netflix Performance Under Load](https://netflixtechblog.medium.com/performance-under-load-3e6fa9a60581)
+- [Netflix Adaptive Concurrency Limit](https://Github.com/Netflix/concurrency-limits)
+- [Load Shedding with NGINX using adaptive concurrency control](https://tech.olx.com/load-shedding-with-nginx-using-adaptive-concurrency-control-part-1-e59c7da6a6df)
+- [Overload Control for Scaling WeChat Microservices](http://web1.cs.columbia.edu/~junfeng/papers/dagor-socc18.pdf)
+- [ReactiveConf 2019 - Jay Phelps: Backpressure: Resistance is NOT Futile](https://www.youtube.com/watch?v=I6eZ4ZyI1Zg)
+- [AWS re:Invent 2021 - Keeping Netflix reliable using prioritized load shedding](https://www.youtube.com/watch?v=TmNiHbh-6Wg)
+- [AWS Using load shedding to avoid overload](https://aws.amazon.com/builders-library/using-load-shedding-to-avoid-overload/)
+- ["Stop Rate Limiting! Capacity Management Done Right" by Jon Moore](https://www.youtube.com/watch?v=m64SWl9bfvk)
+- [Using load shedding to survive a success disaster—CRE life lessons](https://cloud.google.com/blog/products/gcp/using-load-shedding-to-survive-a-success-disaster-cre-life-lessons)
+- [Load Shedding in Web Services](https://medium.com/helpshift-engineering/load-shedding-in-web-services-9fa8cfa1ffe4)
+- [Load Shedding in Distributed Systems](https://blog.sofwancoder.com/load-shedding-in-distributed-systems)
diff --git a/doc/ci/index.md b/doc/ci/index.md
index a3106a2475c..bc254146cdf 100644
--- a/doc/ci/index.md
+++ b/doc/ci/index.md
@@ -104,7 +104,7 @@ GitLab CI/CD features, grouped by DevOps stage, include:
| [Dynamic Application Security Testing](../user/application_security/dast/index.md) | Test your application's runtime behavior for vulnerabilities. |
| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) | Analyze your dependencies for known vulnerabilities. |
| [Infrastructure as Code scanning](../user/application_security/iac_scanning/index.md) | Scan your IaC configuration files for known vulnerabilities. |
-| [License Compliance](../user/compliance/license_compliance/index.md) | Search your project dependencies for their licenses. |
+| [License Scanning](../user/compliance/license_scanning_of_cyclonedx_files/index.md) | Search your project dependencies for their licenses. | Search your project dependencies for their licenses. |
| [Secret Detection](../user/application_security/secret_detection/index.md) | Search your application's source code for secrets. |
| [Static Application Security Testing](../user/application_security/sast/index.md) | Test your application's source code for known vulnerabilities. |
| [Web API fuzz testing](../user/application_security/api_fuzzing/index.md) | Test your application's API behavior by providing randomized input. |
diff --git a/doc/ci/testing/index.md b/doc/ci/testing/index.md
index a8fb6d688d7..852dcaf206d 100644
--- a/doc/ci/testing/index.md
+++ b/doc/ci/testing/index.md
@@ -18,7 +18,7 @@ display reports or link to important information directly from [merge requests](
| [Code Quality](code_quality.md) | Analyze your source code quality using the [Code Climate](https://codeclimate.com/) analyzer and show the Code Climate report right in the merge request widget area. |
| [Display arbitrary job artifacts](../yaml/index.md#artifactsexpose_as) | Configure CI pipelines with the `artifacts:expose_as` parameter to directly link to selected [artifacts](../jobs/job_artifacts.md) in merge requests. |
| [Unit test reports](unit_test_reports.md) | Configure your CI jobs to use Unit test reports, and let GitLab display a report on the merge request so that it's easier and faster to identify the failure without having to check the entire job log. |
-| [License Compliance](../../user/compliance/license_compliance/index.md) | Manage the licenses of your dependencies. |
+| [License Scanning](../../user/compliance/license_scanning_of_cyclonedx_files/index.md) | Manage the licenses of your dependencies. |
| [Metrics Reports](metrics_reports.md) | Display the Metrics Report on the merge request so that it's fast and easier to identify changes to important metrics. |
| [Test Coverage visualization](test_coverage_visualization.md) | See test coverage results for merge requests, in the file diff. |
| [Fail fast testing](fail_fast_testing.md) | Run a subset of your RSpec test suite, so failed tests stop the pipeline before the full suite of tests run, saving resources. |
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index 37cb7efdf94..812c7487cb2 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -245,17 +245,18 @@ concatenate them into a single file. Use either:
- A combination of both (`junit: [rspec.xml, test-results/TEST-*.xml]`).
- Directories are not supported(`junit: test-results`, `junit: test-results/**`).
+<!--- start_remove The following content will be removed on remove_date: '2023-11-22' -->
+
## `artifacts:reports:license_scanning` **(ULTIMATE)**
> Introduced in GitLab 12.8.
-The License Compliance report collects [Licenses](../../user/compliance/license_compliance/index.md). The License
-Compliance report uploads to GitLab as an artifact.
-
-GitLab can display the results of one or more reports in:
+The license scanning report was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561)
+in GitLab 15.9 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/421363) in GitLab 16.3.
+You should instead migrate to use [License approval policies](../../user/compliance/license_approval_policies.md) and
+the [new method of license scanning](../../user/compliance/license_scanning_of_cyclonedx_files/index.md).
-- The merge request [license compliance widget](../../user/compliance/license_compliance/index.md).
-- The [license list](../../user/compliance/license_list.md).
+<!--- end_remove -->
## `artifacts:reports:load_performance` **(PREMIUM)**
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 347cf561e24..4f6a9feb191 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -60,7 +60,6 @@ listed here that also do not work properly in FIPS mode:
- [Code Quality](../ci/testing/code_quality.md) does not support operating in FIPS-compliant mode.
- [Dependency scanning](../user/application_security/dependency_scanning/index.md) support for Gradle.
- [Dynamic Application Security Testing (DAST)](../user/application_security/dast/proxy-based.md) supports a reduced set of analyzers. The proxy-based analyzer is not available in FIPS mode today, however browser-based DAST, DAST API, and DAST API Fuzzing images are available.
-- [License compliance](../user/compliance/license_compliance/index.md).
- [Solutions for vulnerabilities](../user/application_security/vulnerabilities/index.md#resolve-a-vulnerability)
for yarn projects.
- [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index e51542649bb..7648e84f5e8 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -146,8 +146,7 @@ Go GitLab linter plugins are maintained in the [`gitlab-org/language-tools/go/li
Dependencies should be kept to the minimum. The introduction of a new
dependency should be argued in the merge request, as per our [Approval Guidelines](../code_review.md#approval-guidelines).
-Both [License Scanning](../../user/compliance/license_compliance/index.md)
-and [Dependency Scanning](../../user/application_security/dependency_scanning/index.md)
+[Dependency Scanning](../../user/application_security/dependency_scanning/index.md)
should be activated on all projects to ensure new dependencies
security status and license compatibility.
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index fa8392b5580..8fda6042fcf 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -318,8 +318,8 @@ After the deprecation period for a schema version, the file is removed from GitL
declare removed versions are rejected, and an error message displays on the corresponding pipeline.
If a report uses a `PATCH` version that doesn't match any vendored schema version, it is validated against
-the latest vendored `PATCH` version. For example, if a report version is 14.0.23 and the latest vendored
-version is 14.0.6, the report is validated against version 14.0.6.
+the latest vendored `PATCH` version. For example, if a report version is 15.0.23 and the latest vendored
+version is 15.0.6, the report is validated against version 15.0.6.
GitLab uses the
[`json_schemer`](https://www.rubydoc.info/gems/json_schemer) gem to perform validation.
@@ -355,12 +355,12 @@ puts(schema_validation_errors)
```
1. Download the appropriate schema that matches your report type and declared version. For
- example, you can find version `14.0.6` of the `container_scanning` report schema at
- `https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/v14.0.6/dist/container-scanning-report-format.json?inline=false`.
+ example, you can find version `15.0.6` of the `container_scanning` report schema at
+ `https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/v15.0.6/dist/container-scanning-report-format.json?inline=false`.
1. Save the Ruby script above in a file, for example, `validate.rb`.
1. Run the script, passing the schema and report file names as arguments in order. For example:
- 1. Using your local Ruby interpreter: `ruby validate.rb container-scanning-format_14-0-6.json gl-container-scanning-report.json`.
- 1. Using Docker: `docker run -it --rm -v $(pwd):/ci ruby:3-slim ruby /ci/validate.rb /ci/container-scanning-format_14-0-6.json /ci/gl-container-scanning-report.json`
+ 1. Using your local Ruby interpreter: `ruby validate.rb container-scanning-format_15-0-6.json gl-container-scanning-report.json`.
+ 1. Using Docker: `docker run -it --rm -v $(pwd):/ci ruby:3 ruby /ci/validate.rb /ci/container-scanning-format_15-0-6.json /ci/gl-container-scanning-report.json`
1. Validation errors are shown on the screen. You must resolve these errors before GitLab can ingest your report.
### Report Fields
diff --git a/doc/development/sec/analyzer_development_guide.md b/doc/development/sec/analyzer_development_guide.md
index af8d1758713..c76b7f5e55f 100644
--- a/doc/development/sec/analyzer_development_guide.md
+++ b/doc/development/sec/analyzer_development_guide.md
@@ -342,7 +342,7 @@ This issue will guide you through the whole release process. In general, you hav
- Check the list of supported technologies in GitLab documentation.
- [Supported languages in SAST](../../user/application_security/sast/index.md#supported-languages-and-frameworks)
- [Supported languages in DS](../../user/application_security/dependency_scanning/index.md#supported-languages-and-package-managers)
- - [Supported languages in LM](../../user/compliance/license_compliance/index.md#supported-languages-and-package-managers)
+ - [Supported languages in LS](../../user/compliance/license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers)
- Check that CI **_job definitions are still accurate_** in vendored CI/CD templates and **_all of the ENV vars are propagated_** to the Docker containers upon `docker run` per tool.
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 38e7b10c091..bb5a9b27cf5 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -37,7 +37,8 @@ Features requiring Docker-in-Docker might not work.
For Auto DevOps, the following features are not supported yet:
- [Auto Code Quality](../../ci/testing/code_quality.md)
-- [Auto License Compliance](../../user/compliance/license_compliance/index.md) ([License scanning of CycloneDX files](../../user/compliance/license_scanning_of_cyclonedx_files/index.md) is supported on OpenShift)
+- [License approval policies](../../user/compliance/license_approval_policies.md)
+- [License Scanning](../../user/compliance/license_scanning_of_cyclonedx_files/index.md) is supported on OpenShift.
- Auto Browser Performance Testing
- Auto Build
- [Operational Container Scanning](../../user/clusters/agent/vulnerabilities.md) (Note: Pipeline [Container Scanning](../../user/application_security/container_scanning/index.md) is supported)
diff --git a/doc/raketasks/index.md b/doc/raketasks/index.md
index e97e453f118..b50646e4841 100644
--- a/doc/raketasks/index.md
+++ b/doc/raketasks/index.md
@@ -37,7 +37,7 @@ The following Rake tasks are available for use with GitLab:
| [Sidekiq job migration](../administration/sidekiq/sidekiq_job_migration.md) | Migrate Sidekiq jobs scheduled for future dates to a new queue. |
| [Service Desk email](../administration/raketasks/service_desk_email.md) | Service Desk email-related tasks. |
| [SMTP maintenance](../administration/raketasks/smtp.md) | SMTP-related tasks. |
-| [SPDX license list import](spdx.md) | Import a local copy of the [SPDX license list](https://spdx.org/licenses/) for matching [License Compliance policies](../user/compliance/license_compliance/index.md). |
+| [SPDX license list import](spdx.md) | Import a local copy of the [SPDX license list](https://spdx.org/licenses/) for matching [License approval policies](../user/compliance/license_approval_policies.md). |
| [Repository storage](../administration/raketasks/storage.md) | List and migrate existing projects and attachments from legacy storage to hashed storage. |
| [Reset user passwords](../security/reset_user_password.md#use-a-rake-task) | Reset user passwords using Rake. |
| [Uploads migrate](../administration/raketasks/uploads/migrate.md) | Migrate uploads between local storage and object storage. |
diff --git a/doc/raketasks/spdx.md b/doc/raketasks/spdx.md
index 608139fa404..423bd909982 100644
--- a/doc/raketasks/spdx.md
+++ b/doc/raketasks/spdx.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# SPDX license list import Rake task **(ULTIMATE SELF)**
GitLab provides a Rake task for uploading a fresh copy of the [SPDX license list](https://spdx.org/licenses/)
-to a GitLab instance. This list is needed for matching the names of [License Compliance policies](../user/compliance/license_compliance/index.md).
+to a GitLab instance. This list is needed for matching the names of [License approval policies](../user/compliance/license_approval_policies.md).
To import a fresh copy of the PDX license list, run:
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index bbb7bf2f625..6a943568cc2 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -77,8 +77,5 @@ You can configure the following security controls:
You can configure the following security controls:
-- [License Compliance](../../../user/compliance/license_compliance/index.md)
- - Can be configured with `.gitlab-ci.yml`. For more details, read [License Compliance](../../../user/compliance/license_compliance/index.md#enable-license-compliance).
-
- [Security Training](../../../user/application_security/vulnerabilities/index.md#enable-security-training-for-vulnerabilities)
- Enable **Security training** for the current project. For more details, read [security training](../../../user/application_security/vulnerabilities/index.md#enable-security-training-for-vulnerabilities).
diff --git a/doc/user/application_security/dast/proxy-based.md b/doc/user/application_security/dast/proxy-based.md
index 6d36abf25cf..5a1ac7e7fb9 100644
--- a/doc/user/application_security/dast/proxy-based.md
+++ b/doc/user/application_security/dast/proxy-based.md
@@ -675,6 +675,11 @@ To delete a site profile:
Validating a site is required to run an active scan.
+Prerequisites:
+
+- A runner must be available in the project to run a validation job.
+- The GitLab server's certificate must be trusted and must not use a self-signed certificate.
+
To validate a site profile:
1. On the left sidebar, at the top, select **Search GitLab** (**{search}**) to find your project.
@@ -857,3 +862,9 @@ For details of the report's schema, see the [schema for DAST reports](https://gi
WARNING:
The JSON report artifacts are not a public API of DAST and their format is expected to change in the
future.
+
+## Troubleshooting
+
+### `unable to get local issuer certificate` when trying to validate a site profile
+
+The use of self-signed certificates is not supported and may cause the job to fail with an error message: `unable to get local issuer certificate`. For more information, see [issue 416670](https://gitlab.com/gitlab-org/gitlab/-/issues/416670).
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index 72229bedf78..33b8ca5e9be 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -9,11 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - System dependencies [introduced](https://gitlab.com/groups/gitlab-org/-/epics/6698) in GitLab 14.6.
> - Group-level dependency list [introduced](https://gitlab.com/groups/gitlab-org/-/epics/8090) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `group_level_dependencies`. Disabled by default.
-> - Group-level dependency list [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/411257) in GitLab 16.3.
-
-FLAG:
-On self-managed GitLab, by default the group-level dependency list is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `group_level_dependencies`.
-On GitLab.com, this feature is available.
+> - Group-level dependency list [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/411257) in GitLab 16.4.
Use the dependency list to review your project or group's dependencies and key
details about those dependencies, including their known vulnerabilities. It is a collection of dependencies in your project, including existing and new findings.
@@ -83,11 +79,14 @@ Dependency paths are supported for the following package managers:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10536) in GitLab 12.3.
-If the [License Compliance](../../compliance/license_compliance/index.md) CI job is configured,
-[discovered licenses](../../compliance/license_compliance/index.md#supported-languages-and-package-managers) are displayed on this page.
+If the [Dependency Scanning](../../application_security/dependency_scanning/index.md) CI job is configured,
+[discovered licenses](../../compliance/license_scanning_of_cyclonedx_files/index.md#enable-license-scanning) are displayed on this page.
## View a group's dependencies
+FLAG:
+On self-managed GitLab, and GitLab.com the feature is disabled by default. To show the feature, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `group_level_dependencies`.
+
![Dependency list](img/dependency_list_v16_3.png)
GitLab displays dependencies with the following information:
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index e3f6982fd6c..25b0c175d6a 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -416,7 +416,6 @@ For more information about overriding security jobs, see:
- [Overriding Container Scanning jobs](container_scanning/index.md#overriding-the-container-scanning-template).
- [Overriding Secret Detection jobs](secret_detection/index.md#configure-scan-settings).
- [Overriding DAST jobs](dast/proxy-based.md#customize-dast-settings).
-- [Overriding License Compliance jobs](../compliance/license_compliance/index.md#overriding-the-template).
All the security scanning tools define their stage, so this error can occur with all of them.
diff --git a/doc/user/application_security/offline_deployments/index.md b/doc/user/application_security/offline_deployments/index.md
index 3f3da69cbc9..1ab26229b50 100644
--- a/doc/user/application_security/offline_deployments/index.md
+++ b/doc/user/application_security/offline_deployments/index.md
@@ -93,7 +93,7 @@ above. You can find more information at each of the pages below:
- [Secret Detection offline directions](../secret_detection/index.md#running-secret-detection-in-an-offline-environment)
- [DAST offline directions](../dast/run_dast_offline.md#run-dast-in-an-offline-environment)
- [API Fuzzing offline directions](../api_fuzzing/index.md#running-api-fuzzing-in-an-offline-environment)
-- [License Compliance offline directions](../../compliance/license_compliance/index.md#running-license-compliance-in-an-offline-environment)
+- [License Scanning offline directions](../../compliance/license_scanning_of_cyclonedx_files/index.md#running-in-an-offline-environment)
- [Dependency Scanning offline directions](../dependency_scanning/index.md#running-dependency-scanning-in-an-offline-environment)
## Loading Docker images onto your offline host
diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md
index 106bd316fd8..fa6c2c1a6c1 100644
--- a/doc/user/compliance/license_compliance/index.md
+++ b/doc/user/compliance/license_compliance/index.md
@@ -3,843 +3,12 @@ type: reference, howto
stage: Secure
group: Composition Analysis
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+remove_date: '2023-08-22'
+redirect_to: '../license_approval_policies.md'
---
-# License Compliance (deprecated) **(ULTIMATE)**
+# License Compliance (removed) **(ULTIMATE)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5483) in GitLab 11.0.
-> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561) in GitLab 15.9.
-
-WARNING:
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561) in GitLab 15.9. You should instead migrate to use [License approval policies](../license_approval_policies.md) and the [new method of license scanning](../license_scanning_of_cyclonedx_files/index.md) prior to GitLab 16.1.
-
-If you're using [GitLab CI/CD](../../../ci/index.md), you can use License Compliance to search your
-project's dependencies for their licenses. You can then decide whether to allow or deny the use of
-each license. For example, if your application uses an external (open source) library whose license
-is incompatible with yours, then you can deny the use of that license.
-
-To detect the licenses in use, License Compliance uses the [License Finder](https://github.com/pivotal/LicenseFinder) scan tool that runs as part of the CI/CD pipeline. The License Compliance job is not dependent on any other job in
-a pipeline.
-
-For the job to activate, License Finder needs to find a compatible package definition in the project directory. For details, see the [Activation on License Finder documentation](https://github.com/pivotal/LicenseFinder#activation).
-GitLab checks the License Compliance report, compares the
-licenses between the source and target branches, and shows the information right on the merge
-request. Denied licenses are indicated by a `x` red icon next to them as well as new licenses that
-need a decision from you. In addition, you can [manually allow or deny](../license_approval_policies.md) licenses in your
-project's security policies section. If a denied license is detected in a new commit,
-GitLab blocks any merge requests containing that commit and instructs the developer to remove the
-license.
-
-NOTE:
-Starting with GitLab 15.9, License Compliance can detect the licenses in use
-[using Dependency Scanning CI jobs](../license_scanning_of_cyclonedx_files/index.md)
-instead of the License Scanning ones.
-
-NOTE:
-If the license compliance report doesn't have anything to compare to, no information
-is displayed in the merge request area. That is the case when you add the
-`license_scanning` job in your `.gitlab-ci.yml` for the first time.
-Consecutive merge requests have something to compare to and the license
-compliance report is shown properly.
-
-The results are saved as a
-[License Compliance report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportslicense_scanning)
-that you can later download and analyze.
-
-WARNING:
-License Compliance Scanning does not support run-time installation of compilers and interpreters.
-
-## Enable License Compliance
-
-To enable License Compliance in your project's pipeline:
-
-- Include the [`License-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml) in your `.gitlab-ci.yml` file.
-
-License Compliance is not supported when GitLab is run with FIPS mode enabled.
-
-### Include the License Scanning template
-
-Prerequisites:
-
-- [GitLab Runner](../../../ci/runners/index.md) available, with the
- [`docker` executor](https://docs.gitlab.com/runner/executors/docker.html). If you're using the
- shared runners on GitLab.com, this is enabled by default.
-- License Scanning runs in the `test` stage, which is available by default. If you redefine the stages in the
- `.gitlab-ci.yml` file, the `test` stage is required.
-- [FIPS mode](../../../development/fips_compliance.md#enable-fips-mode) must be disabled.
-
-To [include](../../../ci/yaml/index.md#includetemplate) the
-[`License-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml), add it to your `.gitlab-ci.yml` file:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-```
-
-The included template creates a `license_scanning` job in your CI/CD pipeline and scans your
-dependencies to find their licenses.
-
-## License expressions
-
-GitLab has limited support for [composite licenses](https://spdx.github.io/spdx-spec/v2-draft/SPDX-license-expressions/).
-License compliance can read multiple licenses, but always considers them combined using the `AND` operator. For example,
-if a dependency has two licenses, and one of them is allowed and the other is denied by the project [license approval policy](../license_approval_policies.md),
-GitLab evaluates the composite license as _denied_, as this is the safer option.
-The ability to support other license expression operators (like `OR`, `WITH`) is tracked
-in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/6571).
-
-## Supported languages and package managers
-
-The following languages and package managers are supported.
-
-Gradle 1.x projects are not supported. The minimum supported version of Maven is 3.2.5.
-
-| Language | Package managers | Notes |
-|------------|----------------------------------------------------------------------------------------------|-------|
-| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/) (7 and earlier) | |
-| Go | [Godep](https://github.com/tools/godep) ([deprecated](../../../update/deprecations.md#godep-support-in-license-compliance)), [go mod](https://github.com/golang/go/wiki/Modules) | |
-| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) | |
-| .NET | [NuGet](https://www.nuget.org/) | The .NET Framework is supported via the [mono project](https://www.mono-project.com/). There are, however, some limitations. The scanner doesn't support Windows-specific dependencies and doesn't report dependencies of your project's listed dependencies. Also, the scanner always marks detected licenses for all dependencies as `unknown`. |
-| Python | [pip](https://pip.pypa.io/en/stable/) | Python is supported through [requirements.txt](https://pip.pypa.io/en/stable/user_guide/#requirements-files) and [Pipfile.lock](https://github.com/pypa/pipfile#pipfilelock). |
-| Ruby | [gem](https://rubygems.org/) | |
-
-### Experimental support
-
-The following languages and package managers are [supported experimentally](https://github.com/pivotal/LicenseFinder#experimental-project-types).
-The reported licenses might be incomplete or inaccurate.
-
-| Language | Package managers |
-|------------|---------------------------------------------------------------------------------------------------------------|
-| JavaScript | [Yarn](https://yarnpkg.com/) |
-| Go | `go get`, `gvt`, `glide`, `dep`, `trash`, `govendor` |
-| Erlang | [Rebar](https://rebar3.org/) |
-| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage), [CocoaPods](https://cocoapods.org/) v0.39 and below |
-| Elixir | [Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) |
-| C++/C | [Conan](https://conan.io/) |
-| Rust | [Cargo](https://crates.io/) |
-| PHP | [Composer](https://getcomposer.org/) |
-
-## Available CI/CD variables
-
-License Compliance can be configured using CI/CD variables.
-
-| CI/CD variable | Required | Description |
-|-----------------------------|----------|-------------|
-| `ADDITIONAL_CA_CERT_BUNDLE` | no | Bundle of trusted CA certificates (currently supported in Pip, Pipenv, Maven, Gradle, Yarn, and npm projects). |
-| `ASDF_JAVA_VERSION` | no | Version of Java to use for the scan. |
-| `ASDF_NODEJS_VERSION` | no | Version of Node.js to use for the scan. |
-| `ASDF_PYTHON_VERSION` | no | Version of Python to use for the scan. [Configuration](#selecting-the-version-of-python) |
-| `ASDF_RUBY_VERSION` | no | Version of Ruby to use for the scan. |
-| `GRADLE_CLI_OPTS` | no | Additional arguments for the Gradle executable. If not supplied, defaults to `--exclude-task=test`. |
-| `LICENSE_FINDER_CLI_OPTS` | no | Additional arguments for the `license_finder` executable. For example, if you have multiple projects in nested directories, you can update your `.gitlab-ci.yml` template to specify a recursive scan, like `LICENSE_FINDER_CLI_OPTS: '--recursive'`. |
-| `LM_JAVA_VERSION` | no | Version of Java. If set to `11`, Maven and Gradle use Java 11 instead of Java 8. [Configuration](#selecting-the-version-of-java) |
-| `LM_PYTHON_VERSION` | no | Version of Python. If set to `3`, dependencies are installed using Python 3 instead of Python 2.7. [Configuration](#selecting-the-version-of-python) |
-| `MAVEN_CLI_OPTS` | no | Additional arguments for the `mvn` executable. If not supplied, defaults to `-DskipTests`. |
-| `PIP_INDEX_URL` | no | Base URL of Python Package Index (default: `https://pypi.org/simple/`). |
-| `SECURE_ANALYZERS_PREFIX` | no | Set the Docker registry base address to download the analyzer from. |
-| `SETUP_CMD` | no | Custom setup for the dependency installation (experimental). |
-
-## Installing custom dependencies
-
-> Introduced in GitLab 11.4.
-
-The `license_finder` image already embeds many auto-detection scripts, languages,
-and packages. Nevertheless, it's almost impossible to cover all cases for all projects.
-That's why sometimes it's necessary to install extra packages, or to have extra steps
-in the project automated setup, like the download and installation of a certificate.
-For that, a `SETUP_CMD` CI/CD variable can be passed to the container,
-with the required commands to run before the license detection.
-
-If present, this variable overrides the setup step necessary to install all the packages
-of your application (for example: for a project with a `Gemfile`, the setup step could be
-`bundle install`).
-
-For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-variables:
- SETUP_CMD: sh my-custom-install-script.sh
-```
-
-In this example, `my-custom-install-script.sh` is a shell script at the root
-directory of your project.
-
-## Working with Monorepos
-
-Depending on your language, you may need to specify the path to the individual
-projects of a monorepo using the `LICENSE_FINDER_CLI_OPTS` variable. Passing in
-the project paths can significantly speed up builds over using the `--recursive`
-License Finder option.
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-variables:
- LICENSE_FINDER_CLI_OPTS: "--aggregate_paths=relative-path/to/sub-project/one relative-path/to/sub-project/two"
-```
-
-## Overriding the template
-
-WARNING:
-Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/index.md#only--except)
-is no longer supported. When overriding the template, you must use [`rules`](../../../ci/yaml/index.md#rules) instead.
-
-If you want to override the job definition (for example, change properties like
-`variables` or `dependencies`), you need to declare a `license_scanning` job
-after the template inclusion and specify any additional keys under it. For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- CI_DEBUG_TRACE: "true"
-```
-
-## Configuring Maven projects
-
-The License Compliance tool provides a `MAVEN_CLI_OPTS` CI/CD variable which can hold
-the command line arguments to pass to the `mvn install` command which is executed under the hood.
-Feel free to use it for the customization of Maven execution. For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- MAVEN_CLI_OPTS: --debug
-```
-
-`mvn install` runs through all of the [build life cycle](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)
-stages prior to `install`, including `test`. Running unit tests is not directly
-necessary for the license scanning purposes and consumes time, so it's skipped
-by having the default value of `MAVEN_CLI_OPTS` as `-DskipTests`. If you want
-to supply custom `MAVEN_CLI_OPTS` and skip tests at the same time, don't forget
-to explicitly add `-DskipTests` to your options.
-If you still need to run tests during `mvn install`, add `-DskipTests=false` to
-`MAVEN_CLI_OPTS`.
-
-### Using private Maven repositories
-
-If you have a private Maven repository which requires login credentials,
-you can use the `MAVEN_CLI_OPTS` CI/CD variable.
-
-Read more on [how to use private Maven repositories](../../application_security/index.md#using-private-maven-repositories).
-
-You can also use `MAVEN_CLI_OPTS` to connect to a trusted Maven repository that uses a self-signed
-or internally trusted certificate. For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- MAVEN_CLI_OPTS: -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true -Dmaven.wagon.http.ssl.insecure=true
-```
-
-Alternatively, you can use a Java key store to verify the TLS connection. For instructions on how to
-generate a key store file, see the
-[Maven Guide to Remote repository access through authenticated HTTPS](https://maven.apache.org/guides/mini/guide-repository-ssl.html).
-
-## Selecting the version of Java
-
-License Compliance uses Java 8 by default. You can specify a different Java version using `LM_JAVA_VERSION`.
-
-`LM_JAVA_VERSION` only accepts versions: 8, 11, 14, 15.
-
-## Selecting the version of Python
-
-> - [Introduced](https://gitlab.com/gitlab-org/security-products/license-management/-/merge_requests/36) in GitLab 12.0.
-> - In [GitLab 12.2](https://gitlab.com/gitlab-org/gitlab/-/issues/12032), Python 3.5 became the default.
-> - In [GitLab 12.7](https://gitlab.com/gitlab-org/security-products/license-management/-/merge_requests/101), Python 3.8 became the default.
-
-License Compliance uses Python 3.8 and pip 19.1 by default.
-If your project requires Python 2, you can switch to Python 2.7 and pip 10.0
-by setting the `LM_PYTHON_VERSION` CI/CD variable to `2`.
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- LM_PYTHON_VERSION: 2
-```
-
-`LM_PYTHON_VERSION` or `ASDF_PYTHON_VERSION` can be used to specify the desired version of Python. When both variables are specified `LM_PYTHON_VERSION` takes precedence.
-
-## Custom root certificates for Python
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables).
-
-### Using private Python repositories
-
-If you have a private Python repository you can use the `PIP_INDEX_URL` [CI/CD variable](#available-cicd-variables)
-to specify its location.
-
-## Configuring npm projects
-
-You can configure npm projects by using an [`.npmrc`](https://docs.npmjs.com/configuring-npm/npmrc.html/)
-file.
-
-### Using private npm registries
-
-If you have a private npm registry you can use the
-[`registry`](https://docs.npmjs.com/using-npm/config/#registry)
-setting to specify its location.
-
-For example:
-
-```plaintext
-registry = https://npm.example.com
-```
-
-### Custom root certificates for npm
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables).
-
-To disable TLS verification you can provide the [`strict-ssl`](https://docs.npmjs.com/using-npm/config/#strict-ssl)
-setting.
-
-For example:
-
-```plaintext
-strict-ssl = false
-```
-
-## Configuring Yarn projects
-
-You can configure Yarn projects by using a [`.yarnrc.yml`](https://yarnpkg.com/configuration/yarnrc/)
-file.
-
-### Using private Yarn registries
-
-If you have a private Yarn registry you can use the
-[`npmRegistryServer`](https://yarnpkg.com/configuration/yarnrc/#npmRegistryServer)
-setting to specify its location.
-
-For example:
-
-```plaintext
-npmRegistryServer: "https://npm.example.com"
-```
-
-### Custom root certificates for Yarn
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables).
-
-## Configuring Bower projects
-
-You can configure Bower projects by using a [`.bowerrc`](https://bower.io/docs/config/#bowerrc-specification)
-file.
-
-### Using private Bower registries
-
-If you have a private Bower registry you can use the
-[`registry`](https://bower.io/docs/config/#bowerrc-specification)
-setting to specify its location.
-
-For example:
-
-```plaintext
-{
- "registry": "https://registry.bower.io"
-}
-```
-
-### Custom root certificates for Bower
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables), or by
-specifying a `ca` setting in a [`.bowerrc`](https://bower.io/docs/config/#bowerrc-specification)
-file.
-
-## Configuring Bundler projects
-
-### Using private Bundler registries
-
-If you have a private Bundler registry you can use the
-[`source`](https://bundler.io/man/gemfile.5.html#GLOBAL-SOURCES)
-setting to specify its location.
-
-For example:
-
-```plaintext
-source "https://gems.example.com"
-```
-
-### Custom root certificates for Bundler
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables), or by
-specifying a [`BUNDLE_SSL_CA_CERT`](https://bundler.io/v2.0/man/bundle-config.1.html)
-[variable](../../../ci/variables/index.md#define-a-cicd-variable-in-the-gitlab-ciyml-file)
-in the job definition.
-
-## Configuring Cargo projects
-
-### Using private Cargo registries
-
-If you have a private Cargo registry you can use the
-[`registries`](https://doc.rust-lang.org/cargo/reference/registries.html)
-setting to specify its location.
-
-For example:
-
-```toml
-[registries]
-my-registry = { index = "https://my-intranet:8080/git/index" }
-```
-
-### Custom root certificates for Cargo
-
-To supply a custom root certificate to complete TLS verification, do one of the following:
-
-- Use the `ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables).
-- Specify a [`CARGO_HTTP_CAINFO`](https://doc.rust-lang.org/cargo/reference/environment-variables.html)
- [variable](../../../ci/variables/index.md#define-a-cicd-variable-in-the-gitlab-ciyml-file)
- in the job definition.
-
-## Configuring Composer projects
-
-### Using private Composer registries
-
-If you have a private Composer registry you can use the
-[`repositories`](https://getcomposer.org/doc/05-repositories.md)
-setting to specify its location.
-
-For example:
-
-```json
-{
- "repositories": [
- { "packagist.org": false },
- {
- "type": "composer",
- "url": "https://composer.example.com"
- }
- ],
- "require": {
- "monolog/monolog": "1.0.*"
- }
-}
-```
-
-### Custom root certificates for Composer
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables), or by
-specifying a [`COMPOSER_CAFILE`](https://getcomposer.org/doc/03-cli.md#composer-cafile)
-[variable](../../../ci/variables/index.md#define-a-cicd-variable-in-the-gitlab-ciyml-file)
-in the job definition.
-
-## Configuring Conan projects
-
-You can configure [Conan](https://conan.io/) projects by adding a `.conan` directory to your
-project root. The project root serves as the [`CONAN_USER_HOME`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-user-home).
-
-Consult the [Conan](https://docs.conan.io/en/latest/reference/config_files/conan.conf.html#conan-conf)
-documentation for a list of settings that you can apply.
-
-The `license_scanning` job runs in a [Debian 10](https://www.debian.org/releases/buster/) Docker
-image. The supplied image ships with some build tools such as [CMake](https://cmake.org/) and [GCC](https://gcc.gnu.org/).
-However, not all project types are supported by default. To install additional tools needed to
-compile dependencies, use a [`before_script`](../../../ci/yaml/index.md#before_script)
-to install the necessary build tools using the [`apt`](https://wiki.debian.org/PackageManagementTools)
-package manager. For a comprehensive list, consult [the Conan documentation](https://docs.conan.io/en/latest/introduction.html#all-platforms-all-build-systems-and-compilers).
-
-The default [Conan](https://conan.io/) configuration sets [`CONAN_LOGIN_USERNAME`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-login-username-conan-login-username-remote-name)
-to `ci_user`, and binds [`CONAN_PASSWORD`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-password-conan-password-remote-name)
-to the [`CI_JOB_TOKEN`](../../../ci/variables/predefined_variables.md)
-for the running job. This allows Conan projects to fetch packages from a [GitLab Conan Repository](../../packages/conan_repository/index.md#fetch-conan-package-information-from-the-package-registry)
-if a GitLab remote is specified in the `.conan/remotes.json` file.
-
-To override the default credentials specify a [`CONAN_LOGIN_USERNAME_{REMOTE_NAME}`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-login-username-conan-login-username-remote-name)
-matching the name of the remote specified in the `.conan/remotes.json` file.
-
-NOTE:
-[MSBuild](https://github.com/mono/msbuild#microsoftbuild-msbuild) projects aren't supported. The
-`license_scanning` image ships with [Mono](https://www.mono-project.com/) and [MSBuild](https://github.com/mono/msbuild#microsoftbuild-msbuild).
-Additional setup may be required to build packages for this project configuration.
-
-### Using private Conan registries
-
-By default, [Conan](https://conan.io/) uses the `conan-center` remote. For example:
-
-```json
-{
- "remotes": [
- {
- "name": "conan-center",
- "url": "https://conan.bintray.com",
- "verify_ssl": true
- }
- ]
-}
-```
-
-To fetch dependencies from an alternate remote, specify that remote in a `.conan/remotes.json`. For
-example:
-
-```json
-{
- "remotes": [
- {
- "name": "gitlab",
- "url": "https://gitlab.com/api/v4/packages/conan",
- "verify_ssl": true
- }
- ]
-}
-```
-
-If credentials are required to authenticate then you can configure a [protected CI/CD variable](../../../ci/variables/index.md#protect-a-cicd-variable)
-following the naming convention described in the [`CONAN_LOGIN_USERNAME` documentation](https://docs.conan.io/en/latest/reference/env_vars.html#conan-login-username-conan-login-username-remote-name).
-
-### Custom root certificates for Conan
-
-You can provide custom certificates by adding a `.conan/cacert.pem` file to the project root and
-setting [`CA_CERT_PATH`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-cacert-path)
-to `.conan/cacert.pem`.
-
-If you specify the `ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables), this
-variable's X.509 certificates are installed in the Docker image's default trust store and Conan is
-configured to use this as the default `CA_CERT_PATH`.
-
-## Configuring Go projects
-
-To configure [Go modules](https://github.com/golang/go/wiki/Modules)
-based projects, specify [CI/CD variables](https://pkg.go.dev/cmd/go#hdr-Environment_variables)
-in the `license_scanning` job's [variables](#available-cicd-variables) section in `.gitlab-ci.yml`.
-
-If a project has [vendored](https://pkg.go.dev/cmd/go#hdr-Vendor_Directories) its modules,
-then the combination of the `vendor` directory and `mod.sum` file are used to detect the software
-licenses associated with the Go module dependencies.
-
-### Using private Go registries
-
-You can use the [`GOPRIVATE`](https://pkg.go.dev/cmd/go#hdr-Environment_variables)
-and [`GOPROXY`](https://pkg.go.dev/cmd/go#hdr-Environment_variables)
-environment variables to control where modules are sourced from. Alternatively, you can use
-[`go mod vendor`](https://go.dev/ref/mod#tmp_28) to vendor a project's modules.
-
-### Custom root certificates for Go
-
-You can specify the [`-insecure`](https://pkg.go.dev/cmd/go/internal/get) flag by exporting the
-[`GOFLAGS`](https://pkg.go.dev/cmd/go#hdr-Environment_variables)
-environment variable. For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- GOFLAGS: '-insecure'
-```
-
-### Using private NuGet registries
-
-If you have a private NuGet registry you can add it as a source
-by adding it to the [`packageSources`](https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#package-source-sections)
-section of a [`nuget.config`](https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file) file.
-
-For example:
-
-```xml
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <packageSources>
- <clear />
- <add key="custom" value="https://nuget.example.com/v3/index.json" />
- </packageSources>
-</configuration>
-```
-
-### Custom root certificates for NuGet
-
-You can supply a custom root certificate to complete TLS verification by using the
-`ADDITIONAL_CA_CERT_BUNDLE` [CI/CD variable](#available-cicd-variables).
-
-### Migration from `license_management` to `license_scanning`
-
-WARNING:
-The `license_management` job was deprecated in GitLab 12.8. The `License-Management.gitlab-ci.yml` template was removed from GitLab 14.0.
-
-In GitLab 12.8 a new name for `license_management` job was introduced. This change was made to improve clarity around the purpose of the scan, which is to scan and collect the types of licenses present in a projects dependencies.
-GitLab 13.0 drops support for `license_management`.
-If you're using a custom setup for License Compliance, you're required
-to update your CI configuration accordingly:
-
-1. Change the CI template to `License-Scanning.gitlab-ci.yml`.
-1. Change the job name to `license_scanning` (if you mention it in `.gitlab-ci.yml`).
-1. Change the artifact name to `license_scanning`, and the filename to `gl-license-scanning-report.json` (if you mention it in `.gitlab-ci.yml`).
-
-For example, the following `.gitlab-ci.yml`:
-
-```yaml
-include:
- - template: License-Management.gitlab-ci.yml
-
-license_management:
- artifacts:
- reports:
- license_management: gl-license-management-report.json
-```
-
-Should be changed to:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- artifacts:
- reports:
- license_scanning: gl-license-scanning-report.json
-```
-
-If you use the `license_management` artifact in GitLab 13.0 or later, the License Compliance job generates this error:
-
-```plaintext
-WARNING: Uploading artifacts to coordinator... failed id=:id responseStatus=400 Bad Request status=400 Bad Request token=:sha
-
-FATAL: invalid_argument
-```
-
-If you encounter this error, follow the instructions described in this section.
-
-## Running License Compliance in an offline environment
-
-For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
-to external resources through the internet, some adjustments are required for the License Compliance job to
-successfully run. For more information, see [Offline environments](../../application_security/offline_deployments/index.md).
-
-### Requirements for offline License Compliance
-
-To use License Compliance in an offline environment, you need:
-
-- To meet the standard [License Compliance prerequisites](#include-the-license-scanning-template).
-- Docker Container Registry with locally available copies of License Compliance [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
-
-NOTE:
-GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
-meaning the runner tries to pull Docker images from the GitLab container registry even if a local
-copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
-in an offline environment if you prefer using only locally available Docker images. However, we
-recommend keeping the pull policy setting to `always` if not in an offline environment, as this
-enables the use of updated scanners in your CI/CD pipelines.
-
-### Make GitLab License Compliance analyzer images available inside your Docker registry
-
-For License Compliance with all [supported languages and package managers](#supported-languages-and-package-managers),
-import the following default License Compliance analyzer images from `registry.gitlab.com` to your
-offline [local Docker container registry](../../packages/container_registry/index.md):
-
-```plaintext
-registry.gitlab.com/security-products/license-finder:latest
-```
-
-The process for importing Docker images into a local offline Docker registry depends on
-**your network security policy**. Consult your IT staff to find an accepted and approved
-process by which external resources can be imported or temporarily accessed. These scanners are [updated periodically](../../application_security/index.md#vulnerability-scanner-maintenance)
-with new definitions, so consider if you are able to make periodic updates yourself.
-
-For details on saving and transporting Docker images as a file, see the Docker documentation on
-[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
-[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
-
-### Set License Compliance CI/CD variables to use local License Compliance analyzers
-
-Add the following configuration to your `.gitlab-ci.yml` file. You must replace `image` to refer to
-the License Compliance Docker image hosted on your local Docker container registry:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- image:
- name: localhost:5000/analyzers/license-management:latest
-```
-
-The License Compliance job should now use local copies of the License Compliance analyzers to scan
-your code and generate security reports, without requiring internet access.
-
-Additional configuration may be needed for connecting to private registries for:
-
-- [Bower](#using-private-bower-registries),
-- [Bundler](#using-private-bundler-registries),
-- [Conan](#using-private-bower-registries),
-- [Go](#using-private-go-registries),
-- [Maven repositories](#using-private-maven-repositories),
-- [npm](#using-private-npm-registries),
-- [Python repositories](#using-private-python-repositories),
-- [Yarn](#using-private-yarn-registries).
-
-### SPDX license list name matching
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212388) in GitLab 13.3.
-
-Prior to GitLab 13.3, offline environments required an exact name match for [project policies](../license_approval_policies.md).
-In GitLab 13.3 and later, GitLab matches the name of [project policies](../license_approval_policies.md)
-with license names from the [SPDX license list](https://spdx.org/licenses/).
-A local copy of the SPDX license list is distributed with the GitLab instance. If needed, the GitLab
-instance's administrator can manually update it with a [Rake task](../../../raketasks/spdx.md).
-
-## Warnings
-
-We recommend that you use the most recent version of all containers, and the most recent supported version of all package managers and languages. Using previous versions carries an increased security risk because unsupported versions may no longer benefit from active security reporting and backporting of security fixes.
-
-## Troubleshooting
-
-### `ASDF_PYTHON_VERSION` does not automatically install the version
-
-Defining a non-latest Python version in `ASDF_PYTHON_VERSION` [doesn't have it automatically installed](https://gitlab.com/gitlab-org/gitlab/-/issues/325604). If your project requires a non-latest version of Python:
-
-1. Define the required version by setting the `ASDF_PYTHON_VERSION` CI/CD variable.
-1. Pass a custom script to the `SETUP_CMD` CI/CD variable to install the required version and dependencies.
-
-For example:
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- SETUP_CMD: ./setup.sh
- ASDF_PYTHON_VERSION: "3.7.2"
- before_script:
- - echo "asdf install python 3.7.2 && pip install -r requirements.txt" > setup.sh
- - chmod +x setup.sh
- - apt-get -y update
- - apt-get -y install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl git
-```
-
-### `ERROR -- : asdf: No preset version installed for command`
-
-This error occurs when the version of the tools used by your project
-do not match the version of the pre-installed tools available in the
-`license_scanning` Docker image. The `license_scanning` job uses
-[asdf-vm](https://asdf-vm.com/) to activate the appropriate version of
-a tool that your project relies on. For example, if your project relies on a specific
-version of [Node.js](https://nodejs.org/) or any other supported tool you can
-specify the desired version by adding a
-[`.tool-versions`](https://asdf-vm.com/#/core-configuration?id=tool-versions) file to the project
-or using the appropriate [`ASDF_<tool>_VERSION`](https://asdf-vm.com/#/core-configuration?id=environment-variables) environment variable to
-activate the appropriate version.
-
-For example, the following `.tool-versions` file activates version `12.16.3` of [Node.js](https://nodejs.org/)
-and version `2.7.4` of [Ruby](https://www.ruby-lang.org/).
-
-```plaintext
-nodejs 12.16.3
-ruby 2.7.4
-```
-
-The next example shows how to activate the same versions of the tools mentioned above by using CI/CD variables defined in your
-project's `.gitlab-ci.yml` file.
-
-```yaml
-include:
- - template: Security/License-Scanning.gitlab-ci.yml
-
-license_scanning:
- variables:
- ASDF_NODEJS_VERSION: '12.16.3'
- ASDF_RUBY_VERSION: '2.7.4'
-```
-
-A full list of variables can be found in [CI/CD variables](#available-cicd-variables).
-
-To find out what tools are pre-installed in the `license_scanning` Docker image use the following command:
-
-```shell
-$ docker run --entrypoint='' -ti --rm registry.gitlab.com/security-products/license-finder:4 \
- /bin/bash -c 'dpkg -i /opt/toolcache/*.deb && asdf list'
-...
-dotnet-core
- 3.1.302
-elixir
- 1.10.4
-golang
- 1.15.5
- 1.16.2
-gradle
-No versions installed
-java
- 11
- 14
- 15
- 8
-maven
-No versions installed
-nodejs
- 10.21.0
- 12.18.2
- 14.17.1
-php
- 7.4.8
-python
- 2.7.18
- 3.3.7
- 3.4.10
- 3.5.9
- 3.6.11
- 3.7.7
- 3.8.5
-ruby
- 2.4.10
- 2.4.5
- 2.4.9
- 2.5.8
- 2.6.0
- 2.6.1
- 2.6.2
- 2.6.3
- 2.6.4
- 2.6.5
- 2.6.6
- 2.7.0
- 2.7.1
- 2.7.2
-rust
- 1.45.0
-```
-
-It might take more than 10 minutes to run the command above.
-This is because it installs every single tool version available in the Docker image.
-
-To interact with the `license_scanning` runtime environment use the following command:
-
-```shell
-$ docker run -it --entrypoint='' registry.gitlab.com/security-products/license-finder:4 /bin/bash -l
-root@6abb70e9f193:~#
-```
-
-NOTE:
-Selecting a custom version of [Mono](https://www.mono-project.com/) or [.NET Core](https://dotnet.microsoft.com/download/dotnet) is currently not supported.
-
-### LicenseFinder::Maven: is not installed error
-
-If your project contains a `mvnw` or `mvnw.cmd` file, then the license scanning job may fail with the `LicenseFinder::Maven: is not installed error` error. To resolve this, modify the license scanning job to remove the files in the `before_script` section. Example:
-
-```yaml
-include:
- - template: License-Scanning.gitlab-ci.yml
-
-license_scanning:
- before_script:
- - rm mvnw
- - rm mvnw.cmd
-```
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/387561) in GitLab 15.9
+and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/421363) in GitLab 16.3.
+Use [License Approval Policies](https://gitlab.com/groups/gitlab-org/-/epics/8092) instead.
diff --git a/doc/user/compliance/license_list.md b/doc/user/compliance/license_list.md
index deec4e28911..1105d22ecce 100644
--- a/doc/user/compliance/license_list.md
+++ b/doc/user/compliance/license_list.md
@@ -16,13 +16,13 @@ For the licenses to appear under the license list, the following
requirements must be met:
1. You must be generating an SBOM file with components from one of our [one of our supported languages](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers).
-1. If using our [`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml) to generate the SBOM file, then your project must use at least one of the [supported languages and package managers](license_compliance/index.md#supported-languages-and-package-managers).
+1. If using our [`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml) to generate the SBOM file, then your project must use at least one of the [supported languages and package managers](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers).
Alternatively, licenses will also appear under the license list when using our deprecated [`License-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml) as long as the following requirements are met:
-1. The License Compliance CI/CD job must be [enabled](license_compliance/index.md#enable-license-compliance) for your project.
+1. The Dependency Scanning CI/CD job must be [enabled](license_scanning_of_cyclonedx_files/index.md#enable-license-scanning) for your project.
1. Your project must use at least one of the
- [supported languages and package managers](license_compliance/index.md#supported-languages-and-package-managers).
+ [supported languages and package managers](license_scanning_of_cyclonedx_files/index.md#supported-languages-and-package-managers).
When everything is configured, on the left sidebar, select **Secure > License compliance**.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 727c8e10d9c..142c65775d9 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -116,10 +116,10 @@ The following table lists project permissions available for each role:
| [Issues](project/issues/index.md):<br>Archive [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Delete | | | | | ✓ |
-| [License Compliance](compliance/license_compliance/index.md):<br>View allowed and denied licenses | ✓ (1) | ✓ | ✓ | ✓ | ✓ |
-| [License Compliance](compliance/license_compliance/index.md):<br>View License Compliance reports | ✓ (1) | ✓ | ✓ | ✓ | ✓ |
-| [License Compliance](compliance/license_compliance/index.md):<br>View License list | | ✓ | ✓ | ✓ | ✓ |
-| [License Compliance](compliance/license_compliance/index.md):<br>Manage license policy | | | | ✓ | ✓ |
+| [License Scanning](compliance/license_scanning_of_cyclonedx_files/index.md):<br>View allowed and denied licenses | ✓ (1) | ✓ | ✓ | ✓ | ✓ |
+| [License Scanning](compliance/license_scanning_of_cyclonedx_files/index.md):<br>View License Compliance reports | ✓ (1) | ✓ | ✓ | ✓ | ✓ |
+| [License Scanning](compliance/license_scanning_of_cyclonedx_files/index.md):<br>View License list | | ✓ | ✓ | ✓ | ✓ |
+| [License approval policies](../user/compliance/license_approval_policies.md):<br>Manage license policy | | | | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Assign reviewer | | ✓ | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>See list | | ✓ | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Apply code change suggestions | | | ✓ | ✓ | ✓ |
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 76cdd4cfcdd..90124406145 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -280,7 +280,7 @@ For a software developer working in a team:
1. You gather feedback from your team.
1. You work on the implementation optimizing code with [Code Quality reports](../../../ci/testing/code_quality.md).
1. You verify your changes with [Unit test reports](../../../ci/testing/unit_test_reports.md) in GitLab CI/CD.
-1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../compliance/license_compliance/index.md).
+1. You avoid using dependencies whose license is not compatible with your project with [License approval policies](../../../user/compliance/license_approval_policies.md).
1. You request the [approval](approvals/index.md) from your manager.
1. Your manager:
1. Pushes a commit with their final review.
diff --git a/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb b/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
index 0282531ae17..b0b7882d54d 100644
--- a/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
+++ b/lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb
@@ -54,6 +54,7 @@ module Gitlab
.where(namespace_id: nil)
.where(source_type: 'Project')
.where.not(projects: { project_namespace_id: nil })
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
.select("routes.id, projects.project_namespace_id")
end
end
diff --git a/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects.rb b/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects.rb
index 74f5bc3f725..e1ea0c66ad4 100644
--- a/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects.rb
+++ b/lib/gitlab/background_migration/nullify_creator_id_column_of_orphaned_projects.rb
@@ -9,14 +9,18 @@ module Gitlab
relation.where.not(creator_id: nil)
.joins('LEFT OUTER JOIN users ON users.id = projects.creator_id')
.where(users: { id: nil })
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
end
operation_name :update_all
feature_category :groups_and_projects
def perform
- each_sub_batch do |sub_batch|
- sub_batch.update_all(creator_id: nil)
+ ::Gitlab::Database.allow_cross_joins_across_databases(url:
+ 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843') do
+ each_sub_batch do |sub_batch|
+ sub_batch.update_all(creator_id: nil)
+ end
end
end
end
diff --git a/lib/gitlab/background_migration/populate_projects_star_count.rb b/lib/gitlab/background_migration/populate_projects_star_count.rb
index 8417dc91b1b..0790bd98018 100644
--- a/lib/gitlab/background_migration/populate_projects_star_count.rb
+++ b/lib/gitlab/background_migration/populate_projects_star_count.rb
@@ -39,20 +39,23 @@ module Gitlab
# rubocop:enable Database/RescueStatementTimeout
def update_batch(sub_batch)
- ApplicationRecord.connection.execute <<~SQL
- WITH batched_relation AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (#{sub_batch.select(:id).to_sql})
- UPDATE projects
- SET star_count = (
- SELECT COUNT(*)
- FROM users_star_projects
- INNER JOIN users
- ON users_star_projects.user_id = users.id
- WHERE users_star_projects.project_id = batched_relation.id
- AND users.state = 'active'
- )
- FROM batched_relation
- WHERE projects.id = batched_relation.id
- SQL
+ ::Gitlab::Database.allow_cross_joins_across_databases(url:
+ 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843') do
+ ApplicationRecord.connection.execute <<~SQL
+ WITH batched_relation AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (#{sub_batch.select(:id).to_sql})
+ UPDATE projects
+ SET star_count = (
+ SELECT COUNT(*)
+ FROM users_star_projects
+ INNER JOIN users
+ ON users_star_projects.user_id = users.id
+ WHERE users_star_projects.project_id = batched_relation.id
+ AND users.state = 'active'
+ )
+ FROM batched_relation
+ WHERE projects.id = batched_relation.id
+ SQL
+ end
end
end
end
diff --git a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
index 5dbf30bad4e..155e35b64f4 100644
--- a/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
+++ b/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects.rb
@@ -37,6 +37,8 @@ module Gitlab
reverts_for_type('project') do |path_before_rename, current_path|
matches_path = MigrationClasses::Route.arel_table[:path].matches(current_path)
project = MigrationClasses::Project.joins(:route)
+ .allow_cross_joins_across_databases(url:
+ 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
.find_by(matches_path)
if project
@@ -67,6 +69,7 @@ module Gitlab
.matches_any(path_patterns)
@projects_for_paths = MigrationClasses::Project.joins(:route).where(with_paths)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/421843')
end
end
end
diff --git a/qa/lib/gitlab/page/trials/new.rb b/qa/lib/gitlab/page/trials/new.rb
index b2e6cbdb682..f7aa168e6bf 100644
--- a/qa/lib/gitlab/page/trials/new.rb
+++ b/qa/lib/gitlab/page/trials/new.rb
@@ -9,8 +9,8 @@ module Gitlab
text_field :first_name
text_field :last_name
text_field :company_name
- select :number_of_employees
- text_field :telephone_number
+ select :company_size
+ text_field :phone_number
select :country
select :state
button :continue
diff --git a/qa/lib/gitlab/page/trials/new.stub.rb b/qa/lib/gitlab/page/trials/new.stub.rb
new file mode 100644
index 00000000000..0b3dbaafacc
--- /dev/null
+++ b/qa/lib/gitlab/page/trials/new.stub.rb
@@ -0,0 +1,241 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Page
+ module Trials
+ module New
+ # @note Defined as +text_field :first_name+
+ # @return [String] The text content or value of +first_name+
+ def first_name
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # Set the value of first_name
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # new.first_name = 'value'
+ # end
+ # @param value [String] The value to set.
+ def first_name=(value)
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.first_name_element).to exist
+ # end
+ # @return [Watir::TextField] The raw +TextField+ element
+ def first_name_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_first_name
+ # end
+ # @return [Boolean] true if the +first_name+ element is present on the page
+ def first_name?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +text_field :last_name+
+ # @return [String] The text content or value of +last_name+
+ def last_name
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # Set the value of last_name
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # new.last_name = 'value'
+ # end
+ # @param value [String] The value to set.
+ def last_name=(value)
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.last_name_element).to exist
+ # end
+ # @return [Watir::TextField] The raw +TextField+ element
+ def last_name_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_last_name
+ # end
+ # @return [Boolean] true if the +last_name+ element is present on the page
+ def last_name?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +text_field :company_name+
+ # @return [String] The text content or value of +company_name+
+ def company_name
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # Set the value of company_name
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # new.company_name = 'value'
+ # end
+ # @param value [String] The value to set.
+ def company_name=(value)
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.company_name_element).to exist
+ # end
+ # @return [Watir::TextField] The raw +TextField+ element
+ def company_name_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_company_name
+ # end
+ # @return [Boolean] true if the +company_name+ element is present on the page
+ def company_name?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +select :company_size+
+ # @return [String] The text content or value of +company_size+
+ def company_size
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.company_size_element).to exist
+ # end
+ # @return [Watir::Select] The raw +Select+ element
+ def company_size_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_company_size
+ # end
+ # @return [Boolean] true if the +company_size+ element is present on the page
+ def company_size?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +text_field :phone_number+
+ # @return [String] The text content or value of +phone_number+
+ def phone_number
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # Set the value of phone_number
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # new.phone_number = 'value'
+ # end
+ # @param value [String] The value to set.
+ def phone_number=(value)
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.phone_number_element).to exist
+ # end
+ # @return [Watir::TextField] The raw +TextField+ element
+ def phone_number_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_phone_number
+ # end
+ # @return [Boolean] true if the +phone_number+ element is present on the page
+ def phone_number?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +select :country+
+ # @return [String] The text content or value of +country+
+ def country
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.country_element).to exist
+ # end
+ # @return [Watir::Select] The raw +Select+ element
+ def country_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_country
+ # end
+ # @return [Boolean] true if the +country+ element is present on the page
+ def country?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +select :state+
+ # @return [String] The text content or value of +state+
+ def state
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.state_element).to exist
+ # end
+ # @return [Watir::Select] The raw +Select+ element
+ def state_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_state
+ # end
+ # @return [Boolean] true if the +state+ element is present on the page
+ def state?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +button :continue+
+ # Clicks +continue+
+ def continue
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new.continue_element).to exist
+ # end
+ # @return [Watir::Button] The raw +Button+ element
+ def continue_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::New.perform do |new|
+ # expect(new).to be_continue
+ # end
+ # @return [Boolean] true if the +continue+ element is present on the page
+ def continue?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+ end
+ end
+ end
+end
diff --git a/qa/lib/gitlab/page/trials/select.rb b/qa/lib/gitlab/page/trials/select.rb
index d4cf54805ea..ae807f99c25 100644
--- a/qa/lib/gitlab/page/trials/select.rb
+++ b/qa/lib/gitlab/page/trials/select.rb
@@ -8,7 +8,6 @@ module Gitlab
button :select_group, 'data-testid': 'base-dropdown-toggle'
div :group_dropdown, 'data-testid': 'base-dropdown-menu'
- text_field :new_group_name
button :start_your_free_trial
radio :trial_company
radio :trial_individual
diff --git a/qa/lib/gitlab/page/trials/select.stub.rb b/qa/lib/gitlab/page/trials/select.stub.rb
new file mode 100644
index 00000000000..0c61a58d35c
--- /dev/null
+++ b/qa/lib/gitlab/page/trials/select.stub.rb
@@ -0,0 +1,129 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Page
+ module Trials
+ module Select
+ # @note Defined as +button :select_group+
+ # Clicks +select_group+
+ def select_group
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select.select_group_element).to exist
+ # end
+ # @return [Watir::Button] The raw +Button+ element
+ def select_group_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select).to be_select_group
+ # end
+ # @return [Boolean] true if the +select_group+ element is present on the page
+ def select_group?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :group_dropdown+
+ # @return [String] The text content or value of +group_dropdown+
+ def group_dropdown
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select.group_dropdown_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def group_dropdown_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select).to be_group_dropdown
+ # end
+ # @return [Boolean] true if the +group_dropdown+ element is present on the page
+ def group_dropdown?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +button :start_your_free_trial+
+ # Clicks +start_your_free_trial+
+ def start_your_free_trial
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select.start_your_free_trial_element).to exist
+ # end
+ # @return [Watir::Button] The raw +Button+ element
+ def start_your_free_trial_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select).to be_start_your_free_trial
+ # end
+ # @return [Boolean] true if the +start_your_free_trial+ element is present on the page
+ def start_your_free_trial?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +radio :trial_company+
+ # Clicks +trial_company+
+ def trial_company
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select.trial_company_element).to exist
+ # end
+ # @return [Watir::Radio] The raw +Radio+ element
+ def trial_company_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select).to be_trial_company
+ # end
+ # @return [Boolean] true if the +trial_company+ element is present on the page
+ def trial_company?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +radio :trial_individual+
+ # Clicks +trial_individual+
+ def trial_individual
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select.trial_individual_element).to exist
+ # end
+ # @return [Watir::Radio] The raw +Radio+ element
+ def trial_individual_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Trials::Select.perform do |select|
+ # expect(select).to be_trial_individual
+ # end
+ # @return [Boolean] true if the +trial_individual+ element is present on the page
+ def trial_individual?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/flow/trial.rb b/qa/qa/flow/trial.rb
index 109afeffaa3..9bab98bf027 100644
--- a/qa/qa/flow/trial.rb
+++ b/qa/qa/flow/trial.rb
@@ -7,8 +7,8 @@ module QA
CUSTOMER_TRIAL_INFO = {
company_name: 'QA Test Company',
- number_of_employees: '500 - 1,999',
- telephone_number: '555-555-5555',
+ company_size: '500 - 1,999',
+ phone_number: '555-555-5555',
country: 'United States of America',
state: 'CA'
}.freeze
@@ -16,9 +16,9 @@ module QA
def register_for_trial(group: nil)
Gitlab::Page::Trials::New.perform do |new|
new.company_name = CUSTOMER_TRIAL_INFO[:company_name]
- new.number_of_employees = CUSTOMER_TRIAL_INFO[:number_of_employees]
+ new.company_size = CUSTOMER_TRIAL_INFO[:company_size]
new.country = CUSTOMER_TRIAL_INFO[:country]
- new.telephone_number = CUSTOMER_TRIAL_INFO[:telephone_number]
+ new.phone_number = CUSTOMER_TRIAL_INFO[:phone_number]
new.state = CUSTOMER_TRIAL_INFO[:state]
new.continue
diff --git a/spec/lib/gitlab/database/gitlab_schema_spec.rb b/spec/lib/gitlab/database/gitlab_schema_spec.rb
index 1c864239ae6..14ff1a462e3 100644
--- a/spec/lib/gitlab/database/gitlab_schema_spec.rb
+++ b/spec/lib/gitlab/database/gitlab_schema_spec.rb
@@ -148,7 +148,7 @@ RSpec.describe Gitlab::Database::GitlabSchema, feature_category: :database do
subject { described_class.table_schemas!(tables) }
it 'returns the matched schemas' do
- expect(subject).to match_array %i[gitlab_main gitlab_ci].to_set
+ expect(subject).to match_array %i[gitlab_main_cell gitlab_main gitlab_ci].to_set
end
context 'when one of the tables does not have a matching table schema' do
diff --git a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
index 690a4998b36..dac96a48cb1 100644
--- a/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
+++ b/spec/lib/gitlab/database/no_cross_db_foreign_keys_spec.rb
@@ -14,7 +14,9 @@ RSpec.describe 'cross-database foreign keys' do
'routes.namespace_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/420869
'group_import_states.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421210
'user_group_callouts.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421287
- 'group_import_states.user_id' # https://gitlab.com/gitlab-org/gitlab/-/issues/421210
+ 'group_import_states.user_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421210
+ 'projects.creator_id', # https://gitlab.com/gitlab-org/gitlab/-/issues/421844
+ 'projects.marked_for_deletion_by_user_id' # https://gitlab.com/gitlab-org/gitlab/-/issues/421844
]
end
diff --git a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
index b5e08f58608..f325060e592 100644
--- a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
model: ApplicationRecord,
sql: "SELECT 1 FROM projects",
expectations: {
- gitlab_schemas: "gitlab_main",
+ gitlab_schemas: "gitlab_main_cell",
db_config_name: "main"
}
},
@@ -37,7 +37,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
model: ApplicationRecord,
sql: "SELECT 1 FROM projects LEFT JOIN ci_builds ON ci_builds.project_id=projects.id",
expectations: {
- gitlab_schemas: "gitlab_ci,gitlab_main",
+ gitlab_schemas: "gitlab_ci,gitlab_main_cell",
db_config_name: "main"
}
},
@@ -45,7 +45,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics, query_ana
model: ApplicationRecord,
sql: "SELECT 1 FROM ci_builds LEFT JOIN projects ON ci_builds.project_id=projects.id",
expectations: {
- gitlab_schemas: "gitlab_ci,gitlab_main",
+ gitlab_schemas: "gitlab_ci,gitlab_main_cell",
db_config_name: "main"
}
},
diff --git a/spec/models/concerns/cross_database_modification_spec.rb b/spec/models/concerns/cross_database_modification_spec.rb
index eaebf613cb5..bca37ffa9d9 100644
--- a/spec/models/concerns/cross_database_modification_spec.rb
+++ b/spec/models/concerns/cross_database_modification_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe CrossDatabaseModification do
expect(ApplicationRecord.gitlab_transactions_stack).to be_empty
Project.transaction do
- expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main)
+ expect(ApplicationRecord.gitlab_transactions_stack).to contain_exactly(:gitlab_main_cell)
Project.first
end
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_trigger/update_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_trigger/update_spec.rb
new file mode 100644
index 00000000000..ce6e20c088e
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_trigger/update_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'PipelineTriggerUpdate', feature_category: :continuous_integration do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:project) { build(:project) }
+
+ let(:mutation) { graphql_mutation(:pipeline_trigger_update, params) }
+ let_it_be(:old_description) { "Boring old description." }
+ let(:new_description) { 'Awesome new description!' }
+ let_it_be(:trigger) { create(:ci_trigger, owner: current_user, project: project, description: old_description) }
+
+ let(:params) do
+ {
+ id: trigger.to_global_id.to_s,
+ description: new_description
+ }
+ end
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ context 'when unauthorized' do
+ it_behaves_like 'a mutation on an unauthorized resource'
+ end
+
+ context 'when authorized' do
+ before_all do
+ project.add_owner(current_user)
+ end
+
+ context 'when the params are invalid' do
+ let(:new_description) { nil }
+
+ it_behaves_like 'an invalid argument to the mutation', argument_name: 'description'
+
+ it 'does not update a pipeline trigger token' do
+ expect { subject }.not_to change { trigger }
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'when the params are valid' do
+ it_behaves_like 'a working GraphQL mutation'
+
+ it 'updates the pipeline trigger token' do
+ expect { subject }.to change { trigger.reload.description }.to(new_description)
+
+ expect(graphql_errors).to be_blank
+ end
+
+ it 'returns the updated trigger token' do
+ subject
+
+ expect(graphql_data_at(:pipeline_trigger_update, :pipeline_trigger)).to match a_hash_including(
+ 'owner' => a_hash_including(
+ 'id' => current_user.to_global_id.to_s,
+ 'username' => current_user.username,
+ 'name' => current_user.name
+ ),
+ 'description' => new_description,
+ "canAccessProject" => true,
+ "hasTokenExposed" => true,
+ "lastUsed" => nil
+ )
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/create_ref_service_spec.rb b/spec/services/merge_requests/create_ref_service_spec.rb
index 1d073cd143e..85ac651c1fa 100644
--- a/spec/services/merge_requests/create_ref_service_spec.rb
+++ b/spec/services/merge_requests/create_ref_service_spec.rb
@@ -86,6 +86,9 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
it 'writes the merged result into target_ref', :aggregate_failures do
expect(result[:status]).to eq :success
+ expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
+ expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
match(
[
@@ -104,6 +107,9 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
it 'writes the squashed result', :aggregate_failures do
expect(result[:status]).to eq :success
+ expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
+ expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
match(
[
@@ -125,6 +131,9 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
it 'writes the semi-linear merged result', :aggregate_failures do
expect(result[:status]).to eq :success
+ expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(target_ref).parents[1].sha)
+ expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
match(
[
@@ -147,6 +156,9 @@ RSpec.describe MergeRequests::CreateRefService, feature_category: :merge_trains
it 'writes the rebased merged result', :aggregate_failures do
expect(result[:status]).to eq :success
+ expect(result[:commit_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:source_sha]).to eq(project.repository.commit(target_ref).sha)
+ expect(result[:target_sha]).to eq(project.repository.commit(first_parent_ref).sha)
expect(project.repository.commits(target_ref, limit: 10, order: 'topo').map(&:message)).to(
eq(
[