From 6ed4ec3e0b1340f96b7c043ef51d1b33bbe85fde Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 19 Sep 2022 23:18:09 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-4-stable-ee --- spec/policies/ci/pipeline_schedule_policy_spec.rb | 2 +- spec/policies/ci/runner_policy_spec.rb | 160 +++++++++ spec/policies/clusters/agent_policy_spec.rb | 2 +- spec/policies/commit_policy_spec.rb | 107 ++++-- spec/policies/group_member_policy_spec.rb | 6 +- spec/policies/group_policy_spec.rb | 98 +++++- spec/policies/issuable_policy_spec.rb | 54 ++- spec/policies/issue_policy_spec.rb | 2 +- spec/policies/merge_request_policy_spec.rb | 374 ++++++++++++++------- .../packages/policies/group_policy_spec.rb | 79 +++++ .../packages/policies/project_policy_spec.rb | 164 +++++++++ spec/policies/project_policy_spec.rb | 158 +++++++-- .../protected_branch_access_policy_spec.rb | 31 ++ spec/policies/protected_branch_policy_spec.rb | 44 ++- spec/policies/terraform/state_policy_spec.rb | 2 +- .../terraform/state_version_policy_spec.rb | 2 +- 16 files changed, 1067 insertions(+), 218 deletions(-) create mode 100644 spec/policies/ci/runner_policy_spec.rb create mode 100644 spec/policies/packages/policies/group_policy_spec.rb create mode 100644 spec/policies/packages/policies/project_policy_spec.rb create mode 100644 spec/policies/protected_branch_access_policy_spec.rb (limited to 'spec/policies') diff --git a/spec/policies/ci/pipeline_schedule_policy_spec.rb b/spec/policies/ci/pipeline_schedule_policy_spec.rb index f2c99e0de95..9aa50876b55 100644 --- a/spec/policies/ci/pipeline_schedule_policy_spec.rb +++ b/spec/policies/ci/pipeline_schedule_policy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineSchedulePolicy, :models do +RSpec.describe Ci::PipelineSchedulePolicy, :models, :clean_gitlab_redis_cache do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } let_it_be(:pipeline_schedule, reload: true) { create(:ci_pipeline_schedule, :nightly, project: project) } diff --git a/spec/policies/ci/runner_policy_spec.rb b/spec/policies/ci/runner_policy_spec.rb new file mode 100644 index 00000000000..880ff0722fa --- /dev/null +++ b/spec/policies/ci/runner_policy_spec.rb @@ -0,0 +1,160 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::RunnerPolicy do + describe 'ability :read_runner' do + let_it_be(:guest) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:owner) { create(:user) } + + let_it_be(:group1) { create(:group, name: 'top-level', path: 'top-level') } + let_it_be(:subgroup1) { create(:group, name: 'subgroup1', path: 'subgroup1', parent: group1) } + let_it_be(:project1) { create(:project, group: subgroup1) } + let_it_be(:instance_runner) { create(:ci_runner, :instance) } + let_it_be(:group1_runner) { create(:ci_runner, :group, groups: [group1]) } + let_it_be(:project1_runner) { create(:ci_runner, :project, projects: [project1]) } + + subject(:policy) { described_class.new(user, runner) } + + before do + group1.add_guest(guest) + group1.add_developer(developer) + group1.add_owner(owner) + end + + shared_context 'on hierarchy with shared runners disabled' do + around do |example| + group1.update!(shared_runners_enabled: false) + project1.update!(shared_runners_enabled: false) + + example.run + ensure + project1.update!(shared_runners_enabled: true) + group1.update!(shared_runners_enabled: true) + end + end + + shared_context 'on hierarchy with group runners disabled' do + around do |example| + project1.update!(group_runners_enabled: false) + + example.run + ensure + project1.update!(group_runners_enabled: true) + end + end + + shared_examples 'does not allow reading runners on any scope' do + context 'with instance runner' do + let(:runner) { instance_runner } + + it { expect_disallowed :read_runner } + + context 'with shared runners disabled' do + include_context 'on hierarchy with shared runners disabled' do + it { expect_disallowed :read_runner } + end + end + end + + context 'with group runner' do + let(:runner) { group1_runner } + + it { expect_disallowed :read_runner } + + context 'with group runner disabled' do + include_context 'on hierarchy with group runners disabled' do + it { expect_disallowed :read_runner } + end + end + end + + context 'with project runner' do + let(:runner) { project1_runner } + + it { expect_disallowed :read_runner } + end + end + + context 'without access' do + let_it_be(:user) { create(:user) } + + it_behaves_like 'does not allow reading runners on any scope' + end + + context 'with guest access' do + let(:user) { guest } + + it_behaves_like 'does not allow reading runners on any scope' + end + + context 'with developer access' do + let(:user) { developer } + + context 'with instance runner' do + let(:runner) { instance_runner } + + it { expect_allowed :read_runner } + + context 'with shared runners disabled' do + include_context 'on hierarchy with shared runners disabled' do + it { expect_disallowed :read_runner } + end + end + end + + context 'with group runner' do + let(:runner) { group1_runner } + + it { expect_allowed :read_runner } + + context 'with group runner disabled' do + include_context 'on hierarchy with group runners disabled' do + it { expect_disallowed :read_runner } + end + end + end + + context 'with project runner' do + let(:runner) { project1_runner } + + it { expect_disallowed :read_runner } + end + end + + context 'with owner access' do + let(:user) { owner } + + context 'with instance runner' do + let(:runner) { instance_runner } + + context 'with shared runners disabled' do + include_context 'on hierarchy with shared runners disabled' do + it { expect_disallowed :read_runner } + end + end + + it { expect_allowed :read_runner } + end + + context 'with group runner' do + let(:runner) { group1_runner } + + context 'with group runners disabled' do + include_context 'on hierarchy with group runners disabled' do + it { expect_allowed :read_runner } + end + end + + it { expect_allowed :read_runner } + end + + context 'with project runner' do + let(:runner) { project1_runner } + + it { expect_allowed :read_runner } + end + end + end +end diff --git a/spec/policies/clusters/agent_policy_spec.rb b/spec/policies/clusters/agent_policy_spec.rb index 307d751b78b..8f778d318ed 100644 --- a/spec/policies/clusters/agent_policy_spec.rb +++ b/spec/policies/clusters/agent_policy_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Clusters::AgentPolicy do - let(:cluster_agent) { create(:cluster_agent, name: 'agent' )} + let(:cluster_agent) { create(:cluster_agent, name: 'agent' ) } let(:user) { create(:admin) } let(:policy) { described_class.new(user, cluster_agent) } let(:project) { cluster_agent.project } diff --git a/spec/policies/commit_policy_spec.rb b/spec/policies/commit_policy_spec.rb index 0d3dcc97565..cf2798b9ef3 100644 --- a/spec/policies/commit_policy_spec.rb +++ b/spec/policies/commit_policy_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe CommitPolicy do describe '#rules' do + let(:group) { create(:group, :public) } let(:user) { create(:user) } let(:commit) { project.repository.head_commit } let(:policy) { described_class.new(user, commit) } @@ -19,59 +20,119 @@ RSpec.describe CommitPolicy do end shared_examples 'cannot read commit nor create a note' do - it 'can not read commit' do + it 'cannot read commit' do expect(policy).to be_disallowed(:read_commit) end - it 'can not create a note' do + it 'cannot create a note' do expect(policy).to be_disallowed(:create_note) end end context 'when project is public' do - let(:project) { create(:project, :public, :repository) } + let(:project) { create(:project, :public, :repository, group: group) } - it_behaves_like 'can read commit and create a note' + context 'when the user is not a project member' do + it_behaves_like 'can read commit and create a note' + end context 'when repository access level is private' do - let(:project) { create(:project, :public, :repository, :repository_private) } + let(:project) { create(:project, :public, :repository, :repository_private, group: group) } - it_behaves_like 'cannot read commit nor create a note' + context 'when the user is not a project member' do + it_behaves_like 'cannot read commit nor create a note' + end - context 'when the user is a project member' do - before do - project.add_developer(user) + context 'when the user is a direct project member' do + context 'and the user is a developer' do + before do + project.add_developer(user) + end + + it_behaves_like 'can read commit and create a note' end + end - it_behaves_like 'can read commit and create a note' + context 'when the user is an inherited member from the group' do + context 'and the user is a guest' do + before do + group.add_guest(user) + end + + it_behaves_like 'can read commit and create a note' + end + + context 'and the user is a reporter' do + before do + group.add_reporter(user) + end + + it_behaves_like 'can read commit and create a note' + end + + context 'and the user is a developer' do + before do + group.add_developer(user) + end + + it_behaves_like 'can read commit and create a note' + end end end end context 'when project is private' do - let(:project) { create(:project, :private, :repository) } + let(:project) { create(:project, :private, :repository, group: group) } - it_behaves_like 'cannot read commit nor create a note' + context 'when the user is not a project member' do + it_behaves_like 'cannot read commit nor create a note' + end - context 'when the user is a project member' do - before do - project.add_developer(user) + context 'when the user is a direct project member' do + context 'and the user is a developer' do + before do + project.add_developer(user) + end + + it_behaves_like 'can read commit and create a note' end - it 'can read commit and create a note' do - expect(policy).to be_allowed(:read_commit) + context 'and the user is a guest' do + before do + project.add_guest(user) + end + + it_behaves_like 'cannot read commit nor create a note' + + it 'cannot download code' do + expect(policy).to be_disallowed(:download_code) + end end end - context 'when the user is a guest' do - before do - project.add_guest(user) + context 'when the user is an inherited member from the group' do + context 'and the user is a guest' do + before do + group.add_guest(user) + end + + it_behaves_like 'cannot read commit nor create a note' end - it_behaves_like 'cannot read commit nor create a note' + context 'and the user is a reporter' do + before do + group.add_reporter(user) + end + + it_behaves_like 'can read commit and create a note' + end - it 'cannot download code' do - expect(policy).to be_disallowed(:download_code) + context 'and the user is a developer' do + before do + group.add_developer(user) + end + + it_behaves_like 'can read commit and create a note' end end end diff --git a/spec/policies/group_member_policy_spec.rb b/spec/policies/group_member_policy_spec.rb index 50774313aae..27ce683861c 100644 --- a/spec/policies/group_member_policy_spec.rb +++ b/spec/policies/group_member_policy_spec.rb @@ -128,7 +128,7 @@ RSpec.describe GroupMemberPolicy do context 'with the group parent' do let(:current_user) { create :user } - let(:subgroup) { create(:group, :private, parent: group)} + let(:subgroup) { create(:group, :private, parent: group) } before do group.add_owner(owner) @@ -143,7 +143,7 @@ RSpec.describe GroupMemberPolicy do context 'without group parent' do let(:current_user) { create :user } - let(:subgroup) { create(:group, :private)} + let(:subgroup) { create(:group, :private) } before do subgroup.add_owner(current_user) @@ -158,7 +158,7 @@ RSpec.describe GroupMemberPolicy do context 'without group parent with two owners' do let(:current_user) { create :user } let(:other_user) { create :user } - let(:subgroup) { create(:group, :private)} + let(:subgroup) { create(:group, :private) } before do subgroup.add_owner(current_user) diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 57923142648..da0270c15b9 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -9,7 +9,7 @@ RSpec.describe GroupPolicy do let(:group) { create(:group, :public, :crm_enabled) } let(:current_user) { nil } - it do + specify do expect_allowed(*public_permissions) expect_disallowed(:upload_file) expect_disallowed(*reporter_permissions) @@ -24,7 +24,7 @@ RSpec.describe GroupPolicy do let(:group) { create(:group, :public, :crm_enabled) } let(:current_user) { create(:user) } - it do + specify do expect_allowed(*public_permissions) expect_disallowed(:upload_file) expect_disallowed(*reporter_permissions) @@ -43,7 +43,7 @@ RSpec.describe GroupPolicy do create(:project_group_link, project: project, group: group) end - it do + specify do expect_disallowed(*public_permissions) expect_disallowed(*reporter_permissions) expect_disallowed(*owner_permissions) @@ -58,7 +58,7 @@ RSpec.describe GroupPolicy do create(:project_group_link, project: project, group: group) end - it do + specify do expect_disallowed(*public_permissions) expect_disallowed(*reporter_permissions) expect_disallowed(*owner_permissions) @@ -91,7 +91,7 @@ RSpec.describe GroupPolicy do let(:deploy_token) { create(:deploy_token) } let(:current_user) { deploy_token } - it do + specify do expect_disallowed(*public_permissions) expect_disallowed(*guest_permissions) expect_disallowed(*reporter_permissions) @@ -104,7 +104,7 @@ RSpec.describe GroupPolicy do context 'guests' do let(:current_user) { guest } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_disallowed(*reporter_permissions) @@ -121,7 +121,7 @@ RSpec.describe GroupPolicy do context 'reporter' do let(:current_user) { reporter } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -138,7 +138,7 @@ RSpec.describe GroupPolicy do context 'developer' do let(:current_user) { developer } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -195,7 +195,7 @@ RSpec.describe GroupPolicy do context 'owner' do let(:current_user) { owner } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -282,7 +282,7 @@ RSpec.describe GroupPolicy do context 'with no user' do let(:current_user) { nil } - it do + specify do expect_disallowed(*public_permissions) expect_disallowed(*guest_permissions) expect_disallowed(*reporter_permissions) @@ -295,7 +295,7 @@ RSpec.describe GroupPolicy do context 'guests' do let(:current_user) { guest } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_disallowed(*reporter_permissions) @@ -308,7 +308,7 @@ RSpec.describe GroupPolicy do context 'reporter' do let(:current_user) { reporter } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -321,7 +321,7 @@ RSpec.describe GroupPolicy do context 'developer' do let(:current_user) { developer } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -334,7 +334,7 @@ RSpec.describe GroupPolicy do context 'maintainer' do let(:current_user) { maintainer } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -347,7 +347,7 @@ RSpec.describe GroupPolicy do context 'owner' do let(:current_user) { owner } - it do + specify do expect_allowed(*public_permissions) expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) @@ -916,6 +916,74 @@ RSpec.describe GroupPolicy do end end + describe 'observability' do + using RSpec::Parameterized::TableSyntax + + let(:allowed) { be_allowed(:read_observability) } + let(:disallowed) { be_disallowed(:read_observability) } + + # rubocop:disable Layout/LineLength + where(:feature_enabled, :admin_matcher, :owner_matcher, :maintainer_matcher, :developer_matcher, :reporter_matcher, :guest_matcher, :non_member_matcher, :anonymous_matcher) do + false | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) + true | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:allowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) | ref(:disallowed) + end + # rubocop:enable Layout/LineLength + + with_them do + before do + stub_feature_flags(observability_group_tab: feature_enabled) + end + + context 'admin', :enable_admin_mode do + let(:current_user) { admin } + + it { is_expected.to admin_matcher } + end + + context 'owner' do + let(:current_user) { owner } + + it { is_expected.to owner_matcher } + end + + context 'maintainer' do + let(:current_user) { maintainer } + + it { is_expected.to maintainer_matcher } + end + + context 'developer' do + let(:current_user) { developer } + + it { is_expected.to developer_matcher } + end + + context 'reporter' do + let(:current_user) { reporter } + + it { is_expected.to reporter_matcher } + end + + context 'with guest' do + let(:current_user) { guest } + + it { is_expected.to guest_matcher } + end + + context 'with non member' do + let(:current_user) { create(:user) } + + it { is_expected.to non_member_matcher } + end + + context 'with anonymous' do + let(:current_user) { nil } + + it { is_expected.to anonymous_matcher } + end + end + end + describe 'dependency proxy' do context 'feature disabled' do let(:current_user) { owner } diff --git a/spec/policies/issuable_policy_spec.rb b/spec/policies/issuable_policy_spec.rb index 706570babd5..fd7ec5917d6 100644 --- a/spec/policies/issuable_policy_spec.rb +++ b/spec/policies/issuable_policy_spec.rb @@ -18,8 +18,8 @@ RSpec.describe IssuablePolicy, models: true do project.add_reporter(reporter) end - def permissions(user, issue) - described_class.new(user, issue) + def permissions(user, issuable) + described_class.new(user, issuable) end describe '#rules' do @@ -153,5 +153,55 @@ RSpec.describe IssuablePolicy, models: true do expect(permissions(reporter, issue)).to be_allowed(:create_timelog) end end + + context 'when subject is a Merge Request' do + let(:issuable) { create(:merge_request) } + let(:policy) { permissions(user, issuable) } + + before do + allow(policy).to receive(:can?).with(:read_merge_request).and_return(can_read_merge_request) + end + + context 'when can_read_merge_request is false' do + let(:can_read_merge_request) { false } + + it 'does not allow :read_issuable' do + expect(policy).not_to be_allowed(:read_issuable) + end + end + + context 'when can_read_merge_request is true' do + let(:can_read_merge_request) { true } + + it 'allows :read_issuable' do + expect(policy).to be_allowed(:read_issuable) + end + end + end + + context 'when subject is an Issue' do + let(:issuable) { create(:issue) } + let(:policy) { permissions(user, issuable) } + + before do + allow(policy).to receive(:can?).with(:read_issue).and_return(can_read_issue) + end + + context 'when can_read_issue is false' do + let(:can_read_issue) { false } + + it 'does not allow :read_issuable' do + expect(policy).not_to be_allowed(:read_issuable) + end + end + + context 'when can_read_issue is true' do + let(:can_read_issue) { true } + + it 'allows :read_issuable' do + expect(policy).to be_allowed(:read_issuable) + end + end + end end end diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index 7ca4baddb79..4d492deb54c 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -398,7 +398,7 @@ RSpec.describe IssuePolicy do context 'with a hidden issue' do let(:user) { create(:user) } let(:banned_user) { create(:user, :banned) } - let(:admin) { create(:user, :admin)} + let(:admin) { create(:user, :admin) } let(:hidden_issue) { create(:issue, project: project, author: banned_user) } it 'does not allow non-admin user to read the issue' do diff --git a/spec/policies/merge_request_policy_spec.rb b/spec/policies/merge_request_policy_spec.rb index dd42e1b9313..7e1af132b1d 100644 --- a/spec/policies/merge_request_policy_spec.rb +++ b/spec/policies/merge_request_policy_spec.rb @@ -7,24 +7,18 @@ RSpec.describe MergeRequestPolicy do let_it_be(:guest) { create(:user) } let_it_be(:author) { create(:user) } + let_it_be(:reporter) { create(:user) } let_it_be(:developer) { create(:user) } let_it_be(:non_team_member) { create(:user) } - let(:project) { create(:project, :public) } - def permissions(user, merge_request) described_class.new(user, merge_request) end - before do - project.add_guest(guest) - project.add_guest(author) - project.add_developer(developer) - end - mr_perms = %i[create_merge_request_in create_merge_request_from read_merge_request + update_merge_request create_todo approve_merge_request create_note @@ -40,7 +34,28 @@ RSpec.describe MergeRequestPolicy do end end - shared_examples_for 'a user with access' do + shared_examples_for 'a user with reporter access' do + using RSpec::Parameterized::TableSyntax + + where(:policy, :is_allowed) do + :create_merge_request_in | true + :read_merge_request | true + :create_todo | true + :create_note | true + :update_subscription | true + :create_merge_request_from | false + :approve_merge_request | false + :update_merge_request | false + end + + with_them do + specify do + is_allowed ? (is_expected.to be_allowed(policy)) : (is_expected.to be_disallowed(policy)) + end + end + end + + shared_examples_for 'a user with full access' do let(:perms) { permissions(subject, merge_request) } mr_perms.each do |thing| @@ -50,199 +65,304 @@ RSpec.describe MergeRequestPolicy do end end - context 'when merge request is public' do - let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } - let(:user) { author } - - context 'and user is anonymous' do - subject { permissions(nil, merge_request) } + context 'when user is a direct project member' do + let(:project) { create(:project, :public) } - it do - is_expected.to be_disallowed(:create_todo, :update_subscription) - end + before do + project.add_guest(guest) + project.add_guest(author) + project.add_developer(developer) end - context 'and user is author' do - subject { permissions(user, merge_request) } + context 'when merge request is public' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } + let(:user) { author } - context 'and the user is a guest' do - let(:user) { guest } + context 'and user is author' do + subject { permissions(user, merge_request) } - it do - is_expected.to be_allowed(:update_merge_request) - end + context 'and the user is a guest' do + let(:user) { guest } - it do - is_expected.to be_allowed(:reopen_merge_request) - end + it do + is_expected.to be_allowed(:update_merge_request) + end - it do - is_expected.to be_allowed(:approve_merge_request) + it do + is_expected.to be_allowed(:reopen_merge_request) + end + + it do + is_expected.to be_allowed(:approve_merge_request) + end end end + end - context 'and the user is a group member' do - let(:project) { create(:project, :public, group: group) } - let(:group) { create(:group) } - let(:user) { non_team_member } - - before do - group.add_guest(non_team_member) - end + context 'when merge requests have been disabled' do + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: author) } - it do - is_expected.to be_allowed(:approve_merge_request) - end + before do + project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED) end - context 'and the user is a member of a shared group' do - let(:user) { non_team_member } + describe 'the author' do + subject { author } - before do - group = create(:group) - project.project_group_links.create!( - group: group, - group_access: Gitlab::Access::DEVELOPER) + it_behaves_like 'a denied user' + end - group.add_guest(non_team_member) - end + describe 'a guest' do + subject { guest } - it do - is_expected.to be_allowed(:approve_merge_request) - end + it_behaves_like 'a denied user' end - context 'and the user is not a project member' do - let(:user) { non_team_member } + describe 'a developer' do + subject { developer } - it do - is_expected.not_to be_allowed(:approve_merge_request) - end + it_behaves_like 'a denied user' end end - end - context 'when merge requests have been disabled' do - let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: author) } + context 'when merge requests are private' do + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: author) } - before do - project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED) - end + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) + end - describe 'the author' do - subject { author } + describe 'the author' do + subject { author } - it_behaves_like 'a denied user' + it_behaves_like 'a denied user' + end + + describe 'a developer' do + subject { developer } + + it_behaves_like 'a user with full access' + end end - describe 'a guest' do - subject { guest } + context 'when merge request is unlocked' do + let(:merge_request) { create(:merge_request, :closed, source_project: project, target_project: project, author: author) } - it_behaves_like 'a denied user' + it 'allows author to reopen merge request' do + expect(permissions(author, merge_request)).to be_allowed(:reopen_merge_request) + end + + it 'allows developer to reopen merge request' do + expect(permissions(developer, merge_request)).to be_allowed(:reopen_merge_request) + end + + it 'prevents guest from reopening merge request' do + expect(permissions(guest, merge_request)).to be_disallowed(:reopen_merge_request) + end end - describe 'a developer' do - subject { developer } + context 'when merge request is locked' do + let(:merge_request_locked) { create(:merge_request, :closed, discussion_locked: true, source_project: project, target_project: project, author: author) } - it_behaves_like 'a denied user' + it 'prevents author from reopening merge request' do + expect(permissions(author, merge_request_locked)).to be_disallowed(:reopen_merge_request) + end + + it 'prevents developer from reopening merge request' do + expect(permissions(developer, merge_request_locked)).to be_disallowed(:reopen_merge_request) + end + + it 'prevents guests from reopening merge request' do + expect(permissions(guest, merge_request_locked)).to be_disallowed(:reopen_merge_request) + end + + context 'when the user is project member, with at least guest access' do + let(:user) { guest } + + it 'can create a note' do + expect(permissions(user, merge_request_locked)).to be_allowed(:create_note) + end + end end - describe 'any other user' do - subject { non_team_member } + context 'with external authorization enabled' do + let(:user) { create(:user) } + let(:project) { create(:project, :public) } + let(:merge_request) { create(:merge_request, source_project: project) } + let(:policies) { described_class.new(user, merge_request) } - it_behaves_like 'a denied user' + before do + enable_external_authorization_service_check + end + + it 'can read the issue iid without accessing the external service' do + expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?) + + expect(policies).to be_allowed(:read_merge_request_iid) + end end end - context 'when merge requests are private' do - let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: author) } + context 'when user is an inherited member from the parent group' do + let_it_be(:group) { create(:group, :public) } - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: author) } + + before_all do + group.add_guest(guest) + group.add_guest(author) + group.add_reporter(reporter) + group.add_developer(developer) end - describe 'a non-team-member' do - subject { non_team_member } + context 'when project is public' do + let(:project) { create(:project, :public, group: group) } - it_behaves_like 'a denied user' - end + describe 'the merge request author' do + subject { permissions(author, merge_request) } - describe 'the author' do - subject { author } + specify do + is_expected.to be_allowed(:approve_merge_request) + end + end - it_behaves_like 'a denied user' + context 'and merge requests are private' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) + end + + describe 'a guest' do + subject { guest } + + it_behaves_like 'a denied user' + end + + describe 'a reporter' do + subject { permissions(reporter, merge_request) } + + it_behaves_like 'a user with reporter access' + end + + describe 'a developer' do + subject { developer } + + it_behaves_like 'a user with full access' + end + end end - describe 'a developer' do - subject { developer } + context 'when project is private' do + let(:project) { create(:project, :private, group: group) } + + describe 'a guest' do + subject { guest } - it_behaves_like 'a user with access' + it_behaves_like 'a denied user' + end + + describe 'a reporter' do + subject { permissions(reporter, merge_request) } + + it_behaves_like 'a user with reporter access' + end + + describe 'a developer' do + subject { developer } + + it_behaves_like 'a user with full access' + end end end - context 'when merge request is unlocked' do - let(:merge_request) { create(:merge_request, :closed, source_project: project, target_project: project, author: author) } + context 'when user is an inherited member from a shared group' do + let(:project) { create(:project, :public) } + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } + let(:user) { author } - it 'allows author to reopen merge request' do - expect(permissions(author, merge_request)).to be_allowed(:reopen_merge_request) + before do + project.add_guest(author) end - it 'allows developer to reopen merge request' do - expect(permissions(developer, merge_request)).to be_allowed(:reopen_merge_request) - end + context 'and group is given developer access' do + let(:user) { non_team_member } + + subject { permissions(user, merge_request) } + + before do + group = create(:group) + project.project_group_links.create!( + group: group, + group_access: Gitlab::Access::DEVELOPER) + + group.add_guest(non_team_member) + end - it 'prevents guest from reopening merge request' do - expect(permissions(guest, merge_request)).to be_disallowed(:reopen_merge_request) + specify do + is_expected.to be_allowed(:approve_merge_request) + end end end - context 'when merge request is locked' do - let(:merge_request_locked) { create(:merge_request, :closed, discussion_locked: true, source_project: project, target_project: project, author: author) } + context 'when user is not a project member' do + let(:project) { create(:project, :public) } - it 'prevents author from reopening merge request' do - expect(permissions(author, merge_request_locked)).to be_disallowed(:reopen_merge_request) - end + context 'when merge request is public' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - it 'prevents developer from reopening merge request' do - expect(permissions(developer, merge_request_locked)).to be_disallowed(:reopen_merge_request) + subject { permissions(non_team_member, merge_request) } + + specify do + is_expected.not_to be_allowed(:approve_merge_request) + end end - it 'prevents guests from reopening merge request' do - expect(permissions(guest, merge_request_locked)).to be_disallowed(:reopen_merge_request) + context 'when merge requests are disabled' do + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + + before do + project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED) + end + + subject { non_team_member } + + it_behaves_like 'a denied user' end - context 'when the user is not a project member' do - let(:user) { create(:user) } + context 'when merge requests are private' do + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - it 'cannot create a note' do - expect(permissions(user, merge_request_locked)).to be_disallowed(:create_note) + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) end + + subject { non_team_member } + + it_behaves_like 'a denied user' end - context 'when the user is project member, with at least guest access' do - let(:user) { guest } + context 'when merge request is locked' do + let(:merge_request) { create(:merge_request, :closed, discussion_locked: true, source_project: project, target_project: project) } - it 'can create a note' do - expect(permissions(user, merge_request_locked)).to be_allowed(:create_note) + it 'cannot create a note' do + expect(permissions(non_team_member, merge_request)).to be_disallowed(:create_note) end end end - context 'with external authorization enabled' do - let(:user) { create(:user) } + context 'when user is anonymous' do let(:project) { create(:project, :public) } - let(:merge_request) { create(:merge_request, source_project: project) } - let(:policies) { described_class.new(user, merge_request) } - before do - enable_external_authorization_service_check - end + context 'when merge request is public' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - it 'can read the issue iid without accessing the external service' do - expect(::Gitlab::ExternalAuthorization).not_to receive(:access_allowed?) + subject { permissions(nil, merge_request) } - expect(policies).to be_allowed(:read_merge_request_iid) + specify do + is_expected.to be_disallowed(:create_todo, :update_subscription) + end end end end diff --git a/spec/policies/packages/policies/group_policy_spec.rb b/spec/policies/packages/policies/group_policy_spec.rb new file mode 100644 index 00000000000..d0d9a9a22f5 --- /dev/null +++ b/spec/policies/packages/policies/group_policy_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Policies::GroupPolicy do + include_context 'GroupPolicy context' + + subject { described_class.new(current_user, group.packages_policy_subject) } + + describe 'read_package' do + context 'with admin' do + let(:current_user) { admin } + + context 'when admin mode is enabled', :enable_admin_mode do + it { is_expected.to be_allowed(:read_package) } + end + + context 'when admin mode is disabled' do + it { is_expected.to be_disallowed(:read_package) } + end + end + + context 'with owner' do + let(:current_user) { owner } + + it { is_expected.to be_allowed(:read_package) } + end + + context 'with maintainer' do + let(:current_user) { maintainer } + + it { is_expected.to be_allowed(:read_package) } + end + + context 'with reporter' do + let(:current_user) { reporter } + + it { is_expected.to be_allowed(:read_package) } + end + + context 'with guest' do + let(:current_user) { guest } + + it { is_expected.to be_disallowed(:read_package) } + end + + context 'with non member' do + let(:current_user) { create(:user) } + + it { is_expected.to be_disallowed(:read_package) } + end + + context 'with anonymous' do + let(:current_user) { nil } + + it { is_expected.to be_disallowed(:read_package) } + end + end + + describe 'deploy token access' do + let!(:group_deploy_token) do + create(:group_deploy_token, group: group, deploy_token: deploy_token) + end + + subject { described_class.new(deploy_token, group.packages_policy_subject) } + + context 'when a deploy token with read_package_registry scope' do + let(:deploy_token) { create(:deploy_token, :group, read_package_registry: true) } + + it { is_expected.to be_allowed(:read_package) } + end + + context 'when a deploy token with write_package_registry scope' do + let(:deploy_token) { create(:deploy_token, :group, write_package_registry: true) } + + it { is_expected.to be_allowed(:read_package) } + end + end +end diff --git a/spec/policies/packages/policies/project_policy_spec.rb b/spec/policies/packages/policies/project_policy_spec.rb new file mode 100644 index 00000000000..5d54ee54572 --- /dev/null +++ b/spec/policies/packages/policies/project_policy_spec.rb @@ -0,0 +1,164 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Policies::ProjectPolicy do + include_context 'ProjectPolicy context' + + let(:project) { public_project } + + subject { described_class.new(current_user, project.packages_policy_subject) } + + describe 'deploy token access' do + let!(:project_deploy_token) do + create(:project_deploy_token, project: project, deploy_token: deploy_token) + end + + subject { described_class.new(deploy_token, project.packages_policy_subject) } + + context 'when a deploy token with read_package_registry scope' do + let(:deploy_token) { create(:deploy_token, read_package_registry: true) } + + it { is_expected.to be_allowed(:read_package) } + + it_behaves_like 'package access with repository disabled' + end + + context 'when a deploy token with write_package_registry scope' do + let(:deploy_token) { create(:deploy_token, write_package_registry: true) } + + it { is_expected.to be_allowed(:read_package) } + + it_behaves_like 'package access with repository disabled' + end + end + + describe 'read_package', :enable_admin_mode do + using RSpec::Parameterized::TableSyntax + + where(:project, :package_registry_access_level, :current_user, :expect_to_be_allowed) do + ref(:private_project) | ProjectFeature::DISABLED | ref(:anonymous) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:non_member) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:guest) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:reporter) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:developer) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:maintainer) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:owner) | false + ref(:private_project) | ProjectFeature::DISABLED | ref(:admin) | false + + ref(:private_project) | ProjectFeature::PRIVATE | ref(:anonymous) | false + ref(:private_project) | ProjectFeature::PRIVATE | ref(:non_member) | false + ref(:private_project) | ProjectFeature::PRIVATE | ref(:guest) | false + ref(:private_project) | ProjectFeature::PRIVATE | ref(:reporter) | true + ref(:private_project) | ProjectFeature::PRIVATE | ref(:developer) | true + ref(:private_project) | ProjectFeature::PRIVATE | ref(:maintainer) | true + ref(:private_project) | ProjectFeature::PRIVATE | ref(:owner) | true + ref(:private_project) | ProjectFeature::PRIVATE | ref(:admin) | true + + ref(:private_project) | ProjectFeature::PUBLIC | ref(:anonymous) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:non_member) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:guest) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:reporter) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:developer) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:maintainer) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:owner) | true + ref(:private_project) | ProjectFeature::PUBLIC | ref(:admin) | true + + ref(:internal_project) | ProjectFeature::DISABLED | ref(:anonymous) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:non_member) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:guest) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:reporter) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:developer) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:maintainer) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:owner) | false + ref(:internal_project) | ProjectFeature::DISABLED | ref(:admin) | false + + ref(:internal_project) | ProjectFeature::ENABLED | ref(:anonymous) | false + ref(:internal_project) | ProjectFeature::ENABLED | ref(:non_member) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:guest) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:reporter) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:developer) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:maintainer) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:owner) | true + ref(:internal_project) | ProjectFeature::ENABLED | ref(:admin) | true + + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:anonymous) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:non_member) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:guest) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:reporter) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:developer) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:maintainer) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:owner) | true + ref(:internal_project) | ProjectFeature::PUBLIC | ref(:admin) | true + + ref(:public_project) | ProjectFeature::DISABLED | ref(:anonymous) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:non_member) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:guest) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:reporter) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:developer) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:maintainer) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:owner) | false + ref(:public_project) | ProjectFeature::DISABLED | ref(:admin) | false + + ref(:public_project) | ProjectFeature::PUBLIC | ref(:anonymous) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:non_member) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:guest) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:reporter) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:developer) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:maintainer) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:owner) | true + ref(:public_project) | ProjectFeature::PUBLIC | ref(:admin) | true + end + + with_them do + it do + project.project_feature.update!(package_registry_access_level: package_registry_access_level) + + if expect_to_be_allowed + is_expected.to be_allowed(:read_package) + else + is_expected.to be_disallowed(:read_package) + end + end + end + + context 'with feature flag disabled' do + before do + stub_feature_flags(package_registry_access_level: false) + end + + where(:project, :current_user, :expect_to_be_allowed) do + ref(:private_project) | ref(:anonymous) | false + ref(:private_project) | ref(:non_member) | false + ref(:private_project) | ref(:guest) | false + ref(:internal_project) | ref(:anonymous) | false + ref(:public_project) | ref(:admin) | true + ref(:public_project) | ref(:owner) | true + ref(:public_project) | ref(:maintainer) | true + ref(:public_project) | ref(:developer) | true + ref(:public_project) | ref(:reporter) | true + ref(:public_project) | ref(:guest) | true + ref(:public_project) | ref(:non_member) | true + ref(:public_project) | ref(:anonymous) | true + end + + with_them do + it do + project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC) + + if expect_to_be_allowed + is_expected.to be_allowed(:read_package) + else + is_expected.to be_disallowed(:read_package) + end + end + end + end + + context 'with admin' do + let(:current_user) { admin } + + it_behaves_like 'package access with repository disabled' + end + end +end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index e8fdf9a8e25..fefd9f71408 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -777,13 +777,13 @@ RSpec.describe ProjectPolicy do project.add_developer(user) end - it { is_expected.not_to be_allowed(:project_bot_access)} + it { is_expected.not_to be_allowed(:project_bot_access) } end context "when project bot and not part of the project" do let(:current_user) { project_bot } - it { is_expected.not_to be_allowed(:project_bot_access)} + it { is_expected.not_to be_allowed(:project_bot_access) } end context "when project bot and part of the project" do @@ -793,7 +793,7 @@ RSpec.describe ProjectPolicy do project.add_developer(project_bot) end - it { is_expected.to be_allowed(:project_bot_access)} + it { is_expected.to be_allowed(:project_bot_access) } end end @@ -804,7 +804,7 @@ RSpec.describe ProjectPolicy do project.add_maintainer(project_bot) end - it { is_expected.not_to be_allowed(:create_resource_access_tokens)} + it { is_expected.not_to be_allowed(:create_resource_access_tokens) } end end @@ -946,7 +946,7 @@ RSpec.describe ProjectPolicy do context 'with anonymous' do let(:current_user) { anonymous } - it { is_expected.to be_disallowed(:metrics_dashboard)} + it { is_expected.to be_disallowed(:metrics_dashboard) } end end @@ -1930,14 +1930,10 @@ RSpec.describe ProjectPolicy do describe 'operations feature' do using RSpec::Parameterized::TableSyntax - before do - stub_feature_flags(split_operations_visibility_permissions: false) - end + let(:guest_permissions) { [:read_environment, :read_deployment] } - let(:guest_operations_permissions) { [:read_environment, :read_deployment] } - - let(:developer_operations_permissions) do - guest_operations_permissions + [ + let(:developer_permissions) do + guest_permissions + [ :read_feature_flag, :read_sentry_issue, :read_alert_management_alert, :read_terraform_state, :metrics_dashboard, :read_pod_logs, :read_prometheus, :create_feature_flag, :create_environment, :create_deployment, :update_feature_flag, :update_environment, @@ -1946,13 +1942,17 @@ RSpec.describe ProjectPolicy do ] end - let(:maintainer_operations_permissions) do - developer_operations_permissions + [ + let(:maintainer_permissions) do + developer_permissions + [ :read_cluster, :create_cluster, :update_cluster, :admin_environment, :admin_cluster, :admin_terraform_state, :admin_deployment ] end + before do + stub_feature_flags(split_operations_visibility_permissions: false) + end + where(:project_visibility, :access_level, :role, :allowed) do :public | ProjectFeature::ENABLED | :maintainer | true :public | ProjectFeature::ENABLED | :developer | true @@ -2005,33 +2005,22 @@ RSpec.describe ProjectPolicy do expect_disallowed(*permissions_abilities(role)) end end - - def permissions_abilities(role) - case role - when :maintainer - maintainer_operations_permissions - when :developer - developer_operations_permissions - else - guest_operations_permissions - end - end end end describe 'environments feature' do using RSpec::Parameterized::TableSyntax - let(:guest_environments_permissions) { [:read_environment, :read_deployment] } + let(:guest_permissions) { [:read_environment, :read_deployment] } - let(:developer_environments_permissions) do - guest_environments_permissions + [ + let(:developer_permissions) do + guest_permissions + [ :create_environment, :create_deployment, :update_environment, :update_deployment, :destroy_environment ] end - let(:maintainer_environments_permissions) do - developer_environments_permissions + [:admin_environment, :admin_deployment] + let(:maintainer_permissions) do + developer_permissions + [:admin_environment, :admin_deployment] end where(:project_visibility, :access_level, :role, :allowed) do @@ -2086,15 +2075,73 @@ RSpec.describe ProjectPolicy do expect_disallowed(*permissions_abilities(role)) end end + end + end - def permissions_abilities(role) - case role - when :maintainer - maintainer_environments_permissions - when :developer - developer_environments_permissions + describe 'monitor feature' do + using RSpec::Parameterized::TableSyntax + + let(:guest_permissions) { [] } + + let(:developer_permissions) do + guest_permissions + [ + :read_sentry_issue, :read_alert_management_alert, :metrics_dashboard, + :update_sentry_issue, :update_alert_management_alert + ] + end + + let(:maintainer_permissions) { developer_permissions } + + where(:project_visibility, :access_level, :role, :allowed) do + :public | ProjectFeature::ENABLED | :maintainer | true + :public | ProjectFeature::ENABLED | :developer | true + :public | ProjectFeature::ENABLED | :guest | true + :public | ProjectFeature::ENABLED | :anonymous | true + :public | ProjectFeature::PRIVATE | :maintainer | true + :public | ProjectFeature::PRIVATE | :developer | true + :public | ProjectFeature::PRIVATE | :guest | true + :public | ProjectFeature::PRIVATE | :anonymous | false + :public | ProjectFeature::DISABLED | :maintainer | false + :public | ProjectFeature::DISABLED | :developer | false + :public | ProjectFeature::DISABLED | :guest | false + :public | ProjectFeature::DISABLED | :anonymous | false + :internal | ProjectFeature::ENABLED | :maintainer | true + :internal | ProjectFeature::ENABLED | :developer | true + :internal | ProjectFeature::ENABLED | :guest | true + :internal | ProjectFeature::ENABLED | :anonymous | false + :internal | ProjectFeature::PRIVATE | :maintainer | true + :internal | ProjectFeature::PRIVATE | :developer | true + :internal | ProjectFeature::PRIVATE | :guest | true + :internal | ProjectFeature::PRIVATE | :anonymous | false + :internal | ProjectFeature::DISABLED | :maintainer | false + :internal | ProjectFeature::DISABLED | :developer | false + :internal | ProjectFeature::DISABLED | :guest | false + :internal | ProjectFeature::DISABLED | :anonymous | false + :private | ProjectFeature::ENABLED | :maintainer | true + :private | ProjectFeature::ENABLED | :developer | true + :private | ProjectFeature::ENABLED | :guest | false + :private | ProjectFeature::ENABLED | :anonymous | false + :private | ProjectFeature::PRIVATE | :maintainer | true + :private | ProjectFeature::PRIVATE | :developer | true + :private | ProjectFeature::PRIVATE | :guest | false + :private | ProjectFeature::PRIVATE | :anonymous | false + :private | ProjectFeature::DISABLED | :maintainer | false + :private | ProjectFeature::DISABLED | :developer | false + :private | ProjectFeature::DISABLED | :guest | false + :private | ProjectFeature::DISABLED | :anonymous | false + end + + with_them do + let(:current_user) { user_subject(role) } + let(:project) { project_subject(project_visibility) } + + it 'allows/disallows the abilities based on the monitor feature access level' do + project.project_feature.update!(monitor_access_level: access_level) + + if allowed + expect_allowed(*permissions_abilities(role)) else - guest_environments_permissions + expect_disallowed(*permissions_abilities(role)) end end end @@ -2682,6 +2729,43 @@ RSpec.describe ProjectPolicy do end end + describe 'read_milestone' do + context 'when project is public' do + let(:project) { public_project_in_group } + + context 'and issues and merge requests are private' do + before do + project.project_feature.update!( + issues_access_level: ProjectFeature::PRIVATE, + merge_requests_access_level: ProjectFeature::PRIVATE + ) + end + + context 'when user is an inherited member from the group' do + context 'and user is a guest' do + let(:current_user) { inherited_guest } + + it { is_expected.to be_allowed(:read_milestone) } + end + + context 'and user is a reporter' do + let(:current_user) { inherited_reporter } + + it { is_expected.to be_allowed(:read_milestone) } + end + + context 'and user is a developer' do + let(:current_user) { inherited_developer } + + it { is_expected.to be_allowed(:read_milestone) } + end + end + end + end + end + + private + def project_subject(project_type) case project_type when :public diff --git a/spec/policies/protected_branch_access_policy_spec.rb b/spec/policies/protected_branch_access_policy_spec.rb new file mode 100644 index 00000000000..68a130d666a --- /dev/null +++ b/spec/policies/protected_branch_access_policy_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ProtectedBranchAccessPolicy do + let(:user) { create(:user) } + let(:protected_branch_access) { create(:protected_branch_merge_access_level) } + let(:project) { protected_branch_access.protected_branch.project } + + subject { described_class.new(user, protected_branch_access) } + + context 'as maintainers' do + before do + project.add_maintainer(user) + end + + it 'can be read' do + is_expected.to be_allowed(:read_protected_branch) + end + end + + context 'as guests' do + before do + project.add_guest(user) + end + + it 'can not be read' do + is_expected.to be_disallowed(:read_protected_branch) + end + end +end diff --git a/spec/policies/protected_branch_policy_spec.rb b/spec/policies/protected_branch_policy_spec.rb index bb6dbff18a0..d676de14735 100644 --- a/spec/policies/protected_branch_policy_spec.rb +++ b/spec/policies/protected_branch_policy_spec.rb @@ -10,15 +10,47 @@ RSpec.describe ProtectedBranchPolicy do subject { described_class.new(user, protected_branch) } - it 'branches can be updated via project maintainers' do - project.add_maintainer(user) + context 'as maintainers' do + before do + project.add_maintainer(user) + end - is_expected.to be_allowed(:update_protected_branch) + it 'can be read' do + is_expected.to be_allowed(:read_protected_branch) + end + + it 'can be created' do + is_expected.to be_allowed(:create_protected_branch) + end + + it 'can be updated' do + is_expected.to be_allowed(:update_protected_branch) + end + + it 'can be destroyed' do + is_expected.to be_allowed(:destroy_protected_branch) + end end - it "branches can't be updated by guests" do - project.add_guest(user) + context 'as guests' do + before do + project.add_guest(user) + end + + it 'can be read' do + is_expected.to be_disallowed(:read_protected_branch) + end + + it 'can be created' do + is_expected.to be_disallowed(:create_protected_branch) + end + + it 'can be updated' do + is_expected.to be_disallowed(:update_protected_branch) + end - is_expected.to be_disallowed(:update_protected_branch) + it 'cannot be destroyed' do + is_expected.to be_disallowed(:destroy_protected_branch) + end end end diff --git a/spec/policies/terraform/state_policy_spec.rb b/spec/policies/terraform/state_policy_spec.rb index 82152920997..d75e20a2c66 100644 --- a/spec/policies/terraform/state_policy_spec.rb +++ b/spec/policies/terraform/state_policy_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Terraform::StatePolicy do let_it_be(:project) { create(:project) } - let_it_be(:terraform_state) { create(:terraform_state, project: project)} + let_it_be(:terraform_state) { create(:terraform_state, project: project) } subject { described_class.new(user, terraform_state) } diff --git a/spec/policies/terraform/state_version_policy_spec.rb b/spec/policies/terraform/state_version_policy_spec.rb index 6614e073332..4d41dd44455 100644 --- a/spec/policies/terraform/state_version_policy_spec.rb +++ b/spec/policies/terraform/state_version_policy_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Terraform::StateVersionPolicy do let_it_be(:project) { create(:project) } - let_it_be(:terraform_state) { create(:terraform_state, :with_version, project: project)} + let_it_be(:terraform_state) { create(:terraform_state, :with_version, project: project) } subject { described_class.new(user, terraform_state.latest_version) } -- cgit v1.2.1