diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index b5cbe7b7a857bd33f62c04ed6d0a60ea3a72a67f..6ba559d3e820c083489d96b5cfe4e787665cbc31 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -437,6 +437,12 @@ class ProjectPolicy < BasePolicy enable :read_internal_note enable :read_merge_request enable :export_work_items + enable :read_code + enable :download_code + end + + rule { private_project & planner }.policy do + prevent :create_merge_request_in end rule { can?(:reporter_access) & can?(:create_issue) }.enable :create_incident diff --git a/doc/user/permissions.md b/doc/user/permissions.md index fb78fc324abf5b3d92edfd2a479d3efcc4d4ecbb..3a3334cec9108179174978bf6992cc441e26dd07 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -780,7 +780,7 @@ Project permissions for [repository](project/repository/_index.md) features incl Ultimate license can view private repository content if an administrator (on GitLab Self-Managed or GitLab Dedicated) or group owner (on GitLab.com) gives those users permission. The administrator or group owner can create a [custom role](custom_roles/_index.md) through the API or UI and assign - that role to the users. + that role to the users. In GitLab 18.7 and later, users with the Planner role can view private repository content. 2. On GitLab Self-Managed, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](../administration/external_users.md) must be given explicit access (at least the **Reporter** role) even if the project is internal. Users diff --git a/ee/config/custom_abilities/read_code.yml b/ee/config/custom_abilities/read_code.yml index b5abbec4eebf5c227d3562b71f08b0dad34852f3..b0911a924b41d933319801d1e4b4fade4b3cb0f0 100644 --- a/ee/config/custom_abilities/read_code.yml +++ b/ee/config/custom_abilities/read_code.yml @@ -7,8 +7,8 @@ introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/issues/376180 feature_category: source_code_management milestone: '15.7' group_ability: true -enabled_for_group_access_levels: [20, 30, 40, 50] +enabled_for_group_access_levels: [15, 20, 30, 40, 50] project_ability: true -enabled_for_project_access_levels: [20, 30, 40, 50] +enabled_for_project_access_levels: [15, 20, 30, 40, 50] skip_seat_consumption: true -available_from_access_level: 20 +available_from_access_level: 15 diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index d533737845bcac6892c20375536861f6dcb14616..e64f322321cd2baf6c580227fb8b76dd15deea70 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -260,12 +260,6 @@ def set_access_level(access_level) it { is_expected.not_to be_allowed(:create_merge_request_in) } end - context 'when the current_user is planner' do - let(:current_user) { planner } - - it { is_expected.not_to be_allowed(:create_merge_request_in) } - end - context 'when the current_user is reporter or above' do let(:current_user) { reporter } @@ -283,36 +277,30 @@ def set_access_level(access_level) context 'when project is public' do let(:project) { public_project } - %w[guest planner].each do |role| - context "when the current_user is #{role}" do - let(:current_user) { send(role) } + context 'when the current_user is guest' do + let(:current_user) { guest } - it { is_expected.not_to be_allowed(:create_merge_request_in) } - end + it { is_expected.not_to be_allowed(:create_merge_request_in) } end end context 'when project is internal' do let(:project) { internal_project } - %w[guest planner].each do |role| - context "when the current_user is #{role}" do - let(:current_user) { send(role) } + context 'when the current_user is guest' do + let(:current_user) { guest } - it { is_expected.not_to be_allowed(:create_merge_request_in) } - end + it { is_expected.not_to be_allowed(:create_merge_request_in) } end end context 'when project is private' do let(:project) { private_project } - %w[guest planner].each do |role| - context "when the current_user is #{role}" do - let(:current_user) { send(role) } + context 'when the current_user is guest' do + let(:current_user) { guest } - it { is_expected.not_to be_allowed(:create_merge_request_in) } - end + it { is_expected.not_to be_allowed(:create_merge_request_in) } end context 'when the current_user is reporter or above' do @@ -322,6 +310,16 @@ def set_access_level(access_level) end end end + + context 'when the current_user is planner in private project' do + let(:project) { private_project } + let(:current_user) { planner } + + it 'cannot create merge requests even though they can download code' do + expect_allowed(:read_code, :download_code) + expect_disallowed(:create_merge_request_in) + end + end end context 'pipeline feature' do @@ -3700,7 +3698,7 @@ def permissions_abilities(role) :maintainer | true :developer | true :reporter | true - :planner | false + :planner | true :guest | false end diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb index abb669430192c24302192be44fa8f744dcfab994..f6953cd2698fca18e5f7bcaeacf6862867dcf02b 100644 --- a/spec/support/shared_examples/policies/project_policy_shared_examples.rb +++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb @@ -216,7 +216,7 @@ disallowed_reporter_public_permissions + %i[ fork_project read_commit_status read_container_image read_deployment - read_environment create_merge_request_in download_code + read_environment create_merge_request_in ] end @@ -244,7 +244,9 @@ specify do expect_allowed(*guest_permissions) expect_allowed(*planner_permissions) + expect_allowed(:read_code, :download_code) expect_allowed(*(base_reporter_permissions - disallowed_reporter_permissions)) + expect_disallowed(:create_merge_request_in) expect_disallowed(*disallowed_reporter_permissions) expect_disallowed(*(developer_permissions - [:create_wiki])) expect_disallowed(*(maintainer_permissions - [:admin_wiki])) @@ -300,7 +302,9 @@ specify do expect_allowed(*guest_permissions) expect_allowed(*planner_permissions) + expect_allowed(:read_code, :download_code) expect_allowed(*(base_reporter_permissions - disallowed_reporter_permissions)) + expect_disallowed(:create_merge_request_in) expect_disallowed(*disallowed_reporter_permissions) expect_disallowed(*(developer_permissions - [:create_wiki])) expect_disallowed(*(maintainer_permissions - [:admin_wiki]))