diff options
72 files changed, 3267 insertions, 892 deletions
diff --git a/.gitlab/ci/review-apps/main.gitlab-ci.yml b/.gitlab/ci/review-apps/main.gitlab-ci.yml index da3a2afcbb6..55d31fe5df7 100644 --- a/.gitlab/ci/review-apps/main.gitlab-ci.yml +++ b/.gitlab/ci/review-apps/main.gitlab-ci.yml @@ -108,7 +108,7 @@ review-deploy: - .review-workflow-base - .review:rules:review-deploy stage: deploy - image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}dtzar/helm-kubectl:3.10.3 + image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}dtzar/helm-kubectl:3.9.3 needs: - review-build-cng - review-delete-deployment # We always want to start from a clean slate (i.e. no helm release, no k8s namespace) diff --git a/.rubocop_todo/style/redundant_self.yml b/.rubocop_todo/style/redundant_self.yml index ae19cf458be..4f5f4fe632f 100644 --- a/.rubocop_todo/style/redundant_self.yml +++ b/.rubocop_todo/style/redundant_self.yml @@ -2,25 +2,7 @@ # Cop supports --autocorrect. Style/RedundantSelf: Exclude: - - 'app/channels/awareness_channel.rb' - - 'app/controllers/application_controller.rb' - - 'app/finders/security/jobs_finder.rb' - - 'app/graphql/types/permission_types/base_permission_type.rb' - - 'app/models/abuse_report.rb' - - 'app/models/analytics/usage_trends/measurement.rb' - - 'app/models/application_record.rb' - 'app/models/application_setting.rb' - - 'app/models/application_setting_implementation.rb' - - 'app/models/audit_event.rb' - - 'app/models/award_emoji.rb' - - 'app/models/board.rb' - - 'app/models/ci/application_record.rb' - - 'app/models/ci/bridge.rb' - - 'app/models/ci/build.rb' - - 'app/models/ci/build_metadata.rb' - - 'app/models/ci/build_runner_session.rb' - - 'app/models/ci/build_trace_chunk.rb' - - 'app/models/ci/deleted_object.rb' - 'app/models/ci/group.rb' - 'app/models/ci/job_artifact.rb' - 'app/models/ci/job_token/project_scope_link.rb' @@ -15,7 +15,7 @@ gem 'bundler-checksum', '~> 0.1.0', path: 'vendor/gems/bundler-checksum', requir # https://gitlab.com/gitlab-org/gitlab/-/issues/375713 gem 'rails', '~> 6.1.7.1' -gem 'bootsnap', '~> 1.15.0', require: false +gem 'bootsnap', '~> 1.16.0', require: false # Pin openssl to match the version bundled with our supported Rubies. # See https://stdgems.org/openssl/#gem-version. @@ -174,9 +174,9 @@ gem 'seed-fu', '~> 2.3.7' gem 'elasticsearch-model', '~> 7.2' gem 'elasticsearch-rails', '~> 7.2', require: 'elasticsearch/rails/instrumentation' gem 'elasticsearch-api', '7.13.3' -gem 'aws-sdk-core', '~> 3.168.4' +gem 'aws-sdk-core', '~> 3.169.0' gem 'aws-sdk-cloudformation', '~> 1' -gem 'aws-sdk-s3', '~> 1.117.2' +gem 'aws-sdk-s3', '~> 1.118.0' gem 'faraday_middleware-aws-sigv4', '~>0.3.0' gem 'typhoeus', '~> 1.4.0' # Used with Elasticsearch to support http keep-alive connections diff --git a/Gemfile.checksum b/Gemfile.checksum index cfc3af02693..5eaded751b0 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -35,11 +35,11 @@ {"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"}, {"name":"awrence","version":"1.1.1","platform":"ruby","checksum":"9be584c97408ed92d5e1ca11740853646fe270de675f2f8dd44e8233226dfc97"}, {"name":"aws-eventstream","version":"1.2.0","platform":"ruby","checksum":"ffa53482c92880b001ff2fb06919b9bb82fd847cbb0fa244985d2ebb6dd0d1df"}, -{"name":"aws-partitions","version":"1.674.0","platform":"ruby","checksum":"f96e70d85490bbabc2d4b911bad62412fa5e0a643701499e59f8e38d4ab69128"}, +{"name":"aws-partitions","version":"1.695.0","platform":"ruby","checksum":"f48ded613316522f5e44905af9c029dc62b43b7acaa917d9322831029ed45174"}, {"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"}, -{"name":"aws-sdk-core","version":"3.168.4","platform":"ruby","checksum":"2c9bf6cb0c19f9d23fe2a9d5eca15381b0b904d19f2dd7801d094528f8632a8c"}, -{"name":"aws-sdk-kms","version":"1.61.0","platform":"ruby","checksum":"fe6f50aed34f38bd421e43fe997780c86beeecef2898573b30ad2467b73f572a"}, -{"name":"aws-sdk-s3","version":"1.117.2","platform":"ruby","checksum":"2159b3cbc45fc4a129f178ce54770023684fad078ce5c0577e8005fe1143ebf6"}, +{"name":"aws-sdk-core","version":"3.169.0","platform":"ruby","checksum":"81e75e70dfd4a17c55554b593ad2de5534b6cab9197cd8e278eb8b0a9ad4051b"}, +{"name":"aws-sdk-kms","version":"1.62.0","platform":"ruby","checksum":"b9111c698d783f3f092dcc6a8b9b7e3f53f00e6e501bdc5a4409afdcaf411a1c"}, +{"name":"aws-sdk-s3","version":"1.118.0","platform":"ruby","checksum":"85358b4e56a4b56bba0b8995127f1f6123929d9eb7007534925b359a4a0433db"}, {"name":"aws-sigv4","version":"1.5.1","platform":"ruby","checksum":"d68c87fff4ee843b4b92b23c7f31f957f254ec6eb064181f7119124aab8b8bb4"}, {"name":"azure-storage-blob","version":"2.0.3","platform":"ruby","checksum":"61b76118843c91776bd24bee22c74adafeb7c4bb3a858a325047dae3b59d0363"}, {"name":"azure-storage-common","version":"2.0.4","platform":"ruby","checksum":"608f4daab0e06b583b73dcffd3246ea39e78056de31630286b0cf97af7d6956b"}, @@ -59,7 +59,7 @@ {"name":"bindata","version":"2.4.11","platform":"ruby","checksum":"c38e0c99ffcd80c10a0a7ae6c8586d2fe26bf245cbefac90bec8764523220f6a"}, {"name":"binding_ninja","version":"0.2.3","platform":"java","checksum":"bbcf70b211d6e397493bf57c249bbec6aaf28fa7dafeb78e447b1b2f0610484f"}, {"name":"binding_ninja","version":"0.2.3","platform":"ruby","checksum":"4a85550a0066ee4721506b4e150857486808e50c9ddfeed04bdc896bb61eca9d"}, -{"name":"bootsnap","version":"1.15.0","platform":"ruby","checksum":"f246bb1152159098f5d5619b92e373c73db77769bf3e0c4b6336feeb934bc8d2"}, +{"name":"bootsnap","version":"1.16.0","platform":"ruby","checksum":"f87410c00f69cd84a6e72a6c4bdba733f800d80d934f4315849d18ca9f288fed"}, {"name":"bootstrap_form","version":"4.2.0","platform":"ruby","checksum":"f578b3c900d2cf15fab641064d357318b29e285bd5fdf090f903727912889710"}, {"name":"browser","version":"5.3.1","platform":"ruby","checksum":"62745301701ff2c6c5d32d077bb12532b20be261929dcb52c6781ed0d5658b3c"}, {"name":"builder","version":"3.2.4","platform":"ruby","checksum":"99caf08af60c8d7f3a6b004029c4c3c0bdaebced6c949165fe98f1db27fbbc10"}, diff --git a/Gemfile.lock b/Gemfile.lock index a7bdfb7c00d..99649e7e36c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -200,19 +200,19 @@ GEM awesome_print (1.9.2) awrence (1.1.1) aws-eventstream (1.2.0) - aws-partitions (1.674.0) + aws-partitions (1.695.0) aws-sdk-cloudformation (1.41.0) aws-sdk-core (~> 3, >= 3.99.0) aws-sigv4 (~> 1.1) - aws-sdk-core (3.168.4) + aws-sdk-core (3.169.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.61.0) + aws-sdk-kms (1.62.0) aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.117.2) + aws-sdk-s3 (1.118.0) aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) @@ -244,7 +244,7 @@ GEM rack (>= 0.9.0) bindata (2.4.11) binding_ninja (0.2.3) - bootsnap (1.15.0) + bootsnap (1.16.0) msgpack (~> 1.2) bootstrap_form (4.2.0) actionpack (>= 5.0) @@ -1599,8 +1599,8 @@ DEPENDENCIES autoprefixer-rails (= 10.2.5.1) awesome_print aws-sdk-cloudformation (~> 1) - aws-sdk-core (~> 3.168.4) - aws-sdk-s3 (~> 1.117.2) + aws-sdk-core (~> 3.169.0) + aws-sdk-s3 (~> 1.118.0) babosa (~> 1.0.4) base32 (~> 0.3.0) batch-loader (~> 2.0.1) @@ -1608,7 +1608,7 @@ DEPENDENCIES benchmark-ips (~> 2.3.0) benchmark-memory (~> 0.1) better_errors (~> 2.9.1) - bootsnap (~> 1.15.0) + bootsnap (~> 1.16.0) bootstrap_form (~> 4.2.0) browser (~> 5.3.1) bullet (~> 7.0.2) diff --git a/app/assets/javascripts/environments/components/environment_form.vue b/app/assets/javascripts/environments/components/environment_form.vue index 1bac0ef1359..ee5d95ae6f0 100644 --- a/app/assets/javascripts/environments/components/environment_form.vue +++ b/app/assets/javascripts/environments/components/environment_form.vue @@ -3,6 +3,10 @@ import { GlButton, GlForm, GlFormGroup, GlFormInput, GlLink, GlSprintf } from '@ import { helpPagePath } from '~/helpers/help_page_helper'; import { isAbsolute } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; +import { + ENVIRONMENT_NEW_HELP_TEXT, + ENVIRONMENT_EDIT_HELP_TEXT, +} from 'ee_else_ce/environments/constants'; export default { components: { @@ -13,6 +17,7 @@ export default { GlLink, GlSprintf, }, + inject: ['protectedEnvironmentSettingsPath'], props: { environment: { required: true, @@ -34,9 +39,8 @@ export default { }, i18n: { header: __('Environments'), - helpMessage: __( - 'Environments allow you to track deployments of your application. %{linkStart}More information%{linkEnd}.', - ), + helpNewMessage: ENVIRONMENT_NEW_HELP_TEXT, + helpEditMessage: ENVIRONMENT_EDIT_HELP_TEXT, nameLabel: __('Name'), nameFeedback: __('This field is required'), nameDisabledHelp: __("You cannot rename an environment after it's created."), @@ -62,6 +66,9 @@ export default { isNameDisabled() { return Boolean(this.environment.id); }, + showEditHelp() { + return this.isNameDisabled && Boolean(this.protectedEnvironmentSettingsPath); + }, valid() { return { name: this.visited.name && this.environment.name !== '', @@ -89,9 +96,14 @@ export default { {{ $options.i18n.header }} </h4> <p class="gl-w-full"> - <gl-sprintf :message="$options.i18n.helpMessage"> + <gl-sprintf + :message="showEditHelp ? $options.i18n.helpEditMessage : $options.i18n.helpNewMessage" + > <template #link="{ content }"> - <gl-link :href="$options.helpPagePath">{{ content }}</gl-link> + <gl-link + :href="showEditHelp ? protectedEnvironmentSettingsPath : $options.helpPagePath" + >{{ content }}</gl-link + > </template> </gl-sprintf> </p> diff --git a/app/assets/javascripts/environments/constants.js b/app/assets/javascripts/environments/constants.js index f010898073c..28424322dd2 100644 --- a/app/assets/javascripts/environments/constants.js +++ b/app/assets/javascripts/environments/constants.js @@ -81,3 +81,9 @@ export const REVIEW_APP_MODAL_I18N = { export const MIN_STALE_ENVIRONMENT_DATE = getDateInPast(new Date(), 3650); // 10 years ago export const MAX_STALE_ENVIRONMENT_DATE = getDateInPast(new Date(), 7); // one week ago + +export const ENVIRONMENT_NEW_HELP_TEXT = __( + 'Environments allow you to track deployments of your application.%{linkStart} More information.%{linkEnd}', +); + +export const ENVIRONMENT_EDIT_HELP_TEXT = ENVIRONMENT_NEW_HELP_TEXT; diff --git a/app/assets/javascripts/environments/edit.js b/app/assets/javascripts/environments/edit.js index dd6680f64bd..a128d2fb3c7 100644 --- a/app/assets/javascripts/environments/edit.js +++ b/app/assets/javascripts/environments/edit.js @@ -7,6 +7,7 @@ export default (el) => provide: { projectEnvironmentsPath: el.dataset.projectEnvironmentsPath, updateEnvironmentPath: el.dataset.updateEnvironmentPath, + protectedEnvironmentSettingsPath: el.dataset.protectedEnvironmentSettingsPath, }, render(h) { return h(EditEnvironment, { diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs.vue b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs.vue new file mode 100644 index 00000000000..72cfc005782 --- /dev/null +++ b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs.vue @@ -0,0 +1,37 @@ +<script> +import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui'; +import CancelJobsModal from './cancel_jobs_modal.vue'; +import { CANCEL_JOBS_MODAL_ID, CANCEL_JOBS_BUTTON_TEXT, CANCEL_BUTTON_TOOLTIP } from './constants'; + +export default { + name: 'CancelJobs', + components: { + GlButton, + CancelJobsModal, + }, + directives: { + GlModal: GlModalDirective, + GlTooltip: GlTooltipDirective, + }, + props: { + url: { + type: String, + required: true, + }, + }, + modalId: CANCEL_JOBS_MODAL_ID, + buttonText: CANCEL_JOBS_BUTTON_TEXT, + buttonTooltip: CANCEL_BUTTON_TOOLTIP, +}; +</script> +<template> + <div> + <gl-button + v-gl-modal="$options.modalId" + v-gl-tooltip="$options.buttonTooltip" + variant="danger" + >{{ $options.buttonText }}</gl-button + > + <cancel-jobs-modal :modal-id="$options.modalId" :url="url" @confirm="$emit('confirm')" /> + </div> +</template> diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue index b608b3b9492..d5857294617 100644 --- a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue +++ b/app/assets/javascripts/pages/admin/jobs/index/components/cancel_jobs_modal.vue @@ -5,10 +5,9 @@ import axios from '~/lib/utils/axios_utils'; import { redirectTo } from '~/lib/utils/url_utility'; import { CANCEL_TEXT, - STOP_JOBS_MODAL_ID, - STOP_JOBS_FAILED_TEXT, - STOP_JOBS_MODAL_TITLE, - STOP_JOBS_WARNING, + CANCEL_JOBS_FAILED_TEXT, + CANCEL_JOBS_MODAL_TITLE, + CANCEL_JOBS_WARNING, PRIMARY_ACTION_TEXT, } from './constants'; @@ -21,6 +20,10 @@ export default { type: String, required: true, }, + modalId: { + type: String, + required: true, + }, }, methods: { onSubmit() { @@ -32,7 +35,7 @@ export default { }) .catch((error) => { createAlert({ - message: STOP_JOBS_FAILED_TEXT, + message: CANCEL_JOBS_FAILED_TEXT, }); throw error; }); @@ -45,20 +48,19 @@ export default { cancelAction: { text: CANCEL_TEXT, }, - STOP_JOBS_WARNING, - STOP_JOBS_MODAL_ID, - STOP_JOBS_MODAL_TITLE, + CANCEL_JOBS_WARNING, + CANCEL_JOBS_MODAL_TITLE, }; </script> <template> <gl-modal - :modal-id="$options.STOP_JOBS_MODAL_ID" + :modal-id="modalId" :action-primary="$options.primaryAction" :action-cancel="$options.cancelAction" + :title="$options.CANCEL_JOBS_MODAL_TITLE" @primary="onSubmit" > - <template #modal-title>{{ $options.STOP_JOBS_MODAL_TITLE }}</template> - {{ $options.STOP_JOBS_WARNING }} + {{ $options.CANCEL_JOBS_WARNING }} </gl-modal> </template> diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/constants.js b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js index 9e2d464bc4d..cfde1fc0a2b 100644 --- a/app/assets/javascripts/pages/admin/jobs/index/components/constants.js +++ b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js @@ -1,11 +1,12 @@ import { s__, __ } from '~/locale'; -export const STOP_JOBS_MODAL_ID = 'stop-jobs-modal'; -export const STOP_JOBS_MODAL_TITLE = s__('AdminArea|Stop all jobs?'); -export const STOP_JOBS_BUTTON_TEXT = s__('AdminArea|Stop all jobs'); +export const CANCEL_JOBS_MODAL_ID = 'cancel-jobs-modal'; +export const CANCEL_JOBS_MODAL_TITLE = s__('AdminArea|Are you sure?'); +export const CANCEL_JOBS_BUTTON_TEXT = s__('AdminArea|Cancel all jobs'); +export const CANCEL_BUTTON_TOOLTIP = s__('AdminArea|Cancel all running and pending jobs'); export const CANCEL_TEXT = __('Cancel'); -export const STOP_JOBS_FAILED_TEXT = s__('AdminArea|Stopping jobs failed'); -export const PRIMARY_ACTION_TEXT = s__('AdminArea|Stop jobs'); -export const STOP_JOBS_WARNING = s__( - 'AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.', +export const CANCEL_JOBS_FAILED_TEXT = s__('AdminArea|Canceling jobs failed'); +export const PRIMARY_ACTION_TEXT = s__('AdminArea|Yes, proceed'); +export const CANCEL_JOBS_WARNING = s__( + "AdminArea|You're about to cancel all running and pending jobs across this instance. Do you want to proceed?", ); diff --git a/app/assets/javascripts/pages/admin/jobs/index/index.js b/app/assets/javascripts/pages/admin/jobs/index/index.js index c82b186f671..f9bc097da4c 100644 --- a/app/assets/javascripts/pages/admin/jobs/index/index.js +++ b/app/assets/javascripts/pages/admin/jobs/index/index.js @@ -1,31 +1,32 @@ import Vue from 'vue'; import { BV_SHOW_MODAL } from '~/lib/utils/constants'; import Translate from '~/vue_shared/translate'; -import { STOP_JOBS_MODAL_ID } from './components/constants'; -import StopJobsModal from './components/stop_jobs_modal.vue'; +import { CANCEL_JOBS_MODAL_ID } from './components/constants'; +import CancelJobsModal from './components/cancel_jobs_modal.vue'; Vue.use(Translate); function initJobs() { const buttonId = 'js-stop-jobs-button'; - const stopJobsButton = document.getElementById(buttonId); - if (stopJobsButton) { + const cancelJobsButton = document.getElementById(buttonId); + if (cancelJobsButton) { // eslint-disable-next-line no-new new Vue({ - el: `#js-${STOP_JOBS_MODAL_ID}`, + el: `#js-${CANCEL_JOBS_MODAL_ID}`, components: { - StopJobsModal, + CancelJobsModal, }, mounted() { - stopJobsButton.classList.remove('disabled'); - stopJobsButton.addEventListener('click', () => { - this.$root.$emit(BV_SHOW_MODAL, STOP_JOBS_MODAL_ID, `#${buttonId}`); + cancelJobsButton.classList.remove('disabled'); + cancelJobsButton.addEventListener('click', () => { + this.$root.$emit(BV_SHOW_MODAL, CANCEL_JOBS_MODAL_ID, `#${buttonId}`); }); }, render(createElement) { - return createElement(STOP_JOBS_MODAL_ID, { + return createElement(CANCEL_JOBS_MODAL_ID, { props: { - url: stopJobsButton.dataset.url, + url: cancelJobsButton.dataset.url, + modalId: CANCEL_JOBS_MODAL_ID, }, }); }, diff --git a/app/channels/awareness_channel.rb b/app/channels/awareness_channel.rb index cf85e4b3d33..cf7ba0e5aaf 100644 --- a/app/channels/awareness_channel.rb +++ b/app/channels/awareness_channel.rb @@ -15,7 +15,7 @@ class AwarenessChannel < ApplicationCable::Channel # rubocop:disable Gitlab/Name private_class_method :refresh_interval # keep clients updated about session membership - periodically every: self.refresh_interval do + periodically every: refresh_interval do transmit payload end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 36aae42e21f..865cde1b641 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -69,7 +69,7 @@ class ApplicationController < ActionController::Base :masked_page_url def self.endpoint_id_for_action(action_name) - "#{self.name}##{action_name}" + "#{name}##{action_name}" end rescue_from Encoding::CompatibilityError do |exception| diff --git a/app/finders/security/jobs_finder.rb b/app/finders/security/jobs_finder.rb index 6c2090e0509..ef5b63ccd1d 100644 --- a/app/finders/security/jobs_finder.rb +++ b/app/finders/security/jobs_finder.rb @@ -20,7 +20,7 @@ module Security end def initialize(pipeline:, job_types: []) - if self.instance_of?(Security::JobsFinder) + if instance_of?(Security::JobsFinder) raise NotImplementedError, 'This is an abstract class, please instantiate its descendants' end diff --git a/app/graphql/types/permission_types/base_permission_type.rb b/app/graphql/types/permission_types/base_permission_type.rb index 0192af25d0f..d45c61f489b 100644 --- a/app/graphql/types/permission_types/base_permission_type.rb +++ b/app/graphql/types/permission_types/base_permission_type.rb @@ -28,7 +28,7 @@ module Types end def self.define_field_resolver_method(ability) - unless self.respond_to?(ability) + unless respond_to?(ability) define_method ability.to_sym do |*args| Ability.allowed?(context[:current_user], ability, object, args.to_h) end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index e8fc6bc292f..129871ca3fd 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -113,7 +113,7 @@ module GroupsHelper end def render_setting_to_allow_project_access_token_creation?(group) - group.root? && current_user.can?(:admin_setting_to_allow_project_access_token_creation, group) + group.root? && current_user.can?(:admin_setting_to_allow_resource_access_token_creation, group) end def show_thanks_for_purchase_alert?(quantity) diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb index be9d49ab4e2..dbcdfa5e946 100644 --- a/app/models/abuse_report.rb +++ b/app/models/abuse_report.rb @@ -72,9 +72,9 @@ class AbuseReport < ApplicationRecord end def notify - return unless self.persisted? + return unless persisted? - AbuseReportMailer.notify(self.id).deliver_later + AbuseReportMailer.notify(id).deliver_later end private diff --git a/app/models/analytics/usage_trends/measurement.rb b/app/models/analytics/usage_trends/measurement.rb index c1245d8dce7..ddadaf78c8f 100644 --- a/app/models/analytics/usage_trends/measurement.rb +++ b/app/models/analytics/usage_trends/measurement.rb @@ -24,8 +24,8 @@ module Analytics scope :order_by_latest, -> { order(recorded_at: :desc) } scope :with_identifier, ->(identifier) { where(identifier: identifier) } - scope :recorded_after, ->(date) { where(self.model.arel_table[:recorded_at].gteq(date)) if date.present? } - scope :recorded_before, ->(date) { where(self.model.arel_table[:recorded_at].lteq(date)) if date.present? } + scope :recorded_after, ->(date) { where(model.arel_table[:recorded_at].gteq(date)) if date.present? } + scope :recorded_before, ->(date) { where(model.arel_table[:recorded_at].lteq(date)) if date.present? } def self.identifier_query_mapping { diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 198a3653cd3..291375f647c 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -36,7 +36,7 @@ class ApplicationRecord < ActiveRecord::Base end def self.pluck_primary_key - where(nil).pluck(self.primary_key) + where(nil).pluck(primary_key) end def self.safe_ensure_unique(retries: 0) @@ -95,7 +95,7 @@ class ApplicationRecord < ActiveRecord::Base end def self.underscore - Gitlab::SafeRequestStore.fetch("model:#{self}:underscore") { self.to_s.underscore } + Gitlab::SafeRequestStore.fetch("model:#{self}:underscore") { to_s.underscore } end def self.where_exists(query) @@ -111,7 +111,7 @@ class ApplicationRecord < ActiveRecord::Base end def self.cached_column_list - self.column_names.map { |column_name| self.arel_table[column_name] } + column_names.map { |column_name| arel_table[column_name] } end def self.default_select_columns diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index f13b2143cd3..db2c053d12c 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -303,11 +303,11 @@ module ApplicationSettingImplementation end def domain_allowlist_raw - array_to_string(self.domain_allowlist) + array_to_string(domain_allowlist) end def domain_denylist_raw - array_to_string(self.domain_denylist) + array_to_string(domain_denylist) end def domain_allowlist_raw=(values) @@ -323,7 +323,7 @@ module ApplicationSettingImplementation end def outbound_local_requests_allowlist_raw - array_to_string(self.outbound_local_requests_whitelist) + array_to_string(outbound_local_requests_whitelist) end def outbound_local_requests_allowlist_raw=(values) @@ -356,7 +356,7 @@ module ApplicationSettingImplementation end def protected_paths_raw - array_to_string(self.protected_paths) + array_to_string(protected_paths) end def protected_paths_raw=(values) @@ -364,7 +364,7 @@ module ApplicationSettingImplementation end def notes_create_limit_allowlist_raw - array_to_string(self.notes_create_limit_allowlist) + array_to_string(notes_create_limit_allowlist) end def notes_create_limit_allowlist_raw=(values) @@ -372,7 +372,7 @@ module ApplicationSettingImplementation end def users_get_by_id_limit_allowlist_raw - array_to_string(self.users_get_by_id_limit_allowlist) + array_to_string(users_get_by_id_limit_allowlist) end def users_get_by_id_limit_allowlist_raw=(values) @@ -536,7 +536,7 @@ module ApplicationSettingImplementation def set_max_key_restriction!(key_type) attr_name = "#{key_type}_key_restriction" - current = self.attributes[attr_name].to_i + current = attributes[attr_name].to_i return if current == KeyRestrictionValidator::FORBIDDEN @@ -549,7 +549,7 @@ module ApplicationSettingImplementation [min_size, current].max end - self.assign_attributes({ attr_name => new_value }) + assign_attributes({ attr_name => new_value }) end def separate_allowlists(string_array) diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb index 5cc87be388f..0c75f6e8b0b 100644 --- a/app/models/audit_event.rb +++ b/app/models/audit_event.rb @@ -55,7 +55,7 @@ class AuditEvent < ApplicationRecord end def initialize_details - return unless self.has_attribute?(:details) + return unless has_attribute?(:details) self.details = {} if details&.nil? end @@ -82,7 +82,7 @@ class AuditEvent < ApplicationRecord def as_json(options = {}) super(options).tap do |json| - json['ip_address'] = self.ip_address.to_s + json['ip_address'] = ip_address.to_s end end @@ -114,10 +114,10 @@ class AuditEvent < ApplicationRecord def parallel_persist PARALLEL_PERSISTENCE_COLUMNS.each do |name| - original = self[name] || self.details[name] + original = self[name] || details[name] next unless original - self[name] = self.details[name] = original + self[name] = details[name] = original end end diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb index f41f0a8be84..dbc5c7a584e 100644 --- a/app/models/award_emoji.rb +++ b/app/models/award_emoji.rb @@ -55,11 +55,11 @@ class AwardEmoji < ApplicationRecord end def downvote? - self.name == DOWNVOTE_NAME + name == DOWNVOTE_NAME end def upvote? - self.name == UPVOTE_NAME + name == UPVOTE_NAME end def url diff --git a/app/models/board.rb b/app/models/board.rb index 8a7330e7320..2181b2f0545 100644 --- a/app/models/board.rb +++ b/app/models/board.rb @@ -18,7 +18,7 @@ class Board < ApplicationRecord # Sort by case-insensitive name, then ascending ids. This ensures that we will always # get the same list/first board no matter how many other boards are named the same scope :order_by_name_asc, -> { order(arel_table[:name].lower.asc).order(id: :asc) } - scope :first_board, -> { where(id: self.order_by_name_asc.limit(1).select(:id)) } + scope :first_board, -> { where(id: order_by_name_asc.limit(1).select(:id)) } def project_needed? !group diff --git a/app/models/ci/application_record.rb b/app/models/ci/application_record.rb index ea7b1104e36..52f02bfb2fd 100644 --- a/app/models/ci/application_record.rb +++ b/app/models/ci/application_record.rb @@ -13,7 +13,7 @@ module Ci end def self.model_name - @model_name ||= ActiveModel::Name.new(self, nil, self.name.demodulize) + @model_name ||= ActiveModel::Name.new(self, nil, name.demodulize) end end end diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb index 54daff7dbda..697f06fbffd 100644 --- a/app/models/ci/bridge.rb +++ b/app/models/ci/bridge.rb @@ -80,9 +80,9 @@ module Ci def inherit_status_from_downstream!(pipeline) case pipeline.status when 'success' - self.success! + success! when 'failed', 'canceled', 'skipped' - self.drop! + drop! else false end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index ec3aa9d70be..214880f5833 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -386,21 +386,21 @@ module Ci def detailed_status(current_user) Gitlab::Ci::Status::Build::Factory - .new(self.present, current_user) + .new(present, current_user) .fabricate! end def other_manual_actions - pipeline.manual_actions.reject { |action| action.name == self.name } + pipeline.manual_actions.reject { |action| action.name == name } end def other_scheduled_actions - pipeline.scheduled_actions.reject { |action| action.name == self.name } + pipeline.scheduled_actions.reject { |action| action.name == name } end def pages_generator? Gitlab.config.pages.enabled && - self.name == 'pages' + name == 'pages' end def runnable? @@ -456,7 +456,7 @@ module Ci end def retries_count - pipeline.builds.retried.where(name: self.name).count + pipeline.builds.retried.where(name: name).count end override :all_met_to_become_pending? @@ -529,19 +529,19 @@ module Ci end def deployment_job? - has_environment_keyword? && self.environment_action == 'start' + has_environment_keyword? && environment_action == 'start' end def stops_environment? - has_environment_keyword? && self.environment_action == 'stop' + has_environment_keyword? && environment_action == 'stop' end def environment_action - self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options + options.fetch(:environment, {}).fetch(:action, 'start') if options end def environment_tier_from_options - self.options.dig(:environment, :deployment_tier) if self.options + options.dig(:environment, :deployment_tier) if options end def environment_tier @@ -831,7 +831,7 @@ module Ci end def erased? - !self.erased_at.nil? + !erased_at.nil? end def artifacts_expired? @@ -864,8 +864,8 @@ module Ci end def keep_artifacts! - self.update(artifacts_expire_at: nil) - self.job_artifacts.update_all(expire_at: nil) + update(artifacts_expire_at: nil) + job_artifacts.update_all(expire_at: nil) end def artifacts_file_for_type(type) @@ -1096,11 +1096,11 @@ module Ci # without actually loading data. # def all_queuing_entries - ::Ci::PendingBuild.where(build_id: self.id) + ::Ci::PendingBuild.where(build_id: id) end def all_runtime_metadata - ::Ci::RunningBuild.where(build_id: self.id) + ::Ci::RunningBuild.where(build_id: id) end def shared_runner_build? diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb index 5c8ac2adb8d..b294afd405d 100644 --- a/app/models/ci/build_metadata.rb +++ b/app/models/ci/build_metadata.rb @@ -68,7 +68,7 @@ module Ci private def set_build_project - self.project_id ||= self.build.project_id + self.project_id ||= build.project_id end def timeout_with_highest_precedence diff --git a/app/models/ci/build_runner_session.rb b/app/models/ci/build_runner_session.rb index 20c0b04e228..5773b6132be 100644 --- a/app/models/ci/build_runner_session.rb +++ b/app/models/ci/build_runner_session.rb @@ -20,7 +20,7 @@ module Ci validates :url, public_url: { schemes: %w(https) } def terminal_specification - wss_url = Gitlab::UrlHelpers.as_wss(Addressable::URI.escape(self.url)) + wss_url = Gitlab::UrlHelpers.as_wss(Addressable::URI.escape(url)) return {} unless wss_url.present? parsed_wss_url = URI.parse(wss_url) @@ -33,7 +33,7 @@ module Ci port = port.presence || DEFAULT_PORT_NAME service = service.presence || DEFAULT_SERVICE_NAME - parsed_url = URI.parse(Addressable::URI.escape(self.url)) + parsed_url = URI.parse(Addressable::URI.escape(url)) parsed_url.path += "/proxy/#{service}/#{port}/#{path}" subprotocols = subprotocols.presence || ::Ci::BuildRunnerSession::TERMINAL_SUBPROTOCOL diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb index c5f6e54c336..541a8b5bffa 100644 --- a/app/models/ci/build_trace_chunk.rb +++ b/app/models/ci/build_trace_chunk.rb @@ -108,7 +108,7 @@ module Ci raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0 return if offset == size # Skip the following process as it doesn't affect anything - self.append(+"", offset) + append(+"", offset) end def append(new_data, offset) @@ -166,7 +166,7 @@ module Ci raise FailedToPersistDataError, 'Modifed build trace chunk detected' if has_changes_to_save? self.class.with_read_consistency(build) do - self.reset.then(&:unsafe_persist_data!) + reset.then(&:unsafe_persist_data!) end end rescue FailedToObtainLockError @@ -205,9 +205,9 @@ module Ci end def <=>(other) - return unless self.build_id == other.build_id + return unless build_id == other.build_id - self.chunk_index <=> other.chunk_index + chunk_index <=> other.chunk_index end protected diff --git a/app/models/ci/deleted_object.rb b/app/models/ci/deleted_object.rb index d36646aba66..2b5452c803a 100644 --- a/app/models/ci/deleted_object.rb +++ b/app/models/ci/deleted_object.rb @@ -21,7 +21,7 @@ module Ci accumulator << record if record[:store_dir] && record[:file] end - self.insert_all(attributes) if attributes.any? + insert_all(attributes) if attributes.any? end def delete_file_from_storage diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb deleted file mode 100644 index 11f84940c38..00000000000 --- a/app/models/clusters/applications/cert_manager.rb +++ /dev/null @@ -1,129 +0,0 @@ -# frozen_string_literal: true - -module Clusters - module Applications - # DEPRECATED for removal in %14.0 - # See https://gitlab.com/groups/gitlab-org/-/epics/4280 - class CertManager < ApplicationRecord - VERSION = 'v0.10.1' - CRD_VERSION = '0.10' - - self.table_name = 'clusters_applications_cert_managers' - - include ::Clusters::Concerns::ApplicationCore - include ::Clusters::Concerns::ApplicationStatus - include ::Clusters::Concerns::ApplicationVersion - include ::Clusters::Concerns::ApplicationData - - attribute :version, default: VERSION - after_initialize :set_default_email, if: :new_record? - - validates :email, presence: true - - def chart - 'certmanager/cert-manager' - end - - def repository - 'https://charts.jetstack.io' - end - - def install_command - helm_command_module::InstallCommand.new( - name: 'certmanager', - repository: repository, - version: VERSION, - rbac: cluster.platform_kubernetes_rbac?, - chart: chart, - files: files.merge(cluster_issuer_file), - preinstall: pre_install_script, - postinstall: post_install_script - ) - end - - def uninstall_command - helm_command_module::DeleteCommand.new( - name: 'certmanager', - rbac: cluster.platform_kubernetes_rbac?, - files: files, - postdelete: post_delete_script - ) - end - - private - - def set_default_email - self.email ||= self.cluster&.user&.email - end - - def pre_install_script - [ - apply_file("https://raw.githubusercontent.com/jetstack/cert-manager/release-#{CRD_VERSION}/deploy/manifests/00-crds.yaml"), - "kubectl label --overwrite namespace #{Gitlab::Kubernetes::Helm::NAMESPACE} certmanager.k8s.io/disable-validation=true" - ] - end - - def post_install_script - [retry_command(apply_file('/data/helm/certmanager/config/cluster_issuer.yaml'))] - end - - def retry_command(command) - Gitlab::Kubernetes::PodCmd.retry_command(command, times: 90) - end - - def post_delete_script - [ - delete_private_key, - delete_crd('certificates.certmanager.k8s.io'), - delete_crd('certificaterequests.certmanager.k8s.io'), - delete_crd('challenges.certmanager.k8s.io'), - delete_crd('clusterissuers.certmanager.k8s.io'), - delete_crd('issuers.certmanager.k8s.io'), - delete_crd('orders.certmanager.k8s.io') - ].compact - end - - def private_key_name - @private_key_name ||= cluster_issuer_content.dig('spec', 'acme', 'privateKeySecretRef', 'name') - end - - def delete_private_key - return unless private_key_name.present? - - args = %W(secret -n #{Gitlab::Kubernetes::Helm::NAMESPACE} #{private_key_name} --ignore-not-found) - - Gitlab::Kubernetes::KubectlCmd.delete(*args) - end - - def delete_crd(definition) - Gitlab::Kubernetes::KubectlCmd.delete("crd", definition, "--ignore-not-found") - end - - def apply_file(filename) - Gitlab::Kubernetes::KubectlCmd.apply_file(filename) - end - - def cluster_issuer_file - { - 'cluster_issuer.yaml': cluster_issuer_yaml_content - } - end - - def cluster_issuer_yaml_content - YAML.dump(cluster_issuer_content.deep_merge(cluster_issue_overlay)) - end - - def cluster_issuer_content - YAML.safe_load(File.read(cluster_issuer_file_path)) - end - - def cluster_issue_overlay - { "spec" => { "acme" => { "email" => self.email } } } - end - - def cluster_issuer_file_path - Rails.root.join('vendor', 'cert_manager', 'cluster_issuer.yaml') - end - end - end -end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 55dbaf9c6b7..a35ea6ddb46 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -14,7 +14,6 @@ module Clusters APPLICATIONS = { Clusters::Applications::Helm.application_name => Clusters::Applications::Helm, Clusters::Applications::Ingress.application_name => Clusters::Applications::Ingress, - Clusters::Applications::CertManager.application_name => Clusters::Applications::CertManager, Clusters::Applications::Crossplane.application_name => Clusters::Applications::Crossplane, Clusters::Applications::Prometheus.application_name => Clusters::Applications::Prometheus, Clusters::Applications::Runner.application_name => Clusters::Applications::Runner, @@ -57,7 +56,6 @@ module Clusters has_one_cluster_application :helm has_one_cluster_application :ingress - has_one_cluster_application :cert_manager has_one_cluster_application :crossplane has_one_cluster_application :prometheus has_one_cluster_application :runner diff --git a/app/models/ml/experiment.rb b/app/models/ml/experiment.rb index 0a326b0e005..7bb80a170c5 100644 --- a/app/models/ml/experiment.rb +++ b/app/models/ml/experiment.rb @@ -12,6 +12,12 @@ module Ml has_many :candidates, class_name: 'Ml::Candidate' has_many :metadata, class_name: 'Ml::ExperimentMetadata' + scope :with_candidate_count, -> { + left_outer_joins(:candidates) + .select("ml_experiments.*, count(ml_candidates.id) as candidate_count") + .group(:id) + } + has_internal_id :iid, scope: :project class << self diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index b2325b7acac..1dae2682772 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -76,6 +76,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy with_scope :subject condition(:resource_access_token_feature_available) { resource_access_token_feature_available? } condition(:resource_access_token_creation_allowed) { resource_access_token_creation_allowed? } + condition(:resource_access_token_create_feature_available) { resource_access_token_create_feature_available? } with_scope :subject condition(:has_project_with_service_desk_enabled) { @subject.has_project_with_service_desk_enabled? } @@ -277,8 +278,8 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy enable :destroy_resource_access_tokens end - rule { can?(:admin_group) & resource_access_token_creation_allowed }.policy do - enable :admin_setting_to_allow_project_access_token_creation + rule { can?(:admin_group) & resource_access_token_create_feature_available }.policy do + enable :admin_setting_to_allow_resource_access_token_creation end rule { resource_access_token_creation_allowed & can?(:read_resource_access_tokens) }.policy do diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index f2d0cfc42fd..8d858ad72d2 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -4,7 +4,7 @@ - add_page_specific_style 'page_bundles/issuable_list' .top-area - = render 'shared/issuable/nav', type: :merge_requests + = render 'shared/issuable/nav', type: :merge_requests, display_count: !@search_timeout_occurred - if current_user .nav-controls - if @can_bulk_update @@ -16,4 +16,7 @@ - if @can_bulk_update = render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :merge_requests -= render 'shared/merge_requests' +- if @search_timeout_occurred + = render 'shared/dashboard/search_timeout_occurred' +- else + = render 'shared/merge_requests' diff --git a/app/views/projects/environments/edit.html.haml b/app/views/projects/environments/edit.html.haml index dcd5fb2574e..7a275b51c74 100644 --- a/app/views/projects/environments/edit.html.haml +++ b/app/views/projects/environments/edit.html.haml @@ -3,4 +3,5 @@ #js-edit-environment{ data: { project_environments_path: project_environments_path(@project), update_environment_path: project_environment_path(@project, @environment), + protected_environment_settings_path: (project_settings_ci_cd_path(@project, anchor: 'js-protected-environments-settings') if @project.licensed_feature_available?(:protected_environments)), environment: environment_data(@environment)} } diff --git a/db/docs/clusters_applications_cert_managers.yml b/db/docs/clusters_applications_cert_managers.yml index 36bc15e045c..78ef851a2c0 100644 --- a/db/docs/clusters_applications_cert_managers.yml +++ b/db/docs/clusters_applications_cert_managers.yml @@ -1,7 +1,5 @@ --- table_name: clusters_applications_cert_managers -classes: -- Clusters::Applications::CertManager feature_categories: - kubernetes_management description: "(Deprecated) A GitLab managed cert-manager installation in a Kubernetes cluster" diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md index 9f0f7e836f7..a7f8f8e712b 100644 --- a/doc/administration/clusters/kas.md +++ b/doc/administration/clusters/kas.md @@ -62,7 +62,7 @@ To enable the agent server on multiple nodes: gitlab_rails['gitlab_kas_enabled'] = true gitlab_rails['gitlab_kas_external_url'] = 'wss://gitlab.example.com/-/kubernetes-agent/' gitlab_rails['gitlab_kas_internal_url'] = 'grpc://kas.internal.gitlab.example.com' - gitlab_rails['gitlab_kas_external_k8s_proxy_url'] = 'https://gitlab.example.com/-/kubernetes-agent/' + gitlab_rails['gitlab_kas_external_k8s_proxy_url'] = 'https://gitlab.example.com/-/kubernetes-agent/k8s-proxy/' ``` In this configuration: diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md index be4ba2b7f99..740a90257bb 100644 --- a/doc/administration/object_storage.md +++ b/doc/administration/object_storage.md @@ -105,7 +105,13 @@ When the consolidated form is: See the section on [ETag mismatch errors](#etag-mismatch) for more details. -**In Omnibus installations:** +#### Use AWS S3 + +The following example uses AWS S3 to enable object storage for all supported services: + +::Tabs + +:::TabTitle Linux package (Omnibus) 1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, substituting the values you want: @@ -116,7 +122,7 @@ See the section on [ETag mismatch errors](#etag-mismatch) for more details. gitlab_rails['object_store']['proxy_download'] = true gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', - 'region' => '<eu-central-1>', + 'region' => 'eu-central-1', 'aws_access_key_id' => '<AWS_ACCESS_KEY_ID>', 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>' } @@ -125,62 +131,231 @@ See the section on [ETag mismatch errors](#etag-mismatch) for more details. 'server_side_encryption' => '<AES256 or aws:kms>', 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>' } - gitlab_rails['object_store']['objects']['artifacts']['bucket'] = '<artifacts>' - gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = '<external-diffs>' - gitlab_rails['object_store']['objects']['lfs']['bucket'] = '<lfs-objects>' - gitlab_rails['object_store']['objects']['uploads']['bucket'] = '<uploads>' - gitlab_rails['object_store']['objects']['packages']['bucket'] = '<packages>' - gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = '<dependency-proxy>' - gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = '<terraform-state>' - gitlab_rails['object_store']['objects']['pages']['bucket'] = '<pages>' + gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' + gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' + gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' + gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' + gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' + gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' + gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' + gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' + gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages' + ``` + + If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit + the AWS access key and secret access key/value pairs. For example: + + ```ruby + gitlab_rails['object_store']['connection'] = { + 'provider' => 'AWS', + 'region' => 'eu-central-1', + 'use_iam_profile' => true + } ``` - If you're using AWS IAM profiles, omit the AWS access key and secret access - key/value pairs. For example: +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `object_storage.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#connection): + + ```yaml + provider: AWS + region: us-east-1 + aws_access_key_id: <AWS_ACCESS_KEY_ID> + aws_secret_access_key: <AWS_SECRET_ACCESS_KEY> + ``` + + If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit + the AWS access key and secret access key/value pairs. For example: + + ```yaml + provider: AWS + region: us-east-1 + use_iam_profile: true + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + object_store: + enabled: false + proxy_download: true + storage_options: {} + # server_side_encryption: + # server_side_encryption_kms_key_id + connection: + secret: gitlab-object-storage + lfs: + enabled: true + proxy_download: true + bucket: gitlab-lfs + connection: {} + # secret: + # key: + artifacts: + enabled: true + proxy_download: true + bucket: gitlab-artifacts + connection: {} + # secret: + # key: + uploads: + enabled: true + proxy_download: true + bucket: gitlab-uploads + connection: {} + # secret: + # key: + packages: + enabled: true + proxy_download: true + bucket: gitlab-packages + connection: {} + externalDiffs: + enabled: true + when: + proxy_download: true + bucket: gitlab-mr-diffs + connection: {} + terraformState: + enabled: true + bucket: gitlab-terraform-state + connection: {} + ciSecureFiles: + enabled: true + bucket: gitlab-ci-secure-files + connection: {} + dependencyProxy: + enabled: true + proxy_download: true + bucket: gitlab-dependency-proxy + connection: {} + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + # Consolidated object storage configuration + gitlab_rails['object_store']['enabled'] = true + gitlab_rails['object_store']['proxy_download'] = true + gitlab_rails['object_store']['connection'] = { + 'provider' => 'AWS', + 'region' => 'eu-central-1', + 'aws_access_key_id' => '<AWS_ACCESS_KEY_ID>', + 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>' + } + # OPTIONAL: The following lines are only needed if server side encryption is required + gitlab_rails['object_store']['storage_options'] = { + 'server_side_encryption' => '<AES256 or aws:kms>', + 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>' + } + gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' + gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' + gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' + gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' + gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' + gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' + gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' + gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' + gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages' + ``` + + If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit + the AWS access key and secret access key/value pairs. For example: ```ruby gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', - 'region' => '<eu-central-1>', + 'region' => 'eu-central-1', 'use_iam_profile' => true } ``` -1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. +1. Save the file and restart GitLab: -**In installations from source:** + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) 1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines: ```yaml - object_store: - enabled: true - proxy_download: true - connection: - provider: AWS - aws_access_key_id: <AWS_ACCESS_KEY_ID> - aws_secret_access_key: <AWS_SECRET_ACCESS_KEY> - region: <eu-central-1> - storage_options: - server_side_encryption: <AES256 or aws:kms> - server_side_encryption_key_kms_id: <arn:aws:kms:xxx> - objects: - artifacts: - bucket: <artifacts> - external_diffs: - bucket: <external-diffs> - lfs: - bucket: <lfs-objects> - uploads: - bucket: <uploads> - packages: - bucket: <packages> - dependency_proxy: - bucket: <dependency_proxy> - terraform_state: - bucket: <terraform> - pages: - bucket: <pages> + production: &base + object_store: + enabled: true + proxy_download: true + connection: + provider: AWS + aws_access_key_id: <AWS_ACCESS_KEY_ID> + aws_secret_access_key: <AWS_SECRET_ACCESS_KEY> + region: eu-central-1 + storage_options: + server_side_encryption: <AES256 or aws:kms> + server_side_encryption_key_kms_id: <arn:aws:kms:xxx> + objects: + artifacts: + bucket: gitlab-artifacts + external_diffs: + bucket: gitlab-mr-diffs + lfs: + bucket: gitlab-lfs + uploads: + bucket: gitlab-uploads + packages: + bucket: gitlab-packages + dependency_proxy: + bucket: gitlab-dependency-proxy + terraform_state: + bucket: gitlab-terraform-state + ci_secure_files: + bucket: gitlab-ci-secure-files + pages: + bucket: gitlab-pages + ``` + + If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit + the AWS access key and secret access key/value pairs. For example: + + ```yaml + connection: + provider: AWS + region: eu-central-1 + use_iam_profile: true ``` 1. Edit `/home/git/gitlab-workhorse/config.toml` and add or amend the following lines: @@ -194,7 +369,25 @@ See the section on [ETag mismatch errors](#etag-mismatch) for more details. aws_secret_access_key = "<AWS_SECRET_ACCESS_KEY>" ``` -1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. + If you’re using [AWS IAM profiles](#using-amazon-instance-profiles), omit + the AWS access key and secret access key/value pairs. For example: + + ```yaml + [object_storage.s3] + use_iam_profile = true + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs #### Common parameters diff --git a/doc/development/documentation/topic_types/task.md b/doc/development/documentation/topic_types/task.md index 0dba3e079b6..cd55fa0b897 100644 --- a/doc/development/documentation/topic_types/task.md +++ b/doc/development/documentation/topic_types/task.md @@ -57,8 +57,70 @@ The issue is created. You can view it by going to **Issues > List**. For the title text, use the structure `active verb` + `noun`. For example, `Create an issue`. -If you have several tasks on a page that share prerequisites, you can use the title -`Prerequisites` and link to it. +If several tasks on a page share prerequisites, you can create a separate +topic with the title `Prerequisites`. + +### When more than one way exists to perform a task + +If more than one way exists to perform a task in the UI, you should +document the primary way only. + +However, sometimes you must document multiple ways to perform a task. +When this situation occurs: + +- Introduce the task as usual. Then, for each way of performing the task, add a topic title. +- Nest the topic titles one level below the task topic title. +- List the tasks in descending order, with the most likely method first. +- Make the task titles as brief as possible. When possible, + use `infinitive` + `noun`. + +Here is an example. + +```markdown +# Change the default branch name + +You can change the default branch name for the instance or group. +If the name is set for the instance, you can override it for a group. + +## For the instance + +Prerequisites: + +- You must have at least the Maintainer role for the instance. + +To change the default branch name for an instance: + +1. Step. +1. Step. + +## For the group + +Prerequisites: + +- You must have at least the Developer role for the group. + +To change the default branch name for a group: + +1. Step. +1. Step. +``` + +### To perform the task in the UI and API + +Usually an API exists to perform the same task that you perform in the UI. + +When this situation occurs: + +- Do not use a separate heading for a one-sentence link to the API. +- Do not include API examples in the **Use GitLab** documentation. API examples + belong in the API documentation. If you have GraphQL examples, put them on + their own page, because the API documentation might move some day. +- Do not mention the API if you do not need to. Users can search for + the API documentation, and extra linking adds clutter. +- If someone feels strongly that you mention the API, at the end + of the UI task, add this sentence: + + `To create an issue, you can also [use the API](link).` ## Task introductions diff --git a/doc/integration/arkose.md b/doc/integration/arkose.md index 9c8f6cdfb6a..36c0784cb94 100644 --- a/doc/integration/arkose.md +++ b/doc/integration/arkose.md @@ -93,17 +93,25 @@ To check if a user failed to sign in because the ArkoseLabs challenge was not so KQL: json.message:"Challenge was not solved" AND json.username:replace_username_here` ``` -## QA tests caveat +## Allowlists -Several GitLab QA test suites need to sign in to the app to test its features. This can conflict -with Arkose Protect as it would identify QA users as being malicious because they are being run with -a headless browser. To work around this, ArkoseLabs has allowlisted the unique token -that serves as QA session's User Agent. While this doesn't guarantee that the session is not -flagged as malicious, the Arkose API returns a specific telltale when we verify the sign in -attempt's token. We are leveraging this telltale to bypass the verification step entirely so that the -test suite doesn't fail. This bypass is done in the `UserVerificationService` class. +To ensure end-to-end QA test suites can pass during staging and production, we've [allowlisted](https://developer.arkoselabs.com/docs/verify-api-v4#creating-allowlists-and-denylists) the [GITLAB_QA_USER_AGENT](https://start.1password.com/open/i?a=LKATQYUATRBRDHRRABEBH4RJ5Y&v=6gq44ckmq23vqk5poqunurdgay&i=u2wvs63affaxzi22gnfbjjw2zm&h=gitlab.1password.com). Each QA user receives an `ALLOWLIST` [risk category](https://developer.arkoselabs.com/docs/risk-score). + +You can find the usage of the allowlist telltale in our [Arkose::VerifyResponse](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/lib/arkose/verify_response.rb#L38) class. ## Feedback Job To help Arkose improve their protection service, we created a daily background job to send them the list of blocked users by us. This job is performed by the `Arkose::BlockedUsersReportWorker` class. + +## Additional resources + +<!-- markdownlint-disable MD044 --> +The [Anti-abuse team](https://about.gitlab.com/handbook/engineering/development/data-science/anti-abuse/#team-members) owns the ArkoseLabs Protect feature. You can join our ArkoseLabs/GitLab collaboration channel on Slack: [#ext-gitlab-arkose](https://gitlab.slack.com/archives/C02SGF6RLPQ). +<!-- markdownlint-enable MD044 --> + +ArkoseLabs also maintains the following resources: + +- [ArkoseLabs portal](https://portal.arkoselabs.com/) +- [ArkoseLabs Zendesk](https://support.arkoselabs.com/) +- [ArkoseLabs documentation](https://developer.arkoselabs.com/docs/documentation-guide) diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md index 07dbe46691b..1dfd9c95a73 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -43,7 +43,7 @@ GitLab supports the following OmniAuth providers. Before you configure the OmniAuth provider, configure the settings that are common for all providers. -Omnibus, Docker, and source | Helm chart | Description | Default value +Linux package, Docker, and self-compiled | Helm chart | Description | Default value ----------------------------|------------|-------------|----------- `allow_single_sign_on` | `allowSingleSignOn` | List of providers that automatically create a GitLab account. The provider names are available in the **OmniAuth provider name** column in the [supported providers table](#supported-providers). | `false`, which means that signing in using your OmniAuth provider account without a pre-existing GitLab account is not allowed. You must create a GitLab account first, and then connect it to your OmniAuth provider account through your profile settings. `auto_link_ldap_user` | `autoLinkLdapUser` | Creates an LDAP identity in GitLab for users that are created through an OmniAuth provider. You can enable this setting if you have [LDAP integration](../administration/auth/ldap/index.md) enabled. Requires the `uid` of the user to be the same in both LDAP and the OmniAuth provider. | `false` @@ -104,6 +104,27 @@ To change the OmniAuth settings: helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab ``` + :::TabTitle Docker + + 1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'twitter'] + gitlab_rails['omniauth_auto_link_ldap_user'] = true + gitlab_rails['omniauth_block_auto_created_users'] = true + ``` + + 1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + :::TabTitle Self-compiled (source) 1. Edit `/home/git/gitlab/config/gitlab.yml`: diff --git a/doc/integration/saml.md b/doc/integration/saml.md index b210a9b9888..24b5e6152a5 100644 --- a/doc/integration/saml.md +++ b/doc/integration/saml.md @@ -23,62 +23,29 @@ For more information on: ## Configure SAML support in GitLab -1. Make sure GitLab is [configured with HTTPS](../install/installation.md#using-https). - -1. On your GitLab server, open the configuration file. - - For Omnibus installations: - - ```shell - sudo editor /etc/gitlab/gitlab.rb - ``` - - For installations from source: - - ```shell - cd /home/git/gitlab +::Tabs - sudo -u git -H editor config/gitlab.yml - ``` +:::TabTitle Linux package (Omnibus) +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/omnibus/settings/ssl/). 1. Edit the [common configuration file settings](omniauth.md#configure-common-settings) to add `saml` as a single sign-on provider. This enables Just-In-Time account provisioning for users who do not have an existing GitLab account. - 1. To allow your users to use SAML to sign up without having to manually create - an account first, add the following values to your configuration. - - For Omnibus installations: + an account first, edit `/etc/gitlab/gitlab.rb`: ```ruby gitlab_rails['omniauth_allow_single_sign_on'] = ['saml'] gitlab_rails['omniauth_block_auto_created_users'] = false ``` - For installations from source: - - ```yaml - omniauth: - enabled: true - allow_single_sign_on: ["saml"] - block_auto_created_users: false - ``` - 1. Optional. You can automatically link SAML users with existing GitLab users if their - email addresses match by adding the following setting. - - For Omnibus installations: + email addresses match by adding the following setting in `/etc/gitlab/gitlab.rb`: ```ruby gitlab_rails['omniauth_auto_link_saml_user'] = true ``` - For installations from source: - - ```yaml - auto_link_saml_user: true - ``` - Alternatively, a user can manually link their SAML identity to an existing GitLab account by [enabling OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user). @@ -91,9 +58,7 @@ For more information on: See your SAML IdP documentation for information on how to make these attributes unchangeable. -1. Add the provider configuration. - - For Omnibus installations: +1. Edit `/etc/gitlab/gitlab.rb` and add the provider configuration: ```ruby gitlab_rails['omniauth_providers'] = [ @@ -111,7 +76,244 @@ For more information on: ] ``` - For installations from source: + Where: + + - `assertion_consumer_service_url`: The GitLab HTTPS endpoint + (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). + - `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint. + For more information on these values, see the + [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). + For more information on other configuration settings, see + [configuring SAML on your IdP](#configure-saml-on-your-idp). + - `idp_sso_target_url`: Your IdP value. + - `issuer`: Change to a unique name, which identifies the application to the IdP. + - `name_identifier_format`: Your IdP value. + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/charts/installation/tls.html). +1. Edit the [common configuration file settings](omniauth.md#configure-common-settings) + to add `saml` as a single sign-on provider. This enables Just-In-Time + account provisioning for users who do not have an existing GitLab account. +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. To allow your users to use SAML to sign up without having to manually create + an account first, edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + enabled: true + allowSingleSignOn: ['saml'] + blockAutoCreatedUsers: true + ``` + +1. Optional. You can automatically link SAML users with existing GitLab users if their + email addresses match by adding the following setting in `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + autoLinkSamlUser: true + ``` + + Alternatively, a user can manually link their SAML identity to an existing GitLab + account by [enabling OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user). + +1. Configure the following attributes so your SAML users cannot change them: + + - [`NameID`](../user/group/saml_sso/index.md#nameid). + - `Email` when used with `omniauth_auto_link_saml_user`. + + If users can change these attributes, they can sign in as other authorized users. + See your SAML IdP documentation for information on how to make these attributes + unchangeable. + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Provider name' # optional label for login button, defaults to "Saml" + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + + Where: + + - `assertion_consumer_service_url`: The GitLab HTTPS endpoint + (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). + - `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint. + For more information on these values, see the + [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). + For more information on other configuration settings, see + [configuring SAML on your IdP](#configure-saml-on-your-idp). + - `idp_sso_target_url`: Your IdP value. + - `issuer`: Change to a unique name, which identifies the application to the IdP. + - `name_identifier_format`: Your IdP value. + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Edit `gitlab_values.yaml` and add the provider configuration: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/omnibus/settings/ssl/). +1. Edit the [common configuration file settings](omniauth.md#configure-common-settings) + to add `saml` as a single sign-on provider. This enables Just-In-Time + account provisioning for users who do not have an existing GitLab account. +1. To allow your users to use SAML to sign up without having to manually create + an account first, edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_allow_single_sign_on'] = ['saml'] + gitlab_rails['omniauth_block_auto_created_users'] = false + ``` + +1. Optional. You can automatically link SAML users with existing GitLab users if their + email addresses match by adding the following setting in `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_auto_link_saml_user'] = true + ``` + + Alternatively, a user can manually link their SAML identity to an existing GitLab + account by [enabling OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user). + +1. Configure the following attributes so your SAML users cannot change them: + + - [`NameID`](../user/group/saml_sso/index.md#nameid). + - `Email` when used with `omniauth_auto_link_saml_user`. + + If users can change these attributes, they can sign in as other authorized users. + See your SAML IdP documentation for information on how to make these attributes + unchangeable. + +1. Edit `docker-compose.yml` and add the provider configuration: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { + name: "saml", + label: "Provider name", # optional label for login button, defaults to "Saml" + args: { + assertion_consumer_service_url: "https://gitlab.example.com/users/auth/saml/callback", + idp_cert_fingerprint: "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8", + idp_sso_target_url: "https://login.example.com/idp", + issuer: "https://gitlab.example.com", + name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" + } + } + ] + ``` + + Where: + + - `assertion_consumer_service_url`: The GitLab HTTPS endpoint + (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). + - `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint. + For more information on these values, see the + [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). + For more information on other configuration settings, see + [configuring SAML on your IdP](#configure-saml-on-your-idp). + - `idp_sso_target_url`: Your IdP value. + - `issuer`: Change to a unique name, which identifies the application to the IdP. + - `name_identifier_format`: Your IdP value. + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Make sure GitLab is [configured with HTTPS](../install/installation.md#using-https). +1. Edit the [common configuration file settings](omniauth.md#configure-common-settings) + to add `saml` as a single sign-on provider. This enables Just-In-Time + account provisioning for users who do not have an existing GitLab account. +1. To allow your users to use SAML to sign up without having to manually create + an account first, edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + enabled: true + allow_single_sign_on: ["saml"] + block_auto_created_users: false + ``` + +1. Optional. You can automatically link SAML users with existing GitLab users if their + email addresses match by adding the following setting in `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + auto_link_saml_user: true + ``` + + Alternatively, a user can manually link their SAML identity to an existing GitLab + account by [enabling OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user). + +1. Configure the following attributes so your SAML users cannot change them: + + - [`NameID`](../user/group/saml_sso/index.md#nameid). + - `Email` when used with `omniauth_auto_link_saml_user`. + + If users can change these attributes, they can sign in as other authorized users. + See your SAML IdP documentation for information on how to make these attributes + unchangeable. + +1. Edit `/home/git/gitlab/config/gitlab.yml` and add the provider configuration: ```yaml omniauth: @@ -129,26 +331,30 @@ For more information on: } ``` -1. Match the value for `assertion_consumer_service_url` to the HTTPS endpoint - of GitLab. To generate the correct value, append `users/auth/saml/callback` to the - HTTPS URL of your GitLab installation. + Where: + + - `assertion_consumer_service_url`: The GitLab HTTPS endpoint + (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). + - `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint. + For more information on these values, see the + [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). + For more information on other configuration settings, see + [configuring SAML on your IdP](#configure-saml-on-your-idp). + - `idp_sso_target_url`: Your IdP value. + - `issuer`: Change to a unique name, which identifies the application to the IdP. + - `name_identifier_format`: Your IdP value. -1. Change the following values to match your IdP: - - `idp_cert_fingerprint`. - - `idp_sso_target_url`. - - `name_identifier_format`. - If you use a `idp_cert_fingerprint`, it must be a SHA1 fingerprint. For more - information on these values, see the - [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). - For more information on other configuration settings, see - [configuring SAML on your IdP](#configure-saml-on-your-idp). +1. Save the file and restart GitLab: -1. Change the value of `issuer` to a unique name, which identifies the application - to the IdP. + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` -1. For the changes to take effect, if you installed: - - Using Omnibus, [reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure). - - From source, [restart GitLab](../administration/restart_gitlab.md#installations-from-source). +::EndTabs ### Register GitLab in your SAML IdP @@ -204,65 +410,229 @@ You can configure GitLab to use multiple SAML IdPs if: [SAML group memberships](#configure-users-based-on-saml-group-membership) and [Group Sync](../user/group/saml_sso/group_sync.md) do not support multiple IdPs. For more information, see [issue 386605](https://gitlab.com/gitlab-org/gitlab/-/issues/386605). -Example provider's configuration for installations from source: - -```yaml -omniauth: - providers: - - { - name: 'saml', # This must match the following name configuration parameter - args: { - name: 'saml', # This is mandatory and must match the provider name - strategy_class: 'OmniAuth::Strategies::SAML', - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_1/callback', # URL must match the name of the provider - ... # Put here all the required arguments similar to a single provider - }, - label: 'Provider 1' # Differentiate the two buttons and providers in the UI - } - - { - name: 'saml1', # This must match the following name configuration parameter - args: { - name: 'saml1', # This is mandatory and must match the provider name - strategy_class: 'OmniAuth::Strategies::SAML', - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback', # URL must match the name of the provider - ... # Put here all the required arguments similar to a single provider - }, - label: 'Provider 2' # Differentiate the two buttons and providers in the UI - } -``` - -Example provider's configuration for Omnibus GitLab installations: - -To allow your users to use SAML to sign up without having to manually create an account from either of the providers, add the following values to your configuration. - -```ruby -gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'saml1'] -``` - -```ruby -gitlab_rails['omniauth_providers'] = [ - { - name: 'saml', # This must match the following name configuration parameter - args: { - name: 'saml', # This is mandatory and must match the provider name - strategy_class: 'OmniAuth::Strategies::SAML', - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_1/callback', # URL must match the name of the provider - ... # Put here all the required arguments similar to a single provider - }, - label: 'Provider 1' # Differentiate the two buttons and providers in the UI - }, - { - name: 'saml1', # This must match the following name configuration parameter - args: { - name: 'saml1', # This is mandatory and must match the provider name - strategy_class: 'OmniAuth::Strategies::SAML', - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback', # URL must match the name of the provider - ... # Put here all the required arguments similar to a single provider - }, - label: 'Provider 2' # Differentiate the two buttons and providers in the UI - } -] -``` +To set up multiple SAML IdPs: + +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { + name: 'saml', # This must match the following name configuration parameter + label: 'Provider 1' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml', # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML', + ... # Put here all the required arguments similar to a single provider + }, + }, + { + name: 'saml_2', # This must match the following name configuration parameter + label: 'Provider 2' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml_2', # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback', # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML', + ... # Put here all the required arguments similar to a single provider + }, + } + ] + ``` + + To allow your users to use SAML to sign up without having to manually create an + account from either of the providers, add the following values to your configuration: + + ```ruby + gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'saml_2'] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers) + for the first SAML provider: + + ```yaml + name: 'saml' # At least one provider must be named 'saml' + label: 'Provider 1' # Differentiate the two buttons and providers in the UI + args: + name: 'saml' # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML' # Mandatory + ... # Put here all the required arguments similar to a single provider + ``` + +1. Put the following content in a file named `saml_2.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers) + for the second SAML provider: + + ```yaml + name: 'saml_2' + label: 'Provider 2' # Differentiate the two buttons and providers in the UI + args: + name: 'saml_2' # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback' # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML' # Mandatory + ... # Put here all the required arguments similar to a single provider + ``` + +1. Optional. Set additional SAML providers by following the same steps. +1. Create the Kubernetes Secrets: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml \ + --from-file=saml=saml.yaml \ + --from-file=saml_2=saml_2.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + - key: saml + - secret: gitlab-saml + - key: saml_2 + ``` + + To allow your users to use SAML to sign up without having to manually create an + account from either of the providers, add the following values to your configuration: + + ```yaml + global: + appConfig: + omniauth: + allowSingleSignOn: ['saml', 'saml_2'] + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'saml1'] + gitlab_rails['omniauth_providers'] = [ + { + name: 'saml', # This must match the following name configuration parameter + label: 'Provider 1' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml', # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML', + ... # Put here all the required arguments similar to a single provider + }, + }, + { + name: 'saml_2', # This must match the following name configuration parameter + label: 'Provider 2' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml_2', # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback', # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML', + ... # Put here all the required arguments similar to a single provider + }, + } + ] + ``` + + To allow your users to use SAML to sign up without having to manually create an + account from either of the providers, add the following values to your configuration: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_allow_single_sign_on'] = ['saml', 'saml_2'] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { + name: 'saml', # This must match the following name configuration parameter + label: 'Provider 1' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml', # This is mandatory and must match the provider name + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', # URL must match the name of the provider + strategy_class: 'OmniAuth::Strategies::SAML', + ... # Put here all the required arguments similar to a single provider + }, + } + - { + name: 'saml_2', # This must match the following name configuration parameter + label: 'Provider 2' # Differentiate the two buttons and providers in the UI + args: { + name: 'saml_2', # This is mandatory and must match the provider name + strategy_class: 'OmniAuth::Strategies::SAML', + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml_2/callback', # URL must match the name of the provider + ... # Put here all the required arguments similar to a single provider + }, + } + ``` + + To allow your users to use SAML to sign up without having to manually create an + account from either of the providers, add the following values to your configuration: + + ```yaml + production: &base + omniauth: + allow_single_sign_on: ["saml", "saml_2"] + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ## Set up identity providers @@ -388,26 +758,26 @@ Support for these groups depends on: | [Admin](#administrator-groups) | **(FREE SELF)** | Yes | | [Auditor](#auditor-groups) | **(PREMIUM SELF)** | Yes | -### Prerequisites - -You must tell GitLab where to look for group information. To do this, make sure -that your IdP server sends a specific `AttributeStatement` along with the regular -SAML response. For example: - -```xml -<saml:AttributeStatement> - <saml:Attribute Name="Groups"> - <saml:AttributeValue xsi:type="xs:string">Developers</saml:AttributeValue> - <saml:AttributeValue xsi:type="xs:string">Freelancers</saml:AttributeValue> - <saml:AttributeValue xsi:type="xs:string">Admins</saml:AttributeValue> - <saml:AttributeValue xsi:type="xs:string">Auditors</saml:AttributeValue> - </saml:Attribute> -</saml:AttributeStatement> -``` +Prerequisites: -The name of the attribute must contain the groups that a user belongs to. -To tell GitLab where to find these groups, add a `groups_attribute:` -element to your SAML settings. +- You must tell GitLab where to look for group information. To do this, make sure + that your IdP server sends a specific `AttributeStatement` along with the regular + SAML response. For example: + + ```xml + <saml:AttributeStatement> + <saml:Attribute Name="Groups"> + <saml:AttributeValue xsi:type="xs:string">Developers</saml:AttributeValue> + <saml:AttributeValue xsi:type="xs:string">Freelancers</saml:AttributeValue> + <saml:AttributeValue xsi:type="xs:string">Admins</saml:AttributeValue> + <saml:AttributeValue xsi:type="xs:string">Auditors</saml:AttributeValue> + </saml:Attribute> + </saml:AttributeStatement> + ``` + + The name of the attribute must contain the groups that a user belongs to. + To tell GitLab where to find these groups, add a `groups_attribute:` + element to your SAML settings. ### Required groups @@ -423,21 +793,146 @@ membership is required to sign in. If you do not set `required_groups` or leave the setting empty, anyone with proper authentication can use the service. -Example configuration: +::Tabs -```yaml -{ name: 'saml', - label: 'Our SAML Provider', - groups_attribute: 'Groups', - required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], - args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' - } } -``` +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ### External groups @@ -453,19 +948,147 @@ setting. Example configuration: -```yaml -{ name: 'saml', - label: 'Our SAML Provider', - groups_attribute: 'Groups', - external_groups: ['Freelancers'], - args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' - } } -``` +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + external_groups: ['Freelancers'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + external_groups: ['Freelancers'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + external_groups: ['Freelancers'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + external_groups: ['Freelancers'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ### Administrator groups @@ -480,19 +1103,146 @@ the user administrator access. Example configuration: -```yaml -{ name: 'saml', - label: 'Our SAML Provider', - groups_attribute: 'Groups', - admin_groups: ['Admins'], - args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' - } } -``` +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + admin_groups: ['Admins'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + admin_groups: ['Admins'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + admin_groups: ['Admins'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + admin_groups: ['Admins'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ### Auditor groups **(PREMIUM SELF)** @@ -509,19 +1259,146 @@ users with [auditor access](../administration/auditor_users.md). Example configuration: -```yaml -{ name: 'saml', - label: 'Our SAML Provider', - groups_attribute: 'Groups', - auditor_groups: ['Auditors'], - args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' - } } -``` +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + auditor_groups: ['Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + auditor_groups: ['Auditors'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + auditor_groups: ['Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + auditor_groups: ['Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ## Automatically manage SAML Group Sync @@ -535,110 +1412,464 @@ list. 1. Make sure that your IdP is returning the `AuthnContext`. For example: -```xml -<saml:AuthnStatement> - <saml:AuthnContext> - <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:MediumStrongCertificateProtectedTransport</saml:AuthnContextClassRef> - </saml:AuthnContext> -</saml:AuthnStatement> -``` + ```xml + <saml:AuthnStatement> + <saml:AuthnContext> + <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:MediumStrongCertificateProtectedTransport</saml:AuthnContextClassRef> + </saml:AuthnContext> + </saml:AuthnStatement> + ``` 1. Edit your installation configuration to register the SAML authentication method - in the `upstream_two_factor_authn_contexts` list. How you edit your configuration - differs depending on your installation type. + in the `upstream_two_factor_authn_contexts` list. + + ::Tabs + + :::TabTitle Linux package (Omnibus) + + 1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + upstream_two_factor_authn_contexts: + %w( + urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport + urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS + urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN + ), + } + } + ] + ``` + + 1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + + :::TabTitle Helm chart (Kubernetes) + + 1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + upstream_two_factor_authn_contexts: + - 'urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport' + - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS' + - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN' + ``` + + 1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + + 1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + + 1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + + 1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + + :::TabTitle Docker + + 1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + upstream_two_factor_authn_contexts: + %w( + urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport + urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS + urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN + ) + } + } + ] + ``` + + 1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + + :::TabTitle Self-compiled (source) + + 1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + upstream_two_factor_authn_contexts: + [ + 'urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport', + 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS', + 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN' + ] + } + } + ``` + + 1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + + ::EndTabs + +## Validate response signatures + +IdPs must sign SAML responses to ensure that the assertions are not tampered with. + +This prevents user impersonation and privilege escalation when specific group +membership is required. -### Omnibus GitLab installations +### Using `idp_cert_fingerprint` + +You configure the response signature validation using `idp_cert_fingerprint`. +An example configuration: + +::Tabs + +:::TabTitle Linux package (Omnibus) 1. Edit `/etc/gitlab/gitlab.rb`: ```ruby gitlab_rails['omniauth_providers'] = [ - { - name: "saml", + { name: 'saml', + label: 'Our SAML Provider', args: { - assertion_consumer_service_url: "https://gitlab.example.com/users/auth/saml/callback", - idp_cert_fingerprint: "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8", - idp_sso_target_url: "https://login.example.com/idp", - issuer: "https://gitlab.example.com", - name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", - upstream_two_factor_authn_contexts: - %w( - urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport - urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS - urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN - ) - }, - label: "Company Login" # optional label for SAML login button, defaults to "Saml" + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } } ] ``` -1. Save the file and [reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) - GitLab for the changes to take effect. +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` -### Installations from source +:::TabTitle Helm chart (Kubernetes) -1. Edit `config/gitlab.yml`: +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): ```yaml - omniauth: - providers: - - { - name: 'saml', - args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - upstream_two_factor_authn_contexts: - [ - 'urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS', - 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN' - ] - }, - label: 'Company Login' # optional label for SAML login button, defaults to "Saml" - } + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' ``` -1. Save the file and [restart GitLab](../administration/restart_gitlab.md#installations-from-source) - for the changes to take effect. +1. Create the Kubernetes Secret: -## Validate response signatures + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` -IdPs must sign SAML responses to ensure that the assertions are not tampered with. +1. Export the Helm values: -This prevents user impersonation and privilege escalation when specific group -membership is required. + ```shell + helm get values gitlab > gitlab_values.yaml + ``` -You configure the response signature validation using `idp_cert_fingerprint`. -An example configuration: +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', -} -``` +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs + +### Using `idp_cert` If your IdP does not support configuring this using `idp_cert_fingerprint`, you -can instead configure GitLab directly using `idp_cert`. An example configuration: - -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert: '-----BEGIN CERTIFICATE----- - <redacted> - -----END CERTIFICATE-----', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', -} -``` +can instead configure GitLab directly using `idp_cert`. +An example configuration: + +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert: '-----BEGIN CERTIFICATE----- + <redacted> + -----END CERTIFICATE-----', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert: | + -----BEGIN CERTIFICATE----- + <redacted> + -----END CERTIFICATE----- + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert: '-----BEGIN CERTIFICATE----- + <redacted> + -----END CERTIFICATE-----', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert: '-----BEGIN CERTIFICATE----- + <redacted> + -----END CERTIFICATE-----', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs If you have configured the response signature validation incorrectly, you might see error messages such as: @@ -657,24 +1888,92 @@ You can add the `auto_sign_in_with_provider` setting to your GitLab configuratio to automatically redirect you to your SAML server for authentication. This removes the requirement to select an element before actually signing in. -For Omnibus GitLab installations: +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml' + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Export the Helm values: -```ruby -gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml' -``` + ```shell + helm get values gitlab > gitlab_values.yaml + ``` -For installations from source: +1. Edit `gitlab_values.yaml`: -```yaml -omniauth: - auto_sign_in_with_provider: saml -``` + ```yaml + global: + appConfig: + omniauth: + autoSignInWithProvider: 'saml' + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml' + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + auto_sign_in_with_provider: 'saml' + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs Every sign in attempt redirects to the SAML server, so you cannot sign in using local credentials. Make sure at least one of the SAML users has administrator access. -You can also bypass the auto sign-in feature by -`https://gitlab.example.com/users/sign_in?auto_sign_in=false`. +NOTE: +To bypass the auto sign-in setting, append `?auto_sign_in=false` in the sign in +URL, for example: `https://gitlab.example.com/users/sign_in?auto_sign_in=false`. ### Map SAML response attribute names **(FREE SELF)** @@ -690,19 +1989,146 @@ corresponding key in the `info` hash. URI-named Attributes are also supported, f `{ email: ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'] }`. Use this setting to tell GitLab where to look for certain attributes required -to create an account. If your IdP sends the user's email address as `EmailAddress` +to create an account. For example, if your IdP sends the user's email address as `EmailAddress` instead of `email`, let GitLab know by setting it on your configuration: -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - attribute_statements: { email: ['EmailAddress'] } -} -``` +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { email: ['EmailAddress'] } + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + attribute_statements: + email: ['EmailAddress'] + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { email: ['EmailAddress'] } + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { email: ['EmailAddress'] } + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs #### Set a username @@ -711,16 +2137,147 @@ generate the user's GitLab username. Configure `nickname` in `attribute_statements` to specify one or more attributes that contain a user's desired username: -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - attribute_statements: { nickname: ['username'] } -} -``` +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { nickname: ['username'] } + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + attribute_statements: + nickname: ['username'] + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { nickname: ['username'] } + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + attribute_statements: { nickname: ['username'] } + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs This also sets the `username` attribute in your SAML Response to the username in GitLab. @@ -731,34 +2288,152 @@ To allow for a small amount of clock drift, use `allowed_clock_drift` in your settings. You must enter the parameter's value in a number and fraction of seconds. The value given is added to the current time at which the response is validated. -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - attribute_statements: { email: ['EmailAddress'] }, - allowed_clock_drift: 1 # for one second clock drift -} -``` +::Tabs -### Designate a unique attribute for the `uid` +:::TabTitle Linux package (Omnibus) -By default, the `uid` is set as the `name_id` in the SAML response. To designate -a unique attribute for the `uid`, you can set the `uid_attribute`. In the following -example, the value of `uid` attribute in the SAML response is set as the `uid_attribute`. +1. Edit `/etc/gitlab/gitlab.rb`: -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - uid_attribute: 'uid' -} -``` + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + allowed_clock_drift: 1 # for one second clock drift + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + allowed_clock_drift: 1 # for one second clock drift + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + allowed_clock_drift: 1 # for one second clock drift + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + allowed_clock_drift: 1 # for one second clock drift + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs + +### Designate a unique attribute for the `uid` Before setting the `uid` to a unique attribute, make sure that you have configured the following attributes so your SAML users cannot change them: @@ -770,6 +2445,153 @@ If users can change these attributes, they can sign in as other authorized users See your SAML IdP documentation for information on how to make these attributes unchangeable. +By default, the `uid` is set as the `name_id` in the SAML response. To designate +a unique attribute for the `uid`, you can set the `uid_attribute`. In the following +example, the value of `uid` attribute in the SAML response is set as the `uid_attribute`. + +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + uid_attribute: 'uid' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + uid_attribute: 'uid' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + uid_attribute: 'uid' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + uid_attribute: 'uid' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs + ## Assertion encryption (optional) GitLab requires the use of TLS encryption with SAML 2.0. Sometimes, GitLab needs @@ -780,6 +2602,13 @@ additional assertion encryption. For example, if you: Most organizations should not need additional encryption at this layer. +Your IdP encrypts the assertion with the public certificate of GitLab. +GitLab decrypts the `EncryptedAssertion` with its private key. + +NOTE: +This integration uses the `certificate` and `private_key` settings for both +assertion encryption and request signing. + The SAML integration supports `EncryptedAssertion`. To encrypt your assertions, define the private key and the public certificate of your GitLab instance in the SAML settings. @@ -787,24 +2616,154 @@ SAML settings. When you define the key and certificate, replace all line feeds in the key file with `\n`. This makes the key file one long string with no line feeds. -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', - private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' -} -``` +::Tabs -Your IdP encrypts the assertion with the public certificate of GitLab. -GitLab decrypts the `EncryptedAssertion` with its private key. +:::TabTitle Linux package (Omnibus) -NOTE: -This integration uses the `certificate` and `private_key` settings for both -assertion encryption and request signing. +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' + } + } + ] + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + groups_attribute: 'Groups' + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'] + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----' + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' + } + } + ] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + groups_attribute: 'Groups', + required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'], + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' + } + } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs ## Sign SAML authentication requests (optional) @@ -818,24 +2777,173 @@ To implement signing: 1. Configure the signing settings in the `security` section of the configuration. For example: -```yaml -args: { - assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', - idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', - idp_sso_target_url: 'https://login.example.com/idp', - issuer: 'https://gitlab.example.com', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', - certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', - private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----', - security: { - authn_requests_signed: true, # enable signature on AuthNRequest - want_assertions_signed: true, # enable the requirement of signed assertion - metadata_signed: false, # enable signature on Metadata - signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', - digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', - } -} -``` + ::Tabs + + :::TabTitle Linux package (Omnibus) + + 1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----', + security: { + authn_requests_signed: true, # enable signature on AuthNRequest + want_assertions_signed: true, # enable the requirement of signed assertion + metadata_signed: false, # enable signature on Metadata + signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', + } + } + } + ] + ``` + + 1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + + :::TabTitle Helm chart (Kubernetes) + + 1. Put the following content in a file named `saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'saml' + label: 'Our SAML Provider' + args: + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback' + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8' + idp_sso_target_url: 'https://login.example.com/idp' + issuer: 'https://gitlab.example.com' + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent' + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----' + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----' + security: + authn_requests_signed: true # enable signature on AuthNRequest + want_assertions_signed: true # enable the requirement of signed assertion + metadata_signed: false # enable signature on Metadata + signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' + digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256' + ``` + + 1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-saml --from-file=provider=saml.yaml + ``` + + 1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + + 1. Edit `gitlab_values.yaml`: + + ```yaml + global: + appConfig: + omniauth: + providers: + - secret: gitlab-saml + ``` + + 1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + + :::TabTitle Docker + + 1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_providers'] = [ + { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----', + security: { + authn_requests_signed: true, # enable signature on AuthNRequest + want_assertions_signed: true, # enable the requirement of signed assertion + metadata_signed: false, # enable signature on Metadata + signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', + } + } + } + ] + ``` + + 1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + + :::TabTitle Self-compiled (source) + + 1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + omniauth: + providers: + - { name: 'saml', + label: 'Our SAML Provider', + args: { + assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback', + idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8', + idp_sso_target_url: 'https://login.example.com/idp', + issuer: 'https://gitlab.example.com', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', + certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----', + private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----', + security: { + authn_requests_signed: true, # enable signature on AuthNRequest + want_assertions_signed: true, # enable the requirement of signed assertion + metadata_signed: false, # enable signature on Metadata + signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256', + } + } + } + ``` + + 1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + + ::EndTabs GitLab then: @@ -877,24 +2985,108 @@ self-managed instance. To configure group SAML SSO: -1. [Configure GitLab with HTTPS](../install/installation.md#using-https). -1. Enable OmniAuth and the `group_saml` provider. +::Tabs - To do this for Omnibus GitLab installations, edit `gitlab.rb`: +:::TabTitle Linux package (Omnibus) + +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/omnibus/settings/ssl/). +1. Edit `/etc/gitlab/gitlab.rb` to enable OmniAuth and the `group_saml` provider: ```ruby gitlab_rails['omniauth_enabled'] = true gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }] ``` - For installations from source, edit `gitlab/config/gitlab.yml`: +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Helm chart (Kubernetes) + +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/charts/installation/tls.html). +1. Put the following content in a file named `group_saml.yaml` to be used as a + [Kubernetes Secret](https://docs.gitlab.com/charts/charts/globals.html#providers): + + ```yaml + name: 'group_saml' + ``` + +1. Create the Kubernetes Secret: + + ```shell + kubectl create secret generic -n <namespace> gitlab-group-saml --from-file=provider=group_saml.yaml + ``` + +1. Export the Helm values: + + ```shell + helm get values gitlab > gitlab_values.yaml + ``` + +1. Edit `gitlab_values.yaml` to enable OmniAuth and the `group_saml` provider: + + ```yaml + global: + appConfig: + omniauth: + enabled: true + providers: + - secret: gitlab-group-saml + ``` + +1. Save the file and apply the new values: + + ```shell + helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab + ``` + +:::TabTitle Docker + +1. Make sure GitLab is [configured with HTTPS](https://docs.gitlab.com/omnibus/settings/ssl/). +1. Edit `docker-compose.yml` to enable OmniAuth and the `group_saml` provider: + + ```yaml + version: "3.6" + services: + gitlab: + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['omniauth_enabled'] = true + gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }] + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Make sure GitLab is [configured with HTTPS](../install/installation.md#using-https). +1. Edit `/home/git/gitlab/config/gitlab.yml` to enable OmniAuth and the `group_saml` provider: + + ```yaml + production: &base + omniauth: + enabled: true + providers: + - { name: 'group_saml' } + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` - ```yaml - omniauth: - enabled: true - providers: - - { name: 'group_saml' } - ``` +::EndTabs As a multi-tenant solution, group SAML on a self-managed instance is limited compared to the recommended [instance-wide SAML](../user/group/saml_sso/index.md). Use diff --git a/doc/raketasks/backup_gitlab.md b/doc/raketasks/backup_gitlab.md index 9bf811371fc..d63ef61a99f 100644 --- a/doc/raketasks/backup_gitlab.md +++ b/doc/raketasks/backup_gitlab.md @@ -241,8 +241,6 @@ You can exclude specific directories from the backup by adding the environment v - `repositories` (Git repositories data) - `packages` (Packages) -All wikis are backed up as part of the `repositories` group. Non-existent wikis are skipped during a backup. - NOTE: When [backing up and restoring Helm Charts](https://docs.gitlab.com/charts/architecture/backup-restore.html), there is an additional option `packages`, which refers to any packages managed by the GitLab [package registry](../user/packages/package_registry/index.md). For more information see [command line arguments](https://docs.gitlab.com/charts/architecture/backup-restore.html#command-line-arguments). diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md index bc19acde6f7..6710c147c87 100644 --- a/doc/user/packages/nuget_repository/index.md +++ b/doc/user/packages/nuget_repository/index.md @@ -461,9 +461,15 @@ for more details on what other GitLab CI patterns are demonstrated. ## Troubleshooting +### Clear NuGet cache + To improve performance, NuGet caches files related to a package. If you encounter issues, clear the cache with this command: ```shell nuget locals all -clear ``` + +### `Error publishing` or `Invalid Package: Failed metadata extraction error` messages when trying to publish NuGet packages in a Docker-based GitLab installation + +Webhook requests to local network addresses are blocked to prevent the exploitation of internal web services. If you get `Error publishing` or `Invalid Package` messages when you try to publish NuGet packages, change your network settings to [allow webhook and service requests to the local network](../../../security/webhooks.md#allow-webhook-and-service-requests-to-local-network). diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index a3a5f0ca06a..d4a445edfe2 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -624,8 +624,9 @@ module API merge_request = find_project_merge_request(params[:merge_request_iid]) - # Merge request can not be merged - # because user dont have permissions to push into target branch + # Merge request can not be merged because the user doesn't have + # permissions to push into target branch + # unauthorized! unless merge_request.can_be_merged_by?(current_user) merge_when_pipeline_succeeds = to_boolean(params[:merge_when_pipeline_succeeds]) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f2765a5af91..5d1e2ae5499 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2584,6 +2584,9 @@ msgstr "" msgid "AdminArea|All users created in the instance, including users who are not %{billable_users_link_start}billable users%{billable_users_link_end}." msgstr "" +msgid "AdminArea|Are you sure?" +msgstr "" + msgid "AdminArea|Blocked users" msgstr "" @@ -2596,6 +2599,15 @@ msgstr "" msgid "AdminArea|Breakdown of Non-Billable users" msgstr "" +msgid "AdminArea|Cancel all jobs" +msgstr "" + +msgid "AdminArea|Cancel all running and pending jobs" +msgstr "" + +msgid "AdminArea|Canceling jobs failed" +msgstr "" + msgid "AdminArea|Components" msgstr "" @@ -2668,15 +2680,6 @@ msgstr "" msgid "AdminArea|Stop all jobs" msgstr "" -msgid "AdminArea|Stop all jobs?" -msgstr "" - -msgid "AdminArea|Stop jobs" -msgstr "" - -msgid "AdminArea|Stopping jobs failed" -msgstr "" - msgid "AdminArea|Total Billable users" msgstr "" @@ -2713,7 +2716,10 @@ msgstr "" msgid "AdminArea|View latest users" msgstr "" -msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running." +msgid "AdminArea|Yes, proceed" +msgstr "" + +msgid "AdminArea|You're about to cancel all running and pending jobs across this instance. Do you want to proceed?" msgstr "" msgid "AdminArea|active users + blocked users" @@ -15698,7 +15704,10 @@ msgstr "" msgid "Environments Dashboard" msgstr "" -msgid "Environments allow you to track deployments of your application. %{linkStart}More information%{linkEnd}." +msgid "Environments allow you to track deployments of your application. To protect this environment, go to the CI/CD settings %{linkStart}Protected environments%{linkEnd} section." +msgstr "" + +msgid "Environments allow you to track deployments of your application.%{linkStart} More information.%{linkEnd}" msgstr "" msgid "Environments in %{name}" diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 22a406b3197..6b71d5595c5 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -552,6 +552,53 @@ RSpec.describe GroupsController, factory_default: :keep do expect(assigns(:merge_requests)).to eq [merge_request_2, merge_request_1] end end + + context 'rendering views' do + render_views + + it 'displays MR counts in nav' do + get :merge_requests, params: { id: group.to_param } + + expect(response.body).to have_content('Open 2 Merged 0 Closed 0 All 2') + expect(response.body).not_to have_content('Open Merged Closed All') + end + end + + context 'when an ActiveRecord::QueryCanceled is raised' do + before do + allow_next_instance_of(Gitlab::IssuableMetadata) do |instance| + allow(instance).to receive(:data).and_raise(ActiveRecord::QueryCanceled) + end + end + + it 'sets :search_timeout_occurred' do + get :merge_requests, params: { id: group.to_param } + + expect(response).to have_gitlab_http_status(:ok) + expect(assigns(:search_timeout_occurred)).to eq(true) + end + + it 'logs the exception' do + get :merge_requests, params: { id: group.to_param } + end + + context 'rendering views' do + render_views + + it 'shows error message' do + get :merge_requests, params: { id: group.to_param } + + expect(response.body).to have_content('Too many results to display. Edit your search or add a filter.') + end + + it 'does not display MR counts in nav' do + get :merge_requests, params: { id: group.to_param } + + expect(response.body).to have_content('Open Merged Closed All') + expect(response.body).not_to have_content('Open 0 Merged 0 Closed 0 All 0') + end + end + end end describe 'DELETE #destroy' do diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 078450ef1e8..0647058d63a 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -98,11 +98,6 @@ FactoryBot.define do cluster factory: %i(cluster with_installed_helm provided_by_gcp) end - factory :clusters_applications_cert_manager, class: 'Clusters::Applications::CertManager' do - email { 'admin@example.com' } - cluster factory: %i(cluster with_installed_helm provided_by_gcp) - end - factory :clusters_applications_crossplane, class: 'Clusters::Applications::Crossplane' do stack { 'gcp' } cluster factory: %i(cluster with_installed_helm provided_by_gcp) diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb index f6af9d04ea5..32cd6beb7ea 100644 --- a/spec/factories/clusters/clusters.rb +++ b/spec/factories/clusters/clusters.rb @@ -94,7 +94,6 @@ FactoryBot.define do trait :with_all_applications do application_helm factory: %i(clusters_applications_helm installed) application_ingress factory: %i(clusters_applications_ingress installed) - application_cert_manager factory: %i(clusters_applications_cert_manager installed) application_crossplane factory: %i(clusters_applications_crossplane installed) application_prometheus factory: %i(clusters_applications_prometheus installed) application_runner factory: %i(clusters_applications_runner installed) diff --git a/spec/features/admin/admin_jobs_spec.rb b/spec/features/admin/admin_jobs_spec.rb index f0eaa83f05e..626605868cb 100644 --- a/spec/features/admin/admin_jobs_spec.rb +++ b/spec/features/admin/admin_jobs_spec.rb @@ -28,8 +28,8 @@ RSpec.describe 'Admin Jobs', feature_category: :continuous_integration do expect(page).to have_button 'Stop all jobs' click_button 'Stop all jobs' - expect(page).to have_button 'Stop jobs' - expect(page).to have_content 'Stop all jobs?' + expect(page).to have_button 'Yes, proceed' + expect(page).to have_content 'Are you sure?' end end diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js index 5ea23af4c16..ba4b4db54ff 100644 --- a/spec/frontend/environments/edit_environment_spec.js +++ b/spec/frontend/environments/edit_environment_spec.js @@ -14,6 +14,7 @@ const DEFAULT_OPTS = { provide: { projectEnvironmentsPath: '/projects/environments', updateEnvironmentPath: '/proejcts/environments/1', + protectedEnvironmentSettingsPath: '/projects/1/settings/ci_cd', }, propsData: { environment: { id: '0', name: 'foo', external_url: 'https://foo.example.com' } }, }; diff --git a/spec/frontend/environments/environment_form_spec.js b/spec/frontend/environments/environment_form_spec.js index f1af08bcf32..b9b34bee80f 100644 --- a/spec/frontend/environments/environment_form_spec.js +++ b/spec/frontend/environments/environment_form_spec.js @@ -10,11 +10,14 @@ const DEFAULT_PROPS = { cancelPath: '/cancel', }; +const PROVIDE = { protectedEnvironmentSettingsPath: '/projects/not_real/settings/ci_cd' }; + describe('~/environments/components/form.vue', () => { let wrapper; const createWrapper = (propsData = {}) => mountExtended(EnvironmentForm, { + provide: PROVIDE, propsData: { ...DEFAULT_PROPS, ...propsData, @@ -31,7 +34,7 @@ describe('~/environments/components/form.vue', () => { }); it('links to documentation regarding environments', () => { - const link = wrapper.findByRole('link', { name: 'More information' }); + const link = wrapper.findByRole('link', { name: 'More information.' }); expect(link.attributes('href')).toBe('/help/ci/environments/index.md'); }); @@ -124,6 +127,10 @@ describe('~/environments/components/form.vue', () => { expect(urlInput.element.value).toBe(''); }); + + it('does not show protected environment documentation', () => { + expect(wrapper.findByRole('link', { name: 'Protected environments' }).exists()).toBe(false); + }); }); describe('when an existing environment is being edited', () => { diff --git a/spec/frontend/environments/new_environment_spec.js b/spec/frontend/environments/new_environment_spec.js index 6dd4eea7437..5dd77759391 100644 --- a/spec/frontend/environments/new_environment_spec.js +++ b/spec/frontend/environments/new_environment_spec.js @@ -11,7 +11,10 @@ jest.mock('~/lib/utils/url_utility'); jest.mock('~/flash'); const DEFAULT_OPTS = { - provide: { projectEnvironmentsPath: '/projects/environments' }, + provide: { + projectEnvironmentsPath: '/projects/environments', + protectedEnvironmentSettingsPath: '/projects/not_real/settings/ci_cd', + }, }; describe('~/environments/components/new.vue', () => { diff --git a/spec/frontend/pages/admin/jobs/index/components/stop_jobs_modal_spec.js b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_modal_spec.js index 17669331370..366d148a608 100644 --- a/spec/frontend/pages/admin/jobs/index/components/stop_jobs_modal_spec.js +++ b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_modal_spec.js @@ -4,30 +4,27 @@ import { GlModal } from '@gitlab/ui'; import { TEST_HOST } from 'helpers/test_constants'; import axios from '~/lib/utils/axios_utils'; import { redirectTo } from '~/lib/utils/url_utility'; -import StopJobsModal from '~/pages/admin/jobs/index/components/stop_jobs_modal.vue'; +import CancelJobsModal from '~/pages/admin/jobs/index/components/cancel_jobs_modal.vue'; jest.mock('~/lib/utils/url_utility', () => ({ ...jest.requireActual('~/lib/utils/url_utility'), redirectTo: jest.fn(), })); -describe('stop_jobs_modal.vue', () => { +describe('Cancel jobs modal', () => { const props = { - url: `${TEST_HOST}/stop_jobs_modal.vue/stopAll`, + url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`, + modalId: 'cancel-jobs-modal', }; let wrapper; beforeEach(() => { - wrapper = mount(StopJobsModal, { propsData: props }); - }); - - afterEach(() => { - wrapper.destroy(); + wrapper = mount(CancelJobsModal, { propsData: props }); }); describe('on submit', () => { - it('stops jobs and redirects to overview page', async () => { - const responseURL = `${TEST_HOST}/stop_jobs_modal.vue/jobs`; + it('cancels jobs and redirects to overview page', async () => { + const responseURL = `${TEST_HOST}/cancel_jobs_modal.vue/jobs`; // TODO: We can't use axios-mock-adapter because our current version // does not support responseURL // @@ -47,10 +44,10 @@ describe('stop_jobs_modal.vue', () => { expect(redirectTo).toHaveBeenCalledWith(responseURL); }); - it('displays error if stopping jobs failed', async () => { + it('displays error if canceling jobs failed', async () => { Vue.config.errorHandler = () => {}; // silencing thrown error - const dummyError = new Error('stopping jobs failed'); + const dummyError = new Error('canceling jobs failed'); // TODO: We can't use axios-mock-adapter because our current version // does not support responseURL // diff --git a/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js new file mode 100644 index 00000000000..ec6369e7119 --- /dev/null +++ b/spec/frontend/pages/admin/jobs/index/components/cancel_jobs_spec.js @@ -0,0 +1,57 @@ +import { GlButton } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import { TEST_HOST } from 'helpers/test_constants'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import CancelJobs from '~/pages/admin/jobs/index/components/cancel_jobs.vue'; +import CancelJobsModal from '~/pages/admin/jobs/index/components/cancel_jobs_modal.vue'; +import { + CANCEL_JOBS_MODAL_ID, + CANCEL_BUTTON_TOOLTIP, +} from '~/pages/admin/jobs/index/components/constants'; + +describe('CancelJobs component', () => { + let wrapper; + + const findCancelJobs = () => wrapper.findComponent(CancelJobs); + const findButton = () => wrapper.findComponent(GlButton); + const findModal = () => wrapper.findComponent(CancelJobsModal); + + const createComponent = (props = {}) => { + wrapper = shallowMountExtended(CancelJobs, { + directives: { + GlModal: createMockDirective(), + GlTooltip: createMockDirective(), + }, + propsData: { + url: `${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`, + ...props, + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + it('has correct inputs', () => { + expect(findCancelJobs().props().url).toBe(`${TEST_HOST}/cancel_jobs_modal.vue/cancelAll`); + }); + + it('has correct button variant', () => { + expect(findButton().props().variant).toBe('danger'); + }); + + it('checks that button and modal are connected', () => { + const buttonModalDirective = getBinding(findButton().element, 'gl-modal'); + const modalId = findModal().props('modalId'); + + expect(buttonModalDirective.value).toBe(CANCEL_JOBS_MODAL_ID); + expect(modalId).toBe(CANCEL_JOBS_MODAL_ID); + }); + + it('checks that tooltip is displayed', () => { + const buttonTooltipDirective = getBinding(findButton().element, 'gl-tooltip'); + + expect(buttonTooltipDirective.value).toBe(CANCEL_BUTTON_TOOLTIP); + }); +}); diff --git a/spec/graphql/types/ci/runner_architecture_type_spec.rb b/spec/graphql/types/ci/runner_architecture_type_spec.rb index 60709acfd53..58ec73323c6 100644 --- a/spec/graphql/types/ci/runner_architecture_type_spec.rb +++ b/spec/graphql/types/ci/runner_architecture_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::Ci::RunnerArchitectureType do +RSpec.describe Types::Ci::RunnerArchitectureType, feature_category: :runner do specify { expect(described_class.graphql_name).to eq('RunnerArchitecture') } it 'exposes the expected fields' do diff --git a/spec/graphql/types/ci/runner_platform_type_spec.rb b/spec/graphql/types/ci/runner_platform_type_spec.rb index 29b8e885183..1b0f5a5ec71 100644 --- a/spec/graphql/types/ci/runner_platform_type_spec.rb +++ b/spec/graphql/types/ci/runner_platform_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::Ci::RunnerPlatformType do +RSpec.describe Types::Ci::RunnerPlatformType, feature_category: :runner_fleet do specify { expect(described_class.graphql_name).to eq('RunnerPlatform') } it 'exposes the expected fields' do diff --git a/spec/graphql/types/ci/runner_setup_type_spec.rb b/spec/graphql/types/ci/runner_setup_type_spec.rb index 197e717e964..d3e47b52a80 100644 --- a/spec/graphql/types/ci/runner_setup_type_spec.rb +++ b/spec/graphql/types/ci/runner_setup_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::Ci::RunnerSetupType do +RSpec.describe Types::Ci::RunnerSetupType, feature_category: :runner_fleet do specify { expect(described_class.graphql_name).to eq('RunnerSetup') } it 'exposes the expected fields' do diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index b078d7f5fac..2296d1bea30 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['CiRunner'] do +RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do specify { expect(described_class.graphql_name).to eq('CiRunner') } specify { expect(described_class).to require_graphql_authorizations(:read_runner) } diff --git a/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb b/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb index ef378f3fc5a..ec53e5bd508 100644 --- a/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb +++ b/spec/graphql/types/ci/runner_upgrade_status_enum_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::Ci::RunnerUpgradeStatusEnum do +RSpec.describe Types::Ci::RunnerUpgradeStatusEnum, feature_category: :runner_fleet do let(:model_only_enum_values) { %w[not_processed] } let(:expected_graphql_source_values) do Ci::RunnerVersion.statuses.keys - model_only_enum_values diff --git a/spec/graphql/types/ci/runner_web_url_edge_spec.rb b/spec/graphql/types/ci/runner_web_url_edge_spec.rb index 08718df0a5b..07a9655b3e1 100644 --- a/spec/graphql/types/ci/runner_web_url_edge_spec.rb +++ b/spec/graphql/types/ci/runner_web_url_edge_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Types::Ci::RunnerWebUrlEdge do +RSpec.describe Types::Ci::RunnerWebUrlEdge, feature_category: :runner_fleet do specify { expect(described_class.graphql_name).to eq('RunnerWebUrlEdge') } it 'contains URL attributes' do diff --git a/spec/lib/gitlab/ci/runner_instructions_spec.rb b/spec/lib/gitlab/ci/runner_instructions_spec.rb index dd547a0161a..31c53d4a030 100644 --- a/spec/lib/gitlab/ci/runner_instructions_spec.rb +++ b/spec/lib/gitlab/ci/runner_instructions_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::RunnerInstructions do +RSpec.describe Gitlab::Ci::RunnerInstructions, feature_category: :runner_fleet do using RSpec::Parameterized::TableSyntax let(:params) { {} } diff --git a/spec/lib/gitlab/ci/runner_releases_spec.rb b/spec/lib/gitlab/ci/runner_releases_spec.rb index ad1e9b12b8a..14f3c95ec79 100644 --- a/spec/lib/gitlab/ci/runner_releases_spec.rb +++ b/spec/lib/gitlab/ci/runner_releases_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::RunnerReleases do +RSpec.describe Gitlab::Ci::RunnerReleases, feature_category: :runner_fleet do subject { described_class.instance } let(:runner_releases_url) { 'http://testurl.com/runner_public_releases' } diff --git a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb index 55c3834bfa7..a07e95151d6 100644 --- a/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb +++ b/spec/lib/gitlab/ci/runner_upgrade_check_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do +RSpec.describe Gitlab::Ci::RunnerUpgradeCheck, feature_category: :runner_fleet do using RSpec::Parameterized::TableSyntax subject(:instance) { described_class.new(gitlab_version, runner_releases) } diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb deleted file mode 100644 index 427a99efadd..00000000000 --- a/spec/models/clusters/applications/cert_manager_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Clusters::Applications::CertManager do - let(:cert_manager) { create(:clusters_applications_cert_manager) } - - include_examples 'cluster application core specs', :clusters_applications_cert_manager - include_examples 'cluster application status specs', :clusters_applications_cert_manager - include_examples 'cluster application version specs', :clusters_applications_cert_manager - include_examples 'cluster application initial status specs' - - describe 'default values' do - it { expect(cert_manager.version).to eq(described_class::VERSION) } - it { expect(cert_manager.email).to eq("admin@example.com") } - end - - describe '#can_uninstall?' do - subject { cert_manager.can_uninstall? } - - it { is_expected.to be_truthy } - end - - describe '#install_command' do - let(:cert_email) { 'admin@example.com' } - - let(:cluster_issuer_file) do - file_contents = <<~EOF - --- - apiVersion: certmanager.k8s.io/v1alpha1 - kind: ClusterIssuer - metadata: - name: letsencrypt-prod - spec: - acme: - server: https://acme-v02.api.letsencrypt.org/directory - email: #{cert_email} - privateKeySecretRef: - name: letsencrypt-prod - http01: {} - EOF - - { "cluster_issuer.yaml": file_contents } - end - - subject { cert_manager.install_command } - - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } - - it 'is initialized with cert_manager arguments' do - expect(subject.name).to eq('certmanager') - expect(subject.chart).to eq('certmanager/cert-manager') - expect(subject.repository).to eq('https://charts.jetstack.io') - expect(subject.version).to eq('v0.10.1') - expect(subject).to be_rbac - expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file)) - expect(subject.preinstall).to eq( - [ - 'kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.10/deploy/manifests/00-crds.yaml', - 'kubectl label --overwrite namespace gitlab-managed-apps certmanager.k8s.io/disable-validation=true' - ]) - expect(subject.postinstall).to eq( - [ - "for i in $(seq 1 90); do kubectl apply -f /data/helm/certmanager/config/cluster_issuer.yaml && s=0 && break || s=$?; sleep 1s; echo \"Retrying ($i)...\"; done; (exit $s)" - ]) - end - - context 'for a specific user' do - let(:cert_email) { 'abc@xyz.com' } - - before do - cert_manager.email = cert_email - end - - it 'uses their email to register issuer with certificate provider' do - expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file)) - end - end - - context 'on a non rbac enabled cluster' do - before do - cert_manager.cluster.platform_kubernetes.abac! - end - - it { is_expected.not_to be_rbac } - end - - context 'application failed to install previously' do - let(:cert_manager) { create(:clusters_applications_cert_manager, :errored, version: '0.0.1') } - - it 'is initialized with the locked version' do - expect(subject.version).to eq('v0.10.1') - end - end - end - - describe '#uninstall_command' do - subject { cert_manager.uninstall_command } - - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } - - it 'is initialized with cert_manager arguments' do - expect(subject.name).to eq('certmanager') - expect(subject).to be_rbac - expect(subject.files).to eq(cert_manager.files) - end - - it 'specifies a post delete command to remove custom resource definitions' do - expect(subject.postdelete).to eq( - [ - 'kubectl delete secret -n gitlab-managed-apps letsencrypt-prod --ignore-not-found', - 'kubectl delete crd certificates.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd certificaterequests.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd challenges.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd clusterissuers.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd issuers.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd orders.certmanager.k8s.io --ignore-not-found' - ]) - end - - context 'secret key name is not found' do - before do - allow(File).to receive(:read).and_call_original - expect(File).to receive(:read) - .with(Rails.root.join('vendor', 'cert_manager', 'cluster_issuer.yaml')) - .and_return('key: value') - end - - it 'does not try and delete the secret' do - expect(subject.postdelete).to eq( - [ - 'kubectl delete crd certificates.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd certificaterequests.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd challenges.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd clusterissuers.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd issuers.certmanager.k8s.io --ignore-not-found', - 'kubectl delete crd orders.certmanager.k8s.io --ignore-not-found' - ]) - end - end - end - - describe '#files' do - let(:application) { cert_manager } - let(:values) { subject[:'values.yaml'] } - - subject { application.files } - - it 'includes cert_manager specific keys in the values.yaml file' do - expect(values).to include('ingressShim') - end - end - - describe 'validations' do - it { is_expected.to validate_presence_of(:email) } - end -end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 58a986fd099..2a2e2899d24 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -714,14 +714,13 @@ feature_category: :kubernetes_management do context 'when all applications are created' do let!(:helm) { create(:clusters_applications_helm, cluster: cluster) } let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) } - let!(:cert_manager) { create(:clusters_applications_cert_manager, cluster: cluster) } let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) } let!(:runner) { create(:clusters_applications_runner, cluster: cluster) } let!(:jupyter) { create(:clusters_applications_jupyter, cluster: cluster) } let!(:knative) { create(:clusters_applications_knative, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress, cert_manager, prometheus, runner, jupyter, knative) + is_expected.to contain_exactly(helm, ingress, prometheus, runner, jupyter, knative) end end diff --git a/spec/models/ml/experiment_spec.rb b/spec/models/ml/experiment_spec.rb index 52e9f9217f5..c75331a2ab5 100644 --- a/spec/models/ml/experiment_spec.rb +++ b/spec/models/ml/experiment_spec.rb @@ -57,4 +57,21 @@ RSpec.describe Ml::Experiment do it { is_expected.to be_empty } end end + + describe '#with_candidate_count' do + let_it_be(:exp3) do + create(:ml_experiments, project: exp.project).tap do |e| + create_list(:ml_candidates, 3, experiment: e, user: nil) + create(:ml_candidates, experiment: exp2, user: nil) + end + end + + subject { described_class.with_candidate_count.to_h { |e| [e.id, e.candidate_count] } } + + it 'fetches the candidate count', :aggregate_failures do + expect(subject[exp.id]).to eq(0) + expect(subject[exp2.id]).to eq(1) + expect(subject[exp3.id]).to eq(3) + end + end end diff --git a/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb b/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb index 7cfc2db5a41..1739fb3d8b9 100644 --- a/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb +++ b/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'admin/application_settings/_jira_connect.html.haml' do +RSpec.describe 'admin/application_settings/_jira_connect.html.haml', feature_category: :integrations do let_it_be(:admin) { create(:admin) } let(:application_setting) { build(:application_setting) } diff --git a/workhorse/go.mod b/workhorse/go.mod index 582903f9721..9c740e0fe82 100644 --- a/workhorse/go.mod +++ b/workhorse/go.mod @@ -7,7 +7,7 @@ require ( github.com/BurntSushi/toml v1.2.1 github.com/FZambia/sentinel v1.1.1 github.com/alecthomas/chroma/v2 v2.4.0 - github.com/aws/aws-sdk-go v1.44.184 + github.com/aws/aws-sdk-go v1.44.189 github.com/disintegration/imaging v1.6.2 github.com/getsentry/raven-go v0.2.0 github.com/golang-jwt/jwt/v4 v4.4.3 diff --git a/workhorse/go.sum b/workhorse/go.sum index f8b510b88fa..bb1dd5c2b99 100644 --- a/workhorse/go.sum +++ b/workhorse/go.sum @@ -542,8 +542,8 @@ github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.128/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.151/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.44.184 h1:/MggyE66rOImXJKl1HqhLQITvWvqIV7w1Q4MaG6FHUo= -github.com/aws/aws-sdk-go v1.44.184/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.189 h1:9PBrjndH1uL5AN8818qI3duhQ4hgkMuLvqkJlg9MRyk= +github.com/aws/aws-sdk-go v1.44.189/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk= github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= |