Commit 1eb7e79c authored by Max Woolf's avatar Max Woolf

Create compliance framework creation service

Adds a new service:

ComplianceManagement::Frameworks::CreateService to
GitLab EE.
parent c7c3323e
...@@ -133,6 +133,7 @@ class License < ApplicationRecord ...@@ -133,6 +133,7 @@ class License < ApplicationRecord
container_scanning container_scanning
coverage_fuzzing coverage_fuzzing
credentials_inventory credentials_inventory
custom_compliance_frameworks
dast dast
dependency_scanning dependency_scanning
devops_adoption devops_adoption
......
...@@ -5,6 +5,7 @@ module EE ...@@ -5,6 +5,7 @@ module EE
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
condition(:custom_compliance_frameworks_enabled) { License.feature_available?(:custom_compliance_frameworks) }
condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? } condition(:over_storage_limit, scope: :subject) { @subject.over_storage_limit? }
rule { admin & is_gitlab_com }.enable :update_subscription_limit rule { admin & is_gitlab_com }.enable :update_subscription_limit
...@@ -12,6 +13,10 @@ module EE ...@@ -12,6 +13,10 @@ module EE
rule { over_storage_limit }.policy do rule { over_storage_limit }.policy do
prevent :create_projects prevent :create_projects
end end
rule { (owner | admin) & custom_compliance_frameworks_enabled }.policy do
enable :create_custom_compliance_frameworks
end
end end
end end
end end
# frozen_string_literal: true
module ComplianceManagement
module Frameworks
class CreateService < BaseService
attr_reader :namespace, :params, :current_user, :framework
def initialize(namespace:, params:, current_user:)
@namespace = namespace.root_ancestor
@params = params
@current_user = current_user
@framework = ComplianceManagement::Framework.new
end
def execute
return ServiceResponse.error(message: _('Feature not available')) unless permitted?
framework.assign_attributes(
namespace: namespace,
name: params[:name],
description: params[:description],
color: params[:color]
)
framework.save ? success : error
end
private
def permitted?
can?(current_user, :create_custom_compliance_frameworks, namespace)
end
def success
ServiceResponse.success(payload: { framework: framework })
end
def error
ServiceResponse.error(message: _('Failed to create framework'), payload: framework.errors )
end
end
end
end
...@@ -23,6 +23,40 @@ RSpec.describe NamespacePolicy do ...@@ -23,6 +23,40 @@ RSpec.describe NamespacePolicy do
end end
end end
context 'custom_compliance_frameworks_enabled' do
let(:current_user) { owner }
context 'is licensed' do
before do
stub_licensed_features(custom_compliance_frameworks: true)
end
context 'current_user is namespace owner' do
it { is_expected.to be_allowed(:create_custom_compliance_frameworks) }
end
context 'current_user is not namespace owner' do
let(:current_user) { build_stubbed(:user) }
it { is_expected.to be_disallowed(:create_custom_compliance_frameworks) }
end
context 'current_user is administrator', :enable_admin_mode do
let(:current_user) { build_stubbed(:admin) }
it { is_expected.to be_allowed(:create_custom_compliance_frameworks) }
end
end
context 'not licensed' do
before do
stub_licensed_features(custom_compliance_frameworks: false)
end
it { is_expected.to be_disallowed(:create_custom_compliance_frameworks) }
end
end
context ':over_storage_limit' do context ':over_storage_limit' do
let(:current_user) { owner } let(:current_user) { owner }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ComplianceManagement::Frameworks::CreateService do
let_it_be(:namespace) { create(:namespace) }
let(:params) do
{
name: 'GDPR',
description: 'The EUs data protection directive',
color: '#abc123'
}
end
context 'custom_compliance_frameworks is disabled' do
before do
stub_licensed_features(custom_compliance_frameworks: false)
end
subject { described_class.new(namespace: namespace, params: params, current_user: namespace.owner) }
it 'does not create a new compliance framework' do
expect { subject.execute }.not_to change { ComplianceManagement::Framework.count }
end
it 'responds with an error message' do
expect(subject.execute.message).to eq('Feature not available')
end
end
context 'custom_compliance_frameworks is enabled' do
before do
stub_licensed_features(custom_compliance_frameworks: true)
end
context 'namespace has a parent' do
let_it_be(:namespace) { create(:namespace, :with_hierarchy) }
let(:descendant) { namespace.descendants.first }
subject { described_class.new(namespace: descendant, params: params, current_user: namespace.owner) }
it 'responds with a successful service response' do
expect(subject.execute.success?).to be true
end
it 'creates the new framework in the root namespace' do
expect(subject.execute.payload[:framework].namespace).to eq(namespace)
end
end
context 'when using invalid parameters' do
subject { described_class.new(namespace: namespace, params: params.except(:name), current_user: namespace.owner) }
let(:response) { subject.execute }
it 'responds with an error service response' do
expect(response.success?).to eq false
expect(response.payload.messages[:name]).to contain_exactly "can't be blank"
end
end
context 'when creating a compliance framework for a namespace that current_user is not the owner of' do
subject { described_class.new(namespace: namespace, params: params, current_user: create(:user)) }
it 'responds with an error service response' do
expect(subject.execute.success?).to be false
end
it 'does not create a new compliance framework' do
expect { subject.execute }.not_to change { ComplianceManagement::Framework.count }
end
end
context 'when using parameters for a valid compliance framework' do
subject { described_class.new(namespace: namespace, params: params, current_user: namespace.owner) }
it 'creates a new compliance framework' do
expect { subject.execute }.to change { ComplianceManagement::Framework.count }.by(1)
end
it 'responds with a successful service response' do
expect(subject.execute.success?).to be true
end
it 'has the expected attributes' do
framework = subject.execute.payload[:framework]
expect(framework.name).to eq('GDPR')
expect(framework.description).to eq('The EUs data protection directive')
expect(framework.color).to eq('#abc123')
end
end
end
end
...@@ -11288,6 +11288,9 @@ msgstr "" ...@@ -11288,6 +11288,9 @@ msgstr ""
msgid "Failed to create a branch for this issue. Please try again." msgid "Failed to create a branch for this issue. Please try again."
msgstr "" msgstr ""
msgid "Failed to create framework"
msgstr ""
msgid "Failed to create import label for jira import." msgid "Failed to create import label for jira import."
msgstr "" msgstr ""
...@@ -11513,6 +11516,9 @@ msgstr "" ...@@ -11513,6 +11516,9 @@ msgstr ""
msgid "Feature flag was successfully removed." msgid "Feature flag was successfully removed."
msgstr "" msgstr ""
msgid "Feature not available"
msgstr ""
msgid "FeatureFlags|%d user" msgid "FeatureFlags|%d user"
msgid_plural "FeatureFlags|%d users" msgid_plural "FeatureFlags|%d users"
msgstr[0] "" msgstr[0] ""
......
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