diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml index a4acbe6c885583e332d22becc4568422e5b613b8..3c4fc75dbeee3f1bd50d5f640fc4165587158a92 100644 --- a/app/views/admin/application_settings/_visibility_and_access.html.haml +++ b/app/views/admin/application_settings/_visibility_and_access.html.haml @@ -3,6 +3,7 @@ %fieldset = render 'shared/default_branch_protection', f: f, selected_level: @application_setting.default_branch_protection + = render_if_exists 'admin/application_settings/group_owners_can_manage_default_branch_protection_setting', form: f .form-group = f.label s_('ProjectCreationLevel|Default project creation protection'), class: 'label-bold' diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md index 322dcfc8b9b43601006e23d9a4fc233355649895..d38637e2e9eda3626b1a54d83ffc505cbddb9f8c 100644 --- a/doc/user/admin_area/settings/visibility_and_access_controls.md +++ b/doc/user/admin_area/settings/visibility_and_access_controls.md @@ -28,6 +28,21 @@ For more details, see [Protected branches](../../project/protected_branches.md). To change this setting for a specific group, see [Default branch protection for groups](../../group/index.md#changing-the-default-branch-protection-of-a-group) +### Disable group owners from updating default branch protection **(PREMIUM ONLY)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211944) in GitLab 13.0. + +By default, group owners are allowed to override the branch protection set at the global level. + +In [GitLab Premium or higher](https://about.gitlab.com/pricing/), GitLab administrators can disable this privilege of group owners. + +To do this: + +1. Uncheck the **Allow owners to manage default branch protection in groups** checkbox. + +NOTE: **Note:** +GitLab administrators can still update the default branch protection of a group. + ## Default project creation protection Project creation protection specifies which roles can create projects. diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 941462f84a0905ce9538e3cc289418cdef25c8b8..19c608915eb2fd77b181c85d3388572f083ba69a 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -196,6 +196,9 @@ To change this setting for a specific group: To change this setting globally, see [Default branch protection](../admin_area/settings/visibility_and_access_controls.md#default-branch-protection). +NOTE: **Note:** +In [GitLab Premium or higher](https://about.gitlab.com/pricing/), GitLab administrators can choose to [disable group owners from updating the default branch protection](../admin_area/settings/visibility_and_access_controls.md#disable-group-owners-from-updating-default-branch-protection-premium-only). + ## Add projects to a group There are two different ways to add a new project to a group: diff --git a/ee/app/controllers/ee/admin/application_settings_controller.rb b/ee/app/controllers/ee/admin/application_settings_controller.rb index 8ab66fe22f9c8ad23d0eebf830867bbb073570f4..23316d54e52ada355d1a8d978c5381b8c5245ffc 100644 --- a/ee/app/controllers/ee/admin/application_settings_controller.rb +++ b/ee/app/controllers/ee/admin/application_settings_controller.rb @@ -58,6 +58,10 @@ def visible_application_setting_attributes attrs << :npm_package_requests_forwarding end + if License.feature_available?(:default_branch_protection_restriction_in_groups) + attrs << :group_owners_can_manage_default_branch_protection + end + attrs end diff --git a/ee/app/helpers/ee/application_settings_helper.rb b/ee/app/helpers/ee/application_settings_helper.rb index f96f511dcdeb050cb73d8e7f1f2047c8f241df18..b84dc4407a7651ca0f5673f594e54ee9c8f862dd 100644 --- a/ee/app/helpers/ee/application_settings_helper.rb +++ b/ee/app/helpers/ee/application_settings_helper.rb @@ -92,6 +92,7 @@ def self.possible_licensed_attributes %i[ email_additional_text file_template_project_id + group_owners_can_manage_default_branch_protection default_project_deletion_protection deletion_adjourned_period updating_name_disabled_for_users diff --git a/ee/app/models/license.rb b/ee/app/models/license.rb index cb3c722d011fa0f3a777818ce0f2f75284ebdf18..535bea87386006533bf10832e9dd863a82c3d712 100644 --- a/ee/app/models/license.rb +++ b/ee/app/models/license.rb @@ -59,6 +59,7 @@ class License < ApplicationRecord custom_project_templates cycle_analytics_for_groups db_load_balancing + default_branch_protection_restriction_in_groups default_project_deletion_protection dependency_proxy deploy_board @@ -201,6 +202,7 @@ class License < ApplicationRecord custom_file_templates custom_project_templates db_load_balancing + default_branch_protection_restriction_in_groups elastic_search enterprise_templates extended_audit_events diff --git a/ee/app/policies/ee/base_policy.rb b/ee/app/policies/ee/base_policy.rb index 6c64a3a70f32db69e4c271aab2e454918d6022e3..dc1bd1bf1ba59e414c1e185d1a6897715f4da71c 100644 --- a/ee/app/policies/ee/base_policy.rb +++ b/ee/app/policies/ee/base_policy.rb @@ -18,6 +18,14 @@ module BasePolicy condition(:license_block) { License.block_changes? } rule { auditor }.enable :read_all_resources + + condition(:allow_to_manage_default_branch_protection) do + # When un-licensed: Always allow access. + # When licensed: Allow or deny access based on the + # `group_owners_can_manage_default_branch_protection` setting. + !License.feature_available?(:default_branch_protection_restriction_in_groups) || + ::Gitlab::CurrentSettings.group_owners_can_manage_default_branch_protection + end end end end diff --git a/ee/app/policies/ee/global_policy.rb b/ee/app/policies/ee/global_policy.rb index 7e2b05539eb41a0c732f7fded384603a1103ea52..849333bb616e6d9b9de851dcf290758b8659996b 100644 --- a/ee/app/policies/ee/global_policy.rb +++ b/ee/app/policies/ee/global_policy.rb @@ -26,6 +26,10 @@ module GlobalPolicy rule { ~anonymous }.policy do enable :view_productivity_analytics end + + rule { ~(admin | allow_to_manage_default_branch_protection) }.policy do + prevent :create_group_with_default_branch_protection + end end end end diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb index 58e0795072bf0a0e9ff32b7b023ac94b4194125e..26938081e9cabbea69762347f456edb0184c57be 100644 --- a/ee/app/policies/ee/group_policy.rb +++ b/ee/app/policies/ee/group_policy.rb @@ -177,6 +177,10 @@ module GroupPolicy rule { ~group_timelogs_available }.prevent :read_group_timelogs rule { can?(:read_cluster) & cluster_health_available }.enable :read_cluster_health + + rule { ~(admin | allow_to_manage_default_branch_protection) }.policy do + prevent :update_default_branch_protection + end end override :lookup_access_level! diff --git a/ee/app/views/admin/application_settings/_group_owners_can_manage_default_branch_protection_setting.html.haml b/ee/app/views/admin/application_settings/_group_owners_can_manage_default_branch_protection_setting.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..27ccec99ab99d9158848922d784582866e05bb8d --- /dev/null +++ b/ee/app/views/admin/application_settings/_group_owners_can_manage_default_branch_protection_setting.html.haml @@ -0,0 +1,8 @@ +- return unless License.feature_available?(:default_branch_protection_restriction_in_groups) + +- f = local_assigns.fetch(:form) + +.form-group.form-check + = f.check_box :group_owners_can_manage_default_branch_protection, class: 'form-check-input' + = f.label :group_owners_can_manage_default_branch_protection, class: 'form-check-label' do + = _('Allow owners to manage default branch protection per group') diff --git a/ee/changelogs/unreleased/211944-provide-instance-level-setting-for-default-branch-protection.yml b/ee/changelogs/unreleased/211944-provide-instance-level-setting-for-default-branch-protection.yml new file mode 100644 index 0000000000000000000000000000000000000000..d9cbeacb089851eba014f3486c335fab55c1c2f2 --- /dev/null +++ b/ee/changelogs/unreleased/211944-provide-instance-level-setting-for-default-branch-protection.yml @@ -0,0 +1,6 @@ +--- +title: Provide instance level setting to enable or disable 'default branch protection' + at the group level for group owners +merge_request: 28997 +author: +type: added diff --git a/ee/lib/ee/api/entities/application_setting.rb b/ee/lib/ee/api/entities/application_setting.rb index 6ed6cecda844a4d64299528897b3bb12784cc462..20cd1f5592b5195b4a0147a76b5b5603d144d34c 100644 --- a/ee/lib/ee/api/entities/application_setting.rb +++ b/ee/lib/ee/api/entities/application_setting.rb @@ -19,6 +19,7 @@ module ApplicationSetting expose :deletion_adjourned_period, if: ->(_instance, _opts) { ::License.feature_available?(:adjourned_deletion_for_projects_and_groups) } expose :updating_name_disabled_for_users, if: ->(_instance, _opts) { ::License.feature_available?(:disable_name_update_for_users) } expose :npm_package_requests_forwarding, if: ->(_instance, _opts) { ::License.feature_available?(:packages) } + expose :group_owners_can_manage_default_branch_protection, if: ->(_instance, _opts) { ::License.feature_available?(:default_branch_protection_restriction_in_groups) } end end end diff --git a/ee/lib/ee/api/helpers/settings_helpers.rb b/ee/lib/ee/api/helpers/settings_helpers.rb index 1857c56cee3f6f1f12e00539a8e817e284d68b09..bee0f0f613475825655a059b0a8c956ba26ae7ca 100644 --- a/ee/lib/ee/api/helpers/settings_helpers.rb +++ b/ee/lib/ee/api/helpers/settings_helpers.rb @@ -42,6 +42,7 @@ module SettingsHelpers optional :prevent_merge_requests_author_approval, type: Grape::API::Boolean, desc: 'Disable Merge request author ability to approve request.' optional :prevent_merge_requests_committers_approval, type: Grape::API::Boolean, desc: 'Disable Merge request committer ability to approve request.' optional :npm_package_requests_forwarding, type: Grape::API::Boolean, desc: 'NPM package requests are forwarded to npmjs.org if not found on GitLab.' + optional :group_owners_can_manage_default_branch_protection, type: Grape::API::Boolean, desc: 'Allow owners to manage default branch protection in groups' end end diff --git a/ee/lib/ee/api/settings.rb b/ee/lib/ee/api/settings.rb index 75422b9d20264b57736449f44bcd46e85d6384fe..b10623189935db4c551eaefe49510b223e43bd7e 100644 --- a/ee/lib/ee/api/settings.rb +++ b/ee/lib/ee/api/settings.rb @@ -43,6 +43,10 @@ def filter_attributes_using_license(attrs) attrs = attrs.except(:npm_package_requests_forwarding) end + unless License.feature_available?(:default_branch_protection_restriction_in_groups) + attrs = attrs.except(:group_owners_can_manage_default_branch_protection) + end + attrs end end diff --git a/ee/spec/controllers/admin/application_settings_controller_spec.rb b/ee/spec/controllers/admin/application_settings_controller_spec.rb index c1faf63eea273eec8f9698a2b03c97aa7fe53a2e..a36485edc274ddcbfa5edad3bc7193089d93011a 100644 --- a/ee/spec/controllers/admin/application_settings_controller_spec.rb +++ b/ee/spec/controllers/admin/application_settings_controller_spec.rb @@ -111,6 +111,13 @@ it_behaves_like 'settings for licensed features' end + context 'updating `group_owners_can_manage_default_branch_protection` setting' do + let(:settings) { { group_owners_can_manage_default_branch_protection: false } } + let(:feature) { :default_branch_protection_restriction_in_groups } + + it_behaves_like 'settings for licensed features' + end + context 'updating npm packages request forwarding setting' do let(:settings) { { npm_package_requests_forwarding: true } } let(:feature) { :packages } diff --git a/ee/spec/controllers/ee/groups_controller_spec.rb b/ee/spec/controllers/ee/groups_controller_spec.rb index 4437955857fde1da8d9d58172e3a1dd3176a3240..68182c1df43455fdc948fae4a016ac23f46d6e42 100644 --- a/ee/spec/controllers/ee/groups_controller_spec.rb +++ b/ee/spec/controllers/ee/groups_controller_spec.rb @@ -247,6 +247,67 @@ expect(response).to have_gitlab_http_status(:found) end end + + context 'when creating a group with `default_branch_protection` attribute' do + using RSpec::Parameterized::TableSyntax + + let(:params) do + { group: { name: 'new_group', path: 'new_group', default_branch_protection: Gitlab::Access::PROTECTION_NONE } } + end + + subject { post :create, params: params } + + shared_examples_for 'creates the group with the expected `default_branch_protection` value' do + it 'creates the group with the expected `default_branch_protection` value' do + subject + + expect(response).to have_gitlab_http_status(:found) + expect(Group.last.default_branch_protection).to eq(default_branch_protection) + end + end + + context 'authenticated as an admin', :enable_admin_mode do + let_it_be(:user) { create(:admin) } + + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_NONE + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + sign_in(user) + + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it_behaves_like 'creates the group with the expected `default_branch_protection` value' + end + end + + context 'authenticated a normal user' do + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_FULL + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + sign_in(user) + + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it_behaves_like 'creates the group with the expected `default_branch_protection` value' + end + end + end end describe 'PUT #update' do @@ -369,5 +430,67 @@ end end end + + context 'when `default_branch_protection` is specified' do + using RSpec::Parameterized::TableSyntax + + let(:params) do + { id: group.to_param, group: { default_branch_protection: Gitlab::Access::PROTECTION_NONE } } + end + + subject { put :update, params: params } + + shared_examples_for 'updates the attribute' do + it 'updates the attribute' do + subject + + expect(response).to have_gitlab_http_status(:found) + expect(group.reload.default_branch_protection).to eq(default_branch_protection) + end + end + + context 'authenticated as admin', :enable_admin_mode do + let_it_be(:user) { create(:admin) } + + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_NONE + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + sign_in(user) + + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it_behaves_like 'updates the attribute' + end + end + + context 'authenticated as group owner' do + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_FULL + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + group.add_owner(user) + sign_in(user) + + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it_behaves_like 'updates the attribute' + end + end + end end end diff --git a/ee/spec/policies/global_policy_spec.rb b/ee/spec/policies/global_policy_spec.rb index 2c8410fa4f2e6095126e4d2981a9db1b9cfeffd2..3d6242f406efd59905ee1292f70cc803d0c84768 100644 --- a/ee/spec/policies/global_policy_spec.rb +++ b/ee/spec/policies/global_policy_spec.rb @@ -74,4 +74,102 @@ it { expect(described_class.new(create(:admin), [user])).to be_disallowed(:update_max_pages_size) } end + + describe 'create_group_with_default_branch_protection' do + context 'for an admin' do + let(:current_user) { create(:admin) } + + context 'when the `default_branch_protection_restriction_in_groups` feature is available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: true) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + end + + context 'when the `default_branch_protection_restriction_in_groups` feature is not available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: false) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + end + end + + context 'for a normal user' do + let(:current_user) { create(:user) } + + context 'when the `default_branch_protection_restriction_in_groups` feature is available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: true) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_disallowed(:create_group_with_default_branch_protection) } + end + end + + context 'when the `default_branch_protection_restriction_in_groups` feature is not available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: false) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:create_group_with_default_branch_protection) } + end + end + end + end end diff --git a/ee/spec/policies/group_policy_spec.rb b/ee/spec/policies/group_policy_spec.rb index b78b9983c4c78f51ef1386e6d076e9f0d6fa35db..4e5d865470fbcd71118fe2b099d26ab786652b36 100644 --- a/ee/spec/policies/group_policy_spec.rb +++ b/ee/spec/policies/group_policy_spec.rb @@ -739,4 +739,102 @@ end end end + + describe 'update_default_branch_protection' do + context 'for an admin' do + let(:current_user) { admin } + + context 'when the `default_branch_protection_restriction_in_groups` feature is available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: true) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + end + + context 'when the `default_branch_protection_restriction_in_groups` feature is not available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: false) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + end + end + + context 'for an owner' do + let(:current_user) { owner } + + context 'when the `default_branch_protection_restriction_in_groups` feature is available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: true) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_disallowed(:update_default_branch_protection) } + end + end + + context 'when the `default_branch_protection_restriction_in_groups` feature is not available' do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: false) + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is enabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: true) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + + context 'when the setting `group_owners_can_manage_default_branch_protection` is disabled' do + before do + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: false) + end + + it { is_expected.to be_allowed(:update_default_branch_protection) } + end + end + end + end end diff --git a/ee/spec/requests/api/groups_spec.rb b/ee/spec/requests/api/groups_spec.rb index 28620236fa127006dc7a00bacdb483ab64969c51..6d2579239d60d67dad48ea8f5bfc86f4f09b4388 100644 --- a/ee/spec/requests/api/groups_spec.rb +++ b/ee/spec/requests/api/groups_spec.rb @@ -158,6 +158,60 @@ end end end + + context 'default_branch_protection' do + using RSpec::Parameterized::TableSyntax + + let(:params) { { default_branch_protection: Gitlab::Access::PROTECTION_NONE } } + + context 'authenticated as an admin' do + let(:user) { admin } + + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_NONE + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it 'updates the attribute as expected' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['default_branch_protection']).to eq(default_branch_protection) + end + end + end + + context 'authenticated a normal user' do + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_FULL + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it 'updates the attribute as expected' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['default_branch_protection']).to eq(default_branch_protection) + end + end + end + end end describe "POST /groups" do @@ -197,6 +251,64 @@ end end end + + context 'when creating a group with `default_branch_protection` attribute' do + using RSpec::Parameterized::TableSyntax + + let(:params) { attributes_for_group_api(default_branch_protection: Gitlab::Access::PROTECTION_NONE) } + + subject do + post api("/groups", user), params: params + end + + context 'authenticated as an admin' do + let(:user) { admin } + + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_NONE + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it 'creates the group with the expected `default_branch_protection` value' do + subject + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['default_branch_protection']).to eq(default_branch_protection) + end + end + end + + context 'authenticated a normal user' do + where(:feature_enabled, :setting_enabled, :default_branch_protection) do + false | false | Gitlab::Access::PROTECTION_NONE + false | true | Gitlab::Access::PROTECTION_NONE + true | false | Gitlab::Access::PROTECTION_FULL + false | false | Gitlab::Access::PROTECTION_NONE + end + + with_them do + before do + stub_licensed_features(default_branch_protection_restriction_in_groups: feature_enabled) + stub_ee_application_setting(group_owners_can_manage_default_branch_protection: setting_enabled) + end + + it 'creates the group with the expected `default_branch_protection` value' do + subject + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['default_branch_protection']).to eq(default_branch_protection) + end + end + end + end end describe 'POST /groups/:id/ldap_sync' do diff --git a/ee/spec/requests/api/settings_spec.rb b/ee/spec/requests/api/settings_spec.rb index bbd6aead92c543c85f9d8fbf31e4778615c57dd2..4272fa45e8e5e5cd43983b0a10f0874fede309ba 100644 --- a/ee/spec/requests/api/settings_spec.rb +++ b/ee/spec/requests/api/settings_spec.rb @@ -143,6 +143,13 @@ it_behaves_like 'settings for licensed features' end + context 'group_owners_can_manage_default_branch_protection setting' do + let(:settings) { { group_owners_can_manage_default_branch_protection: false } } + let(:feature) { :default_branch_protection_restriction_in_groups } + + it_behaves_like 'settings for licensed features' + end + context 'deletion adjourned period' do let(:settings) { { deletion_adjourned_period: 5 } } let(:feature) { :adjourned_deletion_for_projects_and_groups } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b8c6a824d85c293496f686a161689e4247ead3c5..cfafd624e6f545291954bfc02b3e66611cdc7c98 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1809,6 +1809,9 @@ msgstr "" msgid "Allow only the selected protocols to be used for Git access." msgstr "" +msgid "Allow owners to manage default branch protection per group" +msgstr "" + msgid "Allow owners to manually add users outside of LDAP" msgstr ""