diff --git a/ee/app/models/compliance_management/framework.rb b/ee/app/models/compliance_management/framework.rb index 76f6b162e44a03128dfc1c46374ea9b940f8a9e2..a1e801d5d380dc407fe48e5a836d79f10e73b342 100644 --- a/ee/app/models/compliance_management/framework.rb +++ b/ee/app/models/compliance_management/framework.rb @@ -22,7 +22,18 @@ class Framework < ApplicationRecord validates :namespace_id, uniqueness: { scope: :name } validates :pipeline_configuration_full_path, length: { maximum: 255 } + # Remove this validation once support for user namespaces is added. + # https://gitlab.com/gitlab-org/gitlab/-/issues/358423 + validate :namespace_is_root_level_group + scope :with_projects, ->(project_ids) { includes(:projects).where(projects: { id: project_ids }) } scope :with_namespaces, ->(namespace_ids) { includes(:namespace).where(namespaces: { id: namespace_ids })} + + private + + def namespace_is_root_level_group + errors.add(:namespace, 'must be a group, user namespaces are not supported.') unless namespace.group_namespace? + errors.add(:namespace, 'must be a root group.') if namespace.has_parent? + end end end diff --git a/ee/spec/controllers/projects_controller_spec.rb b/ee/spec/controllers/projects_controller_spec.rb index fa58e4e36f5414108cfa95b043b1e62ea141cf3d..225cee28534e6926db1216001d6b61612514ffe3 100644 --- a/ee/spec/controllers/projects_controller_spec.rb +++ b/ee/spec/controllers/projects_controller_spec.rb @@ -526,11 +526,14 @@ end context 'compliance framework settings' do + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } + shared_examples 'no compliance framework is set' do it 'does not change compliance framework for project' do put :update, params: { - namespace_id: project.namespace, + namespace_id: project.group, id: project, project: params } @@ -541,7 +544,7 @@ end context 'when unlicensed' do - let(:framework) { create(:compliance_framework, namespace: project.namespace.root_ancestor) } + let(:framework) { create(:compliance_framework, namespace: project.group.root_ancestor) } let(:params) { { compliance_framework_setting_attributes: { framework: framework.id } } } before do @@ -552,22 +555,23 @@ end context 'when licensed' do - let(:framework) { create(:compliance_framework, namespace: project.namespace.root_ancestor) } + let(:framework) { create(:compliance_framework, namespace: project.group.root_ancestor) } let(:params) { { compliance_framework_setting_attributes: { framework: framework.id } } } before do stub_licensed_features(compliance_framework: true) + project.add_owner(user) end context 'current_user is a project owner' do before do - sign_in(project.first_owner) + sign_in(user) end it 'sets the compliance framework' do put :update, params: { - namespace_id: project.namespace, + namespace_id: project.group, id: project, project: params } diff --git a/ee/spec/graphql/mutations/compliance_management/frameworks/create_spec.rb b/ee/spec/graphql/mutations/compliance_management/frameworks/create_spec.rb index 42b8e8db919aba59ffee36d9833aa633ac0e67e5..b64c8444bcd78752b0f6e98860e258e1425674b8 100644 --- a/ee/spec/graphql/mutations/compliance_management/frameworks/create_spec.rb +++ b/ee/spec/graphql/mutations/compliance_management/frameworks/create_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Mutations::ComplianceManagement::Frameworks::Create do let_it_be(:current_user) { create(:user) } - let_it_be(:namespace) { create(:namespace) } + let_it_be(:namespace) { create(:group) } let(:params) { valid_params } let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } @@ -31,7 +31,7 @@ stub_licensed_features(custom_compliance_frameworks: true, evaluate_group_level_compliance_pipeline: true) end - context 'current_user is not namespace owner' do + context 'current_user is not group namespace owner' do it 'does not create a new compliance framework' do expect { subject }.not_to change { namespace.compliance_management_frameworks.count } end @@ -42,8 +42,6 @@ end context 'current_user is group owner' do - let_it_be(:namespace) { create(:group) } - before do namespace.add_owner(current_user) end @@ -53,12 +51,14 @@ end end - context 'current_user is namespace owner' do + context 'current_user is personal namespace owner' do + let_it_be(:namespace) { create(:user_namespace) } + let(:current_user) { namespace.owner } context 'framework parameters are valid' do - it 'creates a new compliance framework' do - expect { subject }.to change { namespace.compliance_management_frameworks.count }.by 1 + it 'does not create a new compliance framework' do + expect { subject }.not_to change { namespace.compliance_management_frameworks.count } end end diff --git a/ee/spec/graphql/mutations/projects/set_compliance_framework_spec.rb b/ee/spec/graphql/mutations/projects/set_compliance_framework_spec.rb index b52a4a4f9d16ac63a20b8551999a33e459161377..e36d14f6388d7cf50afb0a45dc1d0cafcef59e88 100644 --- a/ee/spec/graphql/mutations/projects/set_compliance_framework_spec.rb +++ b/ee/spec/graphql/mutations/projects/set_compliance_framework_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' RSpec.describe Mutations::Projects::SetComplianceFramework do - let_it_be(:namespace) { create(:namespace) } - let_it_be(:framework) { create(:compliance_framework, namespace: namespace) } - let_it_be(:project) { create(:project, :repository, namespace: namespace) } + let_it_be(:group) { create(:group) } + let_it_be(:framework) { create(:compliance_framework, namespace: group) } + let_it_be(:project) { create(:project, :repository, group: group) } let_it_be(:current_user) { create(:user) } let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } @@ -67,7 +67,10 @@ end context 'current_user is a project owner' do - let(:current_user) { project.first_owner } + before do + group.add_owner(current_user) + project.add_owner(current_user) + end it_behaves_like "the user can change a project's compliance framework" end diff --git a/ee/spec/lib/ee/audit/compliance_framework_changes_auditor_spec.rb b/ee/spec/lib/ee/audit/compliance_framework_changes_auditor_spec.rb index 67876a0b77750d376d016c166b9234e929c713b9..3869f7edce4bac8f8f620ee3c89c6969b0c6f4c9 100644 --- a/ee/spec/lib/ee/audit/compliance_framework_changes_auditor_spec.rb +++ b/ee/spec/lib/ee/audit/compliance_framework_changes_auditor_spec.rb @@ -5,8 +5,9 @@ RSpec.describe EE::Audit::ComplianceFrameworkChangesAuditor do describe 'auditing compliance framework changes' do let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } - let(:project) { create(:project) } + let(:project) { create(:project, group: group) } before do project.reload @@ -54,7 +55,7 @@ context 'when the framework is changed' do before do - project.update!(compliance_management_framework: create(:compliance_framework, namespace: project.namespace, name: 'SOX')) + project.update!(compliance_management_framework: create(:compliance_framework, namespace: project.group, name: 'SOX')) end it 'adds an audit event' do diff --git a/ee/spec/models/compliance_management/framework_spec.rb b/ee/spec/models/compliance_management/framework_spec.rb index ca7d9c5b6d1b7ea96e05cf17ae3148411b02ff64..f79d85f32acf4a0f2d2220046201e0e5b4163266 100644 --- a/ee/spec/models/compliance_management/framework_spec.rb +++ b/ee/spec/models/compliance_management/framework_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe ComplianceManagement::Framework do - context 'validation' do + describe 'validations' do let_it_be(:framework) { create(:compliance_framework) } subject { framework } @@ -14,6 +14,37 @@ it { is_expected.to validate_length_of(:description).is_at_most(255) } it { is_expected.to validate_length_of(:color).is_at_most(10) } it { is_expected.to validate_length_of(:pipeline_configuration_full_path).is_at_most(255) } + + describe 'namespace_is_root_level_group' do + context 'when namespace is a root group' do + let_it_be(:namespace) { create(:group) } + let_it_be(:framework) { build(:compliance_framework, namespace: namespace) } + + it 'is valid' do + expect(framework).to be_valid + end + end + + context 'when namespace is a user namespace' do + let_it_be(:namespace) { create(:user_namespace) } + let_it_be(:framework) { build(:compliance_framework, namespace: namespace) } + + it 'is invalid' do + expect(framework).not_to be_valid + expect(framework.errors[:namespace]).to include('must be a group, user namespaces are not supported.') + end + end + + context 'when namespace is a subgroup' do + let_it_be(:namespace) { create(:group, :nested) } + let_it_be(:framework) { build(:compliance_framework, namespace: namespace) } + + it 'is invalid' do + expect(framework).not_to be_valid + expect(framework.errors[:namespace]).to include('must be a root group.') + end + end + end end describe 'color' do diff --git a/ee/spec/requests/api/graphql/mutations/compliance_management/frameworks/create_spec.rb b/ee/spec/requests/api/graphql/mutations/compliance_management/frameworks/create_spec.rb index b7a3638f5d5909838a04f6672b793f26a5a7e4bd..dc7b1dc83ee065dd7fbdd5e31500d007075120c6 100644 --- a/ee/spec/requests/api/graphql/mutations/compliance_management/frameworks/create_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/compliance_management/frameworks/create_spec.rb @@ -5,8 +5,8 @@ RSpec.describe 'Create a Compliance Framework' do include GraphqlHelpers - let_it_be(:namespace) { create(:namespace) } - let_it_be(:current_user) { namespace.owner } + let_it_be(:namespace) { create(:group) } + let_it_be(:current_user) { create(:user) } let(:mutation) do graphql_mutation( @@ -54,6 +54,7 @@ def mutation_response context 'pipeline configuration feature is unlicensed' do before do stub_licensed_features(custom_compliance_frameworks: true, evaluate_group_level_compliance_pipeline: false) + namespace.add_owner(current_user) post_graphql_mutation(mutation, current_user: current_user) end @@ -65,29 +66,43 @@ def mutation_response stub_licensed_features(custom_compliance_frameworks: true, evaluate_group_level_compliance_pipeline: true) end - context 'current_user is namespace owner' do - it_behaves_like 'a mutation that creates a compliance framework' - end + context 'namespace is a personal namespace' do + let_it_be(:namespace) { create(:user_namespace) } - context 'current_user is group owner' do - let_it_be(:namespace) { create(:group) } - let_it_be(:current_user) { create(:user) } + context 'current_user is namespace owner' do + let(:current_user) { namespace.owner } - before do - namespace.add_owner(current_user) - end + it_behaves_like 'a mutation that returns errors in the response', errors: ['Failed to create framework', + 'Namespace must be a group, user namespaces are not supported.'] - it_behaves_like 'a mutation that creates a compliance framework' + it 'does not create a new compliance framework' do + expect { subject }.not_to change { namespace.compliance_management_frameworks.count } + end + end end - context 'current_user is not namespace owner' do - let_it_be(:current_user) { create(:user) } + context 'namespace is a group' do + context 'current_user is group owner' do + before do + namespace.add_owner(current_user) + end - it 'does not create a new compliance framework' do - expect { subject }.not_to change { namespace.compliance_management_frameworks.count } + it_behaves_like 'a mutation that creates a compliance framework' end - it_behaves_like 'a mutation that returns errors in the response', errors: ['Not permitted to create framework'] + context 'current_user is not a group owner' do + context 'current_user is group owner' do + before do + namespace.add_maintainer(current_user) + end + + it 'does not create a new compliance framework' do + expect { subject }.not_to change { namespace.compliance_management_frameworks.count } + end + + it_behaves_like 'a mutation that returns errors in the response', errors: ['Not permitted to create framework'] + end + end end end end diff --git a/ee/spec/requests/api/graphql/mutations/projects/set_compliance_framework_spec.rb b/ee/spec/requests/api/graphql/mutations/projects/set_compliance_framework_spec.rb index 66fb84f17a6f459cc3a56e6d59eaea70c3fa38ff..72076e5db4fd1ef9ed37e88bdd4c9078e83fbacd 100644 --- a/ee/spec/requests/api/graphql/mutations/projects/set_compliance_framework_spec.rb +++ b/ee/spec/requests/api/graphql/mutations/projects/set_compliance_framework_spec.rb @@ -5,10 +5,14 @@ RSpec.describe 'Set project compliance framework' do include GraphqlHelpers - let_it_be(:namespace) { create(:namespace) } + let_it_be(:namespace) { create(:group) } let_it_be(:project) { create(:project, namespace: namespace) } let_it_be(:framework) { create(:compliance_framework, namespace: namespace) } - let_it_be(:current_user) { project.first_owner } + let_it_be(:current_user) { create(:user) } + + before do + namespace.add_owner(current_user) + end let(:variables) { { project_id: GitlabSchema.id_from_object(project).to_s, compliance_framework_id: GitlabSchema.id_from_object(framework).to_s } } diff --git a/ee/spec/requests/api/graphql/namespace/compliance_frameworks_spec.rb b/ee/spec/requests/api/graphql/namespace/compliance_frameworks_spec.rb index d96845aa264c1b548bb963aea2c63480c5dd38be..c31f1d3b1c324cc89f223bdbce5956de693d5578 100644 --- a/ee/spec/requests/api/graphql/namespace/compliance_frameworks_spec.rb +++ b/ee/spec/requests/api/graphql/namespace/compliance_frameworks_spec.rb @@ -5,9 +5,10 @@ RSpec.describe 'getting a list of compliance frameworks for a root namespace' do include GraphqlHelpers - let_it_be(:namespace) { create(:namespace) } + let_it_be(:namespace) { create(:group) } let_it_be(:compliance_framework_1) { create(:compliance_framework, namespace: namespace, name: 'Test1') } let_it_be(:compliance_framework_2) { create(:compliance_framework, namespace: namespace, name: 'Test2') } + let_it_be(:current_user) { create(:user) } let(:path) { %i[namespace compliance_frameworks nodes] } @@ -20,10 +21,9 @@ context 'when authenticated as the namespace owner' do before do stub_licensed_features(custom_compliance_frameworks: true) + namespace.add_owner(current_user) end - let(:current_user) { namespace.owner } - it 'returns the groups compliance frameworks' do post_graphql(query, current_user: current_user) diff --git a/ee/spec/services/compliance_management/frameworks/create_service_spec.rb b/ee/spec/services/compliance_management/frameworks/create_service_spec.rb index 9b74a3a6cb2a1b53384f0398d3d1be0392751b40..0585cf152188f658d691e9d2077466bbb1210eae 100644 --- a/ee/spec/services/compliance_management/frameworks/create_service_spec.rb +++ b/ee/spec/services/compliance_management/frameworks/create_service_spec.rb @@ -3,7 +3,12 @@ require 'spec_helper' RSpec.describe ComplianceManagement::Frameworks::CreateService do - let_it_be_with_refind(:namespace) { create(:user_namespace) } + let_it_be_with_refind(:namespace) { create(:group) } + let_it_be(:current_user) { create(:user) } + + before do + namespace.add_owner(current_user) + end let(:params) do { @@ -18,7 +23,7 @@ stub_licensed_features(custom_compliance_frameworks: false) end - subject { described_class.new(namespace: namespace, params: params, current_user: namespace.owner) } + subject { described_class.new(namespace: namespace, params: params, current_user: current_user) } it 'does not create a new compliance framework' do expect { subject.execute }.not_to change { ComplianceManagement::Framework.count } @@ -56,7 +61,7 @@ end context 'when using invalid parameters' do - subject { described_class.new(namespace: namespace, params: params.except(:name), current_user: namespace.owner) } + subject { described_class.new(namespace: namespace, params: params.except(:name), current_user: current_user) } let(:response) { subject.execute } @@ -79,7 +84,7 @@ end context 'when pipeline_configuration_full_path parameter is used and feature is not available' do - subject { described_class.new(namespace: namespace, params: params, current_user: namespace.owner) } + subject { described_class.new(namespace: namespace, params: params, current_user: current_user) } before do params[:pipeline_configuration_full_path] = '.compliance-gitlab-ci.yml@compliance/hipaa' @@ -95,7 +100,7 @@ end context 'when using parameters for a valid compliance framework' do - subject { described_class.new(namespace: namespace, params: params, current_user: namespace.owner) } + subject { described_class.new(namespace: namespace, params: params, current_user: current_user) } it 'audits the changes' do expect { subject.execute }.to change { AuditEvent.count }.by(1) diff --git a/ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb b/ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb index fffc9d5e91820f29726cf4642d3ea96000568baa..ca07c1a4c28ee33808aec2749810352e4c19e2d7 100644 --- a/ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb +++ b/ee/spec/services/compliance_management/frameworks/destroy_service_spec.rb @@ -3,15 +3,20 @@ require 'spec_helper' RSpec.describe ComplianceManagement::Frameworks::DestroyService do - let_it_be_with_refind(:namespace) { create(:user_namespace) } + let_it_be_with_refind(:namespace) { create(:group) } let_it_be_with_refind(:framework) { create(:compliance_framework, namespace: namespace) } + let_it_be(:user) { create(:user) } + + before do + namespace.add_owner(user) + end context 'when feature is disabled' do before do stub_licensed_features(custom_compliance_frameworks: false) end - subject { described_class.new(framework: framework, current_user: namespace.owner) } + subject { described_class.new(framework: framework, current_user: user) } it 'does not destroy the compliance framework' do expect { subject.execute }.not_to change { ComplianceManagement::Framework.count } @@ -28,7 +33,7 @@ end context 'when current user is namespace owner' do - subject { described_class.new(framework: framework, current_user: namespace.owner) } + subject { described_class.new(framework: framework, current_user: user) } it 'destroys the compliance framework' do expect { subject.execute }.to change { ComplianceManagement::Framework.count }.by(-1) diff --git a/ee/spec/services/compliance_management/frameworks/update_service_spec.rb b/ee/spec/services/compliance_management/frameworks/update_service_spec.rb index f7c0177e49811605bc9233edf239f84a4c8d1810..c242d1c244ddda4351bec732f07bf967b0432e98 100644 --- a/ee/spec/services/compliance_management/frameworks/update_service_spec.rb +++ b/ee/spec/services/compliance_management/frameworks/update_service_spec.rb @@ -3,10 +3,14 @@ require 'spec_helper' RSpec.describe ComplianceManagement::Frameworks::UpdateService do - let_it_be_with_refind(:namespace) { create(:user_namespace) } + let_it_be_with_refind(:namespace) { create(:group) } let_it_be_with_refind(:framework) { create(:compliance_framework, namespace: namespace) } + let_it_be(:current_user) { create(:user) } + + before do + namespace.add_owner(current_user) + end - let(:current_user) { namespace.owner } let(:params) { { color: '#000001', description: 'New Description', name: 'New Name' } } subject { described_class.new(framework: framework, current_user: current_user, params: params) } diff --git a/ee/spec/services/projects/update_service_spec.rb b/ee/spec/services/projects/update_service_spec.rb index 5b4107207cc89dfa329f0bd26e34957bc6ee5ae4..5d1dba4e756f85e02c95a956ebb43231ce71fc03 100644 --- a/ee/spec/services/projects/update_service_spec.rb +++ b/ee/spec/services/projects/update_service_spec.rb @@ -348,12 +348,16 @@ end context 'custom compliance frameworks' do - let(:framework) { create(:compliance_framework, namespace: project.namespace) } + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } + let(:framework) { create(:compliance_framework, namespace: group) } let(:opts) { { compliance_framework_setting_attributes: { framework: framework.id } } } context 'when current_user has :admin_compliance_framework ability' do before do stub_licensed_features(compliance_framework: true) + group.add_owner(user) + project.add_owner(user) end it 'updates the framework' do