Commit ea8c370a authored by Etienne Baqué's avatar Etienne Baqué

Merge branch '349933-all-group-members-read-compliance-frameworks' into 'master'

Allow all users within a group to view all compliance frameworks

See merge request gitlab-org/gitlab!79133
parents 871e2da1 92ac5dc3
...@@ -5,6 +5,8 @@ module Resolvers ...@@ -5,6 +5,8 @@ module Resolvers
class FrameworkResolver < BaseResolver class FrameworkResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource include Gitlab::Graphql::Authorize::AuthorizeResource
authorize :read_compliance_framework
type ::Types::ComplianceManagement::ComplianceFrameworkType.connection_type, null: true type ::Types::ComplianceManagement::ComplianceFrameworkType.connection_type, null: true
argument :id, ::Types::GlobalIDType[::ComplianceManagement::Framework], argument :id, ::Types::GlobalIDType[::ComplianceManagement::Framework],
...@@ -31,8 +33,6 @@ module Resolvers ...@@ -31,8 +33,6 @@ module Resolvers
def evaluate(namespace_ids, by_namespace_id, loader) def evaluate(namespace_ids, by_namespace_id, loader)
frameworks(namespace_ids).group_by(&:namespace_id).each do |ns_id, group| frameworks(namespace_ids).group_by(&:namespace_id).each do |ns_id, group|
by_namespace_id[ns_id].each do |fw_id| by_namespace_id[ns_id].each do |fw_id|
authorize!
group.each do |fw| group.each do |fw|
next unless fw_id.nil? || fw_id.to_i == fw.id next unless fw_id.nil? || fw_id.to_i == fw.id
...@@ -45,10 +45,6 @@ module Resolvers ...@@ -45,10 +45,6 @@ module Resolvers
def frameworks(namespace_ids) def frameworks(namespace_ids)
::ComplianceManagement::Framework.with_namespaces(namespace_ids) ::ComplianceManagement::Framework.with_namespaces(namespace_ids)
end end
def authorize!
Ability.allowed?(context[:current_user], :admin_compliance_framework, object) || raise_resource_not_available_error!
end
end end
end end
end end
...@@ -12,8 +12,17 @@ module ComplianceManagement ...@@ -12,8 +12,17 @@ module ComplianceManagement
@subject.namespace.feature_available?(:evaluate_group_level_compliance_pipeline) @subject.namespace.feature_available?(:evaluate_group_level_compliance_pipeline)
end end
condition(:read_root_group) do
@user.can?(:read_group, @subject.namespace.root_ancestor)
end
rule { can?(:owner_access) & custom_compliance_frameworks_enabled }.policy do rule { can?(:owner_access) & custom_compliance_frameworks_enabled }.policy do
enable :manage_compliance_framework enable :manage_compliance_framework
enable :read_compliance_framework
end
rule { read_root_group & custom_compliance_frameworks_enabled }.policy do
enable :read_compliance_framework
end end
rule { can?(:owner_access) & group_level_compliance_pipeline_enabled }.policy do rule { can?(:owner_access) & group_level_compliance_pipeline_enabled }.policy do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :compliance_framework, class: 'ComplianceManagement::Framework' do factory :compliance_framework, class: 'ComplianceManagement::Framework' do
namespace association :namespace, factory: :group
name { 'GDPR' } name { 'GDPR' }
description { 'The General Data Protection Regulation (GDPR) is a regulation in EU law on data protection and privacy in the European Union (EU) and the European Economic Area (EEA).' } description { 'The General Data Protection Regulation (GDPR) is a regulation in EU law on data protection and privacy in the European Union (EU) and the European Economic Area (EEA).' }
......
...@@ -5,13 +5,18 @@ require 'spec_helper' ...@@ -5,13 +5,18 @@ require 'spec_helper'
RSpec.describe Mutations::ComplianceManagement::Frameworks::Destroy do RSpec.describe Mutations::ComplianceManagement::Frameworks::Destroy do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:framework) { create(:compliance_framework) } let_it_be(:namespace) { create(:group) }
let_it_be(:framework) { create(:compliance_framework, namespace: namespace) }
let(:user) { framework.namespace.owner } let(:user) { create(:user) }
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
subject { mutation.resolve(id: global_id_of(framework)) } subject { mutation.resolve(id: global_id_of(framework)) }
before do
namespace.add_owner(user)
end
shared_examples 'a compliance framework that cannot be found' do shared_examples 'a compliance framework that cannot be found' do
it 'raises an error' do it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
......
...@@ -5,9 +5,10 @@ require 'spec_helper' ...@@ -5,9 +5,10 @@ require 'spec_helper'
RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:framework) { create(:compliance_framework) } let_it_be(:namespace) { create(:group) }
let_it_be(:framework) { create(:compliance_framework, namespace: namespace) }
let(:user) { framework.namespace.owner } let(:user) { create(:user) }
let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) } let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
let(:params) do let(:params) do
{ {
...@@ -17,6 +18,10 @@ RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do ...@@ -17,6 +18,10 @@ RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do
} }
end end
before do
namespace.add_owner(user)
end
subject { mutation.resolve(id: global_id_of(framework), params: params) } subject { mutation.resolve(id: global_id_of(framework), params: params) }
context 'feature is licensed' do context 'feature is licensed' do
...@@ -38,7 +43,9 @@ RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do ...@@ -38,7 +43,9 @@ RSpec.describe Mutations::ComplianceManagement::Frameworks::Update do
end end
context 'current_user is not authorized to update framework' do context 'current_user is not authorized to update framework' do
let_it_be(:user) { create(:user) } before do
namespace.update!(owners: [])
end
it 'raises an error' do it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
......
...@@ -3,47 +3,63 @@ ...@@ -3,47 +3,63 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe ComplianceManagement::FrameworkPolicy do RSpec.describe ComplianceManagement::FrameworkPolicy do
let_it_be_with_refind(:framework) { create(:compliance_framework) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let(:user) { framework.namespace.owner } let_it_be_with_refind(:framework) { create(:compliance_framework, namespace: group) }
subject { described_class.new(user, framework) } subject { described_class.new(user, framework) }
shared_examples 'full access to compliance framework administration' do
it { is_expected.to be_allowed(:manage_compliance_framework) }
it { is_expected.to be_allowed(:read_compliance_framework) }
it { is_expected.to be_allowed(:manage_group_level_compliance_pipeline_config) }
end
shared_examples 'no access to compliance framework administration' do
it { is_expected.to be_disallowed(:manage_compliance_framework) }
it { is_expected.to be_disallowed(:read_compliance_framework) }
it { is_expected.to be_disallowed(:manage_group_level_compliance_pipeline_config) }
end
context 'feature is licensed' do context 'feature is licensed' do
before do before do
stub_licensed_features(custom_compliance_frameworks: true, evaluate_group_level_compliance_pipeline: true) stub_licensed_features(custom_compliance_frameworks: true, evaluate_group_level_compliance_pipeline: true)
end end
context 'user is namespace owner' do
it { is_expected.to be_allowed(:manage_compliance_framework) }
it { is_expected.to be_allowed(:manage_group_level_compliance_pipeline_config) }
end
context 'user is group owner' do context 'user is group owner' do
let_it_be(:group) { create(:group) }
let_it_be(:framework) { create(:compliance_framework, namespace: group) }
let_it_be(:user) { create(:user) }
before do before do
group.add_owner(user) group.add_owner(user)
end end
it { is_expected.to be_allowed(:manage_compliance_framework) } it_behaves_like 'full access to compliance framework administration'
it { is_expected.to be_allowed(:manage_group_level_compliance_pipeline_config) }
end end
context 'user is not namespace owner' do context 'user is not a member of the namespace' do
let(:user) { build(:user) } let(:user) { create(:user) }
it { is_expected.to be_disallowed(:manage_compliance_framework) } it_behaves_like 'no access to compliance framework administration'
it { is_expected.to be_disallowed(:manage_group_level_compliance_pipeline_config) }
end end
context 'user is an admin', :enable_admin_mode do context 'user is an admin', :enable_admin_mode do
let(:user) { build(:admin) } let(:user) { build(:admin) }
it { is_expected.to be_allowed(:manage_compliance_framework) } it_behaves_like 'full access to compliance framework administration'
it { is_expected.to be_allowed(:manage_group_level_compliance_pipeline_config) } end
context 'user is subgroup member but not the owner of the root namespace' do
let_it_be(:user) { create(:user) }
let(:subgroup) { create(:group, :private, parent: group) }
before do
group.add_developer(user)
subgroup.add_maintainer(user)
end
it { is_expected.to be_allowed(:read_compliance_framework) }
it { is_expected.to be_disallowed(:manage_compliance_framework) }
it { is_expected.to be_disallowed(:manage_group_level_compliance_pipeline_config) }
end end
end end
...@@ -52,7 +68,6 @@ RSpec.describe ComplianceManagement::FrameworkPolicy do ...@@ -52,7 +68,6 @@ RSpec.describe ComplianceManagement::FrameworkPolicy do
stub_licensed_features(custom_compliance_frameworks: false, evaluate_group_level_compliance_pipeline: false) stub_licensed_features(custom_compliance_frameworks: false, evaluate_group_level_compliance_pipeline: false)
end end
it { is_expected.to be_disallowed(:manage_compliance_framework) } it_behaves_like 'no access to compliance framework administration'
it { is_expected.to be_disallowed(:manage_group_level_compliance_pipeline_config) }
end end
end end
...@@ -5,8 +5,10 @@ require 'spec_helper' ...@@ -5,8 +5,10 @@ require 'spec_helper'
RSpec.describe 'Delete a compliance framework' do RSpec.describe 'Delete a compliance framework' do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:framework) { create(:compliance_framework) } let_it_be(:namespace) { create(:group) }
let_it_be(:framework) { create(:compliance_framework, namespace: namespace) }
let(:current_user) { create(:user) }
let(:mutation) { graphql_mutation(:destroy_compliance_framework, { id: global_id_of(framework) }) } let(:mutation) { graphql_mutation(:destroy_compliance_framework, { id: global_id_of(framework) }) }
subject { post_graphql_mutation(mutation, current_user: current_user) } subject { post_graphql_mutation(mutation, current_user: current_user) }
...@@ -16,8 +18,6 @@ RSpec.describe 'Delete a compliance framework' do ...@@ -16,8 +18,6 @@ RSpec.describe 'Delete a compliance framework' do
end end
context 'feature is unlicensed' do context 'feature is unlicensed' do
let_it_be(:current_user) { framework.namespace.owner }
before do before do
stub_licensed_features(custom_compliance_frameworks: false) stub_licensed_features(custom_compliance_frameworks: false)
end end
...@@ -36,7 +36,9 @@ RSpec.describe 'Delete a compliance framework' do ...@@ -36,7 +36,9 @@ RSpec.describe 'Delete a compliance framework' do
end end
context 'current_user is namespace owner' do context 'current_user is namespace owner' do
let_it_be(:current_user) { framework.namespace.owner } before do
namespace.add_owner(current_user)
end
it 'has no errors' do it 'has no errors' do
subject subject
...@@ -50,14 +52,12 @@ RSpec.describe 'Delete a compliance framework' do ...@@ -50,14 +52,12 @@ RSpec.describe 'Delete a compliance framework' do
end end
context 'current_user is not namespace owner' do context 'current_user is not namespace owner' do
let_it_be(:current_user) { create(:user) } it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it 'does not destroy a compliance framework' do it 'does not destroy a compliance framework' do
expect { subject }.not_to change { ComplianceManagement::Framework.count } expect { subject }.not_to change { ComplianceManagement::Framework.count }
end end
it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end end
end end
end end
...@@ -5,10 +5,11 @@ require 'spec_helper' ...@@ -5,10 +5,11 @@ require 'spec_helper'
RSpec.describe 'Update a compliance framework' do RSpec.describe 'Update a compliance framework' do
include GraphqlHelpers include GraphqlHelpers
let_it_be(:framework) { create(:compliance_framework) } let_it_be(:namespace) { create(:group) }
let_it_be(:framework) { create(:compliance_framework, namespace: namespace) }
let(:current_user) { create(:user) }
let(:mutation) { graphql_mutation(:update_compliance_framework, { id: global_id_of(framework), **params }) } let(:mutation) { graphql_mutation(:update_compliance_framework, { id: global_id_of(framework), **params }) }
let(:current_user) { framework.namespace.owner }
let(:params) do let(:params) do
{ {
params: { params: {
...@@ -21,6 +22,10 @@ RSpec.describe 'Update a compliance framework' do ...@@ -21,6 +22,10 @@ RSpec.describe 'Update a compliance framework' do
subject { post_graphql_mutation(mutation, current_user: current_user) } subject { post_graphql_mutation(mutation, current_user: current_user) }
before do
namespace.add_owner(current_user)
end
def mutation_response def mutation_response
graphql_mutation_response(:update_compliance_framework) graphql_mutation_response(:update_compliance_framework)
end end
...@@ -94,7 +99,9 @@ RSpec.describe 'Update a compliance framework' do ...@@ -94,7 +99,9 @@ RSpec.describe 'Update a compliance framework' do
end end
context 'current_user is not permitted to update framework' do context 'current_user is not permitted to update framework' do
let_it_be(:current_user) { create(:user) } before do
namespace.update!(owners: [])
end
it_behaves_like 'a mutation that returns top-level errors', it_behaves_like 'a mutation that returns top-level errors',
errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR] errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
......
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