Merge branch '343268-add-mutation-to-unlink-policy-project' into 'master'

Add mutation to unlink policy project

See merge request gitlab-org/gitlab!72831
This commit is contained in:
Kamil Trzciński 2021-10-27 15:16:21 +00:00
commit cb5df34aa1
7 changed files with 189 additions and 0 deletions

View file

@ -4097,6 +4097,26 @@ Input type: `SecurityPolicyProjectCreateInput`
| <a id="mutationsecuritypolicyprojectcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationsecuritypolicyprojectcreateproject"></a>`project` | [`Project`](#project) | Security Policy Project that was created. |
### `Mutation.securityPolicyProjectUnassign`
Unassigns the security policy project for the given project(`project_path`).
Input type: `SecurityPolicyProjectUnassignInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsecuritypolicyprojectunassignclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsecuritypolicyprojectunassignprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationsecuritypolicyprojectunassignclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationsecuritypolicyprojectunassignerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.terraformStateDelete`
Input type: `TerraformStateDeleteInput`

View file

@ -81,6 +81,7 @@ module MutationType
mount_mutation ::Mutations::Projects::SetComplianceFramework
mount_mutation ::Mutations::SecurityPolicy::CommitScanExecutionPolicy
mount_mutation ::Mutations::SecurityPolicy::AssignSecurityPolicyProject
mount_mutation ::Mutations::SecurityPolicy::UnassignSecurityPolicyProject
mount_mutation ::Mutations::SecurityPolicy::CreateSecurityPolicyProject
mount_mutation ::Mutations::Security::CiConfiguration::ConfigureDependencyScanning
mount_mutation ::Mutations::AuditEvents::ExternalAuditEventDestinations::Create

View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Mutations
module SecurityPolicy
class UnassignSecurityPolicyProject < BaseMutation
include FindsProject
graphql_name 'SecurityPolicyProjectUnassign'
description 'Unassigns the security policy project for the given project(`project_path`).'
authorize :update_security_orchestration_policy_project
argument :project_path, GraphQL::Types::ID,
required: true,
description: 'Full path of the project.'
def resolve(args)
project = authorized_find!(args[:project_path])
result = unassign_project(project)
{
errors: result.success? ? [] : [result.message]
}
end
private
def unassign_project(project)
::Security::Orchestration::UnassignService
.new(project, current_user)
.execute
end
end
end
end

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Security
module Orchestration
class UnassignService < ::BaseService
def execute
return error(_('Policy project doesn\'t exist')) unless security_orchestration_policy_configuration
result = security_orchestration_policy_configuration.delete
return success if result
error(project.security_orchestration_policy_configuration.errors.full_messages.to_sentence)
end
private
delegate :security_orchestration_policy_configuration, to: :project
def success
ServiceResponse.success
end
def error(message)
ServiceResponse.error(message: message)
end
end
end
end

View file

@ -62,5 +62,9 @@
project.project_setting.save!
end
end
trait :with_security_orchestration_policy_configuration do
association :security_orchestration_policy_configuration, factory: :security_orchestration_policy_configuration
end
end
end

View file

@ -0,0 +1,68 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::SecurityPolicy::UnassignSecurityPolicyProject do
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
describe '#resolve' do
let_it_be(:owner) { create(:user) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :with_security_orchestration_policy_configuration, namespace: owner.namespace) }
let_it_be(:project_without_policy_project) { create(:project, namespace: owner.namespace) }
let(:project_full_path) { project.full_path }
let(:current_user) { owner }
subject { mutation.resolve(project_path: project_full_path) }
context 'when permission is set for user' do
before do
stub_licensed_features(security_orchestration_policies: true)
end
context 'when user is an owner of the project' do
context 'when policy project is assigned to a project' do
it 'assigns the security policy project' do
result = subject
expect(result[:errors]).to be_empty
expect(project.reload.security_orchestration_policy_configuration).to be_blank
end
end
context 'when policy project is not assigned to a project' do
let(:project_full_path) { project_without_policy_project.full_path }
it 'respond with an error' do
result = subject
expect(result[:errors]).to match_array(["Policy project doesn't exist"])
end
end
end
context 'when user is not an owner' do
let(:current_user) { user }
before do
project.add_maintainer(user)
end
it 'raises exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
context 'when feature is not licensed' do
before do
stub_licensed_features(security_orchestration_policies: false)
end
it 'raises exception' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Security::Orchestration::UnassignService do
let_it_be(:project, reload: true) { create(:project, :with_security_orchestration_policy_configuration) }
let_it_be(:project_without_policy_project, reload: true) { create(:project) }
let(:service) { described_class.new(project, nil) }
describe '#execute' do
subject(:result) { service.execute }
context 'when policy project is assigned to a project' do
let(:service) { described_class.new(project, nil) }
it 'unassigns policy project from the project', :aggregate_failures do
expect(result).to be_success
expect(project.security_orchestration_policy_configuration).to be_destroyed
end
end
context 'when policy project is not assigned to a project' do
let(:service) { described_class.new(project_without_policy_project, nil) }
it 'respond with an error', :aggregate_failures do
expect(result).not_to be_success
expect(result.message).to eq("Policy project doesn't exist")
end
end
end
end