Commit 4b975914 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch...

Merge branch '211944-provide-instance-level-setting-to-enable-or-disable-the-updation-of-default-branch' into 'master'

Add instance setting to manage default branch protection in groups

See merge request gitlab-org/gitlab!28997
parents aef34407 dee24a2b
......@@ -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'
......
......@@ -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.
......
......@@ -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:
......
......@@ -58,6 +58,10 @@ module EE
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
......
......@@ -92,6 +92,7 @@ module EE
%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
......
......@@ -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
......
......@@ -18,6 +18,14 @@ module EE
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
......@@ -26,6 +26,10 @@ module EE
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
......@@ -177,6 +177,10 @@ module EE
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!
......
- 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')
---
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
......@@ -19,6 +19,7 @@ module EE
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
......
......@@ -42,6 +42,7 @@ module EE
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
......
......@@ -43,6 +43,10 @@ module EE
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
......
......@@ -111,6 +111,13 @@ describe Admin::ApplicationSettingsController do
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 }
......
......@@ -247,6 +247,67 @@ describe GroupsController do
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 @@ describe GroupsController do
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
......@@ -74,4 +74,102 @@ describe GlobalPolicy do
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
......@@ -739,4 +739,102 @@ describe GroupPolicy do
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
......@@ -158,6 +158,60 @@ describe API::Groups do
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 @@ describe API::Groups do
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
......
......@@ -143,6 +143,13 @@ describe API::Settings, 'EE Settings' do
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 }
......
......@@ -1812,6 +1812,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 ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment