diff --git a/db/migrate/20250506035156_add_allow_bypass_placeholder_confirmation_for_enterprise_to_namespace_settings.rb b/db/migrate/20250506035156_add_allow_bypass_placeholder_confirmation_for_enterprise_to_namespace_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..411419b16fa8d3f28c324ad6221c6ddcb9699a37 --- /dev/null +++ b/db/migrate/20250506035156_add_allow_bypass_placeholder_confirmation_for_enterprise_to_namespace_settings.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class AddAllowBypassPlaceholderConfirmationForEnterpriseToNamespaceSettings < Gitlab::Database::Migration[2.3] + milestone '18.1' + + def change + add_column :namespace_settings, :allow_enterprise_bypass_placeholder_confirmation, :boolean, + default: false, null: false + end +end diff --git a/db/schema_migrations/20250506035156 b/db/schema_migrations/20250506035156 new file mode 100644 index 0000000000000000000000000000000000000000..e13a4fdcf789fe0975c90ac04bce4bc426ec09cf --- /dev/null +++ b/db/schema_migrations/20250506035156 @@ -0,0 +1 @@ +2244181d0870519e816e9f8735a44976b3740cc8a7d1a97f709b63d2acef0d7b \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index d4264f8126420b0e447793c851dd10cac3aa04d2..e690bbba93bc63a4b65eacef7fea371449fa827a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -18099,6 +18099,7 @@ CREATE TABLE namespace_settings ( disable_invite_members boolean DEFAULT false NOT NULL, web_based_commit_signing_enabled boolean, lock_web_based_commit_signing_enabled boolean DEFAULT false NOT NULL, + allow_enterprise_bypass_placeholder_confirmation boolean DEFAULT false NOT NULL, CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)), CONSTRAINT check_namespace_settings_security_policies_is_hash CHECK ((jsonb_typeof(security_policies) = 'object'::text)), CONSTRAINT namespace_settings_unique_project_download_limit_alertlist_size CHECK ((cardinality(unique_project_download_limit_alertlist) <= 100)), diff --git a/ee/app/controllers/concerns/ee/groups/params.rb b/ee/app/controllers/concerns/ee/groups/params.rb index ba2f8572bbedbcd235cefe7cf3aecfccde5ca545..f366b8f3d2841ce73884b42cd8af0ff9ebfd5448 100644 --- a/ee/app/controllers/concerns/ee/groups/params.rb +++ b/ee/app/controllers/concerns/ee/groups/params.rb @@ -94,6 +94,8 @@ def group_params_ee can?(current_user, :owner_access, current_group) params_ee << :disable_invite_members end + + params_ee << :allow_enterprise_bypass_placeholder_confirmation if enterprise_bypass_placeholders_allowed? end end # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize @@ -119,6 +121,11 @@ def licensed_ai_features_available? def current_group @group end + + def enterprise_bypass_placeholders_allowed? + ::Feature.enabled?(:importer_user_mapping_allow_bypass_of_confirmation, current_group) && + current_group&.domain_verification_available? + end end end end diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb index b54dfa1779d750fc691e72380aef57c0b809499b..ddf5ab26f4c62321983ae381bc026ca2678928c8 100644 --- a/ee/app/models/ee/namespace.rb +++ b/ee/app/models/ee/namespace.rb @@ -214,6 +214,10 @@ module Namespace delegate :security_policy_management_project, to: :security_orchestration_policy_configuration, allow_nil: true + delegate :allow_enterprise_bypass_placeholder_confirmation, + :allow_enterprise_bypass_placeholder_confirmation=, + to: :namespace_settings, allow_nil: true + before_create :sync_membership_lock_with_parent # Changing the plan or other details may invalidate this cache diff --git a/ee/app/models/ee/namespace_setting.rb b/ee/app/models/ee/namespace_setting.rb index 5daf679e97ba774a3ac123a987e4cdaace1c2588..7f2005ece2288a8af2dc48a69240720ef41cfa53 100644 --- a/ee/app/models/ee/namespace_setting.rb +++ b/ee/app/models/ee/namespace_setting.rb @@ -58,6 +58,7 @@ module NamespaceSetting validates :remove_dormant_members, inclusion: { in: [false] }, if: :subgroup? validates :remove_dormant_members_period, numericality: { only_integer: true, greater_than_or_equal_to: 90, less_than_or_equal_to: 1827 } # 90d - ~5 years + validates :allow_enterprise_bypass_placeholder_confirmation, inclusion: { in: [true, false] } enum :enterprise_users_extensions_marketplace_opt_in_status, ::Enums::WebIde::ExtensionsMarketplaceOptInStatus.statuses, prefix: :enterprise_users_extensions_marketplace @@ -239,6 +240,7 @@ def experiment_features_allowed duo_features_enabled lock_duo_features_enabled enterprise_users_extensions_marketplace_opt_in_status + allow_enterprise_bypass_placeholder_confirmation web_based_commit_signing_enabled lock_web_based_commit_signing_enabled ].freeze diff --git a/ee/app/services/ee/groups/update_service.rb b/ee/app/services/ee/groups/update_service.rb index a104e749555766f99268b27098ff37ee62a47bab..3fbe3a9e98226dd6450b86570a00845915b2b502 100644 --- a/ee/app/services/ee/groups/update_service.rb +++ b/ee/app/services/ee/groups/update_service.rb @@ -7,7 +7,8 @@ module UpdateService EE_SETTINGS_PARAMS = [ :prevent_forking_outside_group, :remove_dormant_members, - :remove_dormant_members_period + :remove_dormant_members_period, + :allow_enterprise_bypass_placeholder_confirmation ].freeze override :execute diff --git a/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb b/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb index 98ccf9be2a811efb3ee66542a3b89f88b0ba0b1b..8e9b94ce9a76ea62e05362ea84faa83db0048f10 100644 --- a/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb +++ b/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb @@ -127,7 +127,7 @@ jwt_ci_cd_job_token_enabled jwt_ci_cd_job_token_opted_out require_dpop_for_manage_api_endpoints disable_invite_members job_token_policies_enabled security_policies duo_nano_features_enabled lock_model_prompt_cache_enabled model_prompt_cache_enabled lock_web_based_commit_signing_enabled - web_based_commit_signing_enabled] + web_based_commit_signing_enabled allow_enterprise_bypass_placeholder_confirmation] columns_to_audit = Namespaces::NamespaceSettingChangesAuditor::EVENT_NAME_PER_COLUMN.keys.map(&:to_s) diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb index bc82a28a983c3f02d481ec54b3c9059b7c74711f..4768cc3c8b1e2861f8c531ab10d119ee57e15b86 100644 --- a/ee/spec/models/ee/namespace_spec.rb +++ b/ee/spec/models/ee/namespace_spec.rb @@ -50,6 +50,8 @@ it { is_expected.to delegate_method(:lock_duo_features_enabled).to(:namespace_settings) } it { is_expected.to delegate_method(:duo_availability).to(:namespace_settings) } it { is_expected.to delegate_method(:security_policy_management_project).to(:security_orchestration_policy_configuration) } + it { is_expected.to delegate_method(:allow_enterprise_bypass_placeholder_confirmation).to(:namespace_settings).allow_nil } + it { is_expected.to delegate_method(:allow_enterprise_bypass_placeholder_confirmation=).to(:namespace_settings).with_arguments(:args) } it { is_expected.to delegate_method(:duo_workflow_mcp_enabled).to(:ai_settings).allow_nil } it { is_expected.to delegate_method(:duo_workflow_mcp_enabled=).to(:ai_settings).with_arguments(:args).allow_nil } diff --git a/ee/spec/requests/groups_controller_spec.rb b/ee/spec/requests/groups_controller_spec.rb index b004ea23446372f106f4a4e4afcc68d87f9bf567..331c94666cd2596fc17ccbe189b1b42d7b2ac0b7 100644 --- a/ee/spec/requests/groups_controller_spec.rb +++ b/ee/spec/requests/groups_controller_spec.rb @@ -643,6 +643,67 @@ end end end + + context 'when setting allow_enterprise_bypass_placeholder_confirmation' do + let(:params) { { group: { allow_enterprise_bypass_placeholder_confirmation: true } } } + + before do + group.add_owner(user) + allow(Group).to receive(:find_by_full_path).and_return(group) + allow(group).to receive(:domain_verification_available?).and_return(true) + end + + it 'successfully updates the setting for top-level group owners' do + expect { request }.to change { + group.reload.namespace_settings.allow_enterprise_bypass_placeholder_confirmation? + }.from(false).to(true) + + expect(response).to have_gitlab_http_status(:found) + end + + context 'and user is not a group owner' do + before do + group.owners.delete(user) + group.add_maintainer(user) + end + + it 'does not change the setting and returns not found' do + expect { request }.not_to change { + group.reload.namespace_settings.allow_enterprise_bypass_placeholder_confirmation? + }.from(false) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when domain verification is not enabled' do + before do + allow(group).to receive(:domain_verification_available?).and_return(false) + end + + it 'does not change the setting' do + expect { request }.not_to change { + group.reload.namespace_settings.allow_enterprise_bypass_placeholder_confirmation? + }.from(false) + + expect(response).to have_gitlab_http_status(:found) + end + end + + context 'when the importer_user_mapping_allow_bypass_of_confirmation feature flag is disabled' do + before do + stub_feature_flags(importer_user_mapping_allow_bypass_of_confirmation: false) + end + + it 'does not change the setting' do + expect { request }.not_to change { + group.reload.namespace_settings.allow_enterprise_bypass_placeholder_confirmation? + }.from(false) + + expect(response).to have_gitlab_http_status(:found) + end + end + end end describe 'PUT #transfer', :saas do