From f4c7cc7de7a87be216a97872f1b3647abdbdfac2 Mon Sep 17 00:00:00 2001
From: "Alan (Maciej) Paruszewski" <mparuszewski@gitlab.com>
Date: Wed, 8 Dec 2021 00:15:30 +0100
Subject: [PATCH 1/2] Add request specs for security policies mutations

---
 .../assign_security_policy_project_spec.rb    | 75 ++++++++++++++++
 .../create_security_policy_project_spec.rb    | 76 +++++++++++++++++
 .../unassign_security_policy_project_spec.rb  | 85 +++++++++++++++++++
 3 files changed, 236 insertions(+)
 create mode 100644 ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
 create mode 100644 ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
 create mode 100644 ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb

diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
new file mode 100644
index 00000000000000..6361c3f2760644
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Assigns scan execution policy project to a project' do
+  include GraphqlHelpers
+
+  let_it_be_with_refind(:owner) { create(:user) }
+  let_it_be_with_refind(:user) { create(:user) }
+  let_it_be_with_refind(:project) { create(:project, namespace: owner.namespace) }
+  let_it_be_with_refind(:policy_project) { create(:project) }
+  let_it_be_with_refind(:policy_project_id) { GitlabSchema.id_from_object(policy_project) }
+
+  let(:current_user) { owner }
+
+  subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+  def mutation
+    variables = { project_path: project.full_path, security_policy_project_id: GitlabSchema.id_from_object(policy_project).to_s }
+
+    graphql_mutation(:security_policy_project_assign, variables) do
+      <<-QL.strip_heredoc
+        errors
+      QL
+    end
+  end
+
+  def mutation_response
+    graphql_mutation_response(:security_policy_project_assign)
+  end
+
+  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
+      it 'assigns the security policy project', :aggregate_failures do
+        subject
+
+        orchestration_policy_configuration = project.security_orchestration_policy_configuration
+
+        expect(graphql_data_at[:errors]).to be_nil
+        expect(orchestration_policy_configuration.security_policy_management_project).to eq(policy_project)
+      end
+    end
+
+    context 'when user is not an owner' do
+      let(:current_user) { user }
+
+      before do
+        project.add_maintainer(user)
+      end
+
+      it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+    end
+  end
+
+  context 'when policy_project_id is invalid' do
+    let_it_be_with_refind(:policy_project_id) { 'invalid' }
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+
+  context 'when feature is not licensed' do
+    before do
+      stub_licensed_features(security_orchestration_policies: false)
+    end
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+end
diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
new file mode 100644
index 00000000000000..bb2a011f6783d4
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Creates and assigns scan execution policy project to a project' do
+  include GraphqlHelpers
+
+  let_it_be_with_refind(:owner) { create(:user) }
+  let_it_be_with_refind(:user) { create(:user) }
+  let_it_be_with_refind(:project) { create(:project, namespace: owner.namespace) }
+
+  let(:current_user) { owner }
+
+  subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+  def mutation
+    variables = { project_path: project.full_path }
+
+    graphql_mutation(:security_policy_project_create, variables) do
+      <<-QL.strip_heredoc
+        errors
+      QL
+    end
+  end
+
+  def mutation_response
+    graphql_mutation_response(:security_policy_project_create)
+  end
+
+  context 'when permission is set for user' do
+    before do
+      # todo: investigate too many qeuries issue as part of Project Management Database and Query Performance
+      # epic: https://gitlab.com/groups/gitlab-org/-/epics/5804
+      stub_const('Gitlab::QueryLimiting::Transaction::THRESHOLD', 130)
+      stub_licensed_features(security_orchestration_policies: true)
+    end
+
+    context 'when user is an owner of the project' do
+      it 'creates and assigns the security policy project', :aggregate_failures do
+        expect { subject }.to change { ::Project.count }.by(1)
+
+        orchestration_policy_configuration = project.security_orchestration_policy_configuration
+
+        expect(graphql_data_at[:errors]).to be_nil
+        expect(orchestration_policy_configuration.security_policy_management_project.name).to eq("#{project.name} - Security policy project")
+      end
+    end
+
+    context 'when user is not an owner' do
+      let(:current_user) { user }
+
+      before do
+        project.add_maintainer(user)
+      end
+
+      it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+    end
+  end
+
+  context 'when policy_project_id is invalid' do
+    let_it_be_with_refind(:policy_project_id) { 'invalid' }
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+
+  context 'when feature is not licensed' do
+    before do
+      stub_licensed_features(security_orchestration_policies: false)
+    end
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+end
diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
new file mode 100644
index 00000000000000..ab12aebd5c9406
--- /dev/null
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Unassigns scan execution policy project from a project' do
+  include GraphqlHelpers
+
+  let_it_be_with_refind(:owner) { create(:user) }
+  let_it_be_with_refind(:user) { create(:user) }
+  let_it_be_with_refind(:project) { create(:project, namespace: owner.namespace) }
+  let_it_be_with_refind(:policy_project) { create(:project) }
+  let_it_be_with_refind(:policy_project_id) { GitlabSchema.id_from_object(policy_project) }
+
+  let(:current_user) { owner }
+
+  subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+  def mutation
+    variables = { project_path: project.full_path }
+
+    graphql_mutation(:security_policy_project_unassign, variables) do
+      <<-QL.strip_heredoc
+        errors
+      QL
+    end
+  end
+
+  def mutation_response
+    graphql_mutation_response(:security_policy_project_unassign)
+  end
+
+  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 there is no security policy project assigned to the project' do
+        it 'assigns the security policy project', :aggregate_failures do
+          subject
+
+          expect(graphql_data_at[:errors]).to be_nil
+        end
+      end
+
+      context 'when security policy project is assigned to the project' do
+        let!(:security_policy_management_project) { create(:project, :repository, namespace: current_user.namespace) }
+        let!(:policy_configuration) { create(:security_orchestration_policy_configuration, project: project, security_policy_management_project: security_policy_management_project) }
+
+        it 'unassigns the security policy project', :aggregate_failures do
+          expect { subject }.to change { ::Security::OrchestrationPolicyConfiguration.count }.by(-1)
+
+          expect(graphql_data_at[:errors]).to be_nil
+        end
+      end
+    end
+
+    context 'when user is not an owner' do
+      let(:current_user) { user }
+
+      before do
+        project.add_maintainer(user)
+      end
+
+      it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+    end
+  end
+
+  context 'when policy_project_id is invalid' do
+    let_it_be_with_refind(:policy_project_id) { 'invalid' }
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+
+  context 'when feature is not licensed' do
+    before do
+      stub_licensed_features(security_orchestration_policies: false)
+    end
+
+    it_behaves_like 'a mutation that returns top-level errors',
+                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+  end
+end
-- 
GitLab


From f1d62e163a971c9866e7317bbcdadb2cf580ddb3 Mon Sep 17 00:00:00 2001
From: "Alan (Maciej) Paruszewski" <mparuszewski@gitlab.com>
Date: Mon, 13 Dec 2021 22:01:04 +0100
Subject: [PATCH 2/2] Address MR comments

---
 .../create_security_policy_project.rb         |  1 -
 .../assign_security_policy_project_spec.rb    | 17 ++++++-------
 .../create_security_policy_project_spec.rb    | 24 +++++++++----------
 .../unassign_security_policy_project_spec.rb  | 21 ++++++----------
 4 files changed, 28 insertions(+), 35 deletions(-)

diff --git a/ee/app/graphql/mutations/security_policy/create_security_policy_project.rb b/ee/app/graphql/mutations/security_policy/create_security_policy_project.rb
index 22c4d5141ef3df..7fa7e4ee5ca47c 100644
--- a/ee/app/graphql/mutations/security_policy/create_security_policy_project.rb
+++ b/ee/app/graphql/mutations/security_policy/create_security_policy_project.rb
@@ -23,7 +23,6 @@ def resolve(args)
         project = authorized_find!(args[:project_path])
 
         result = create_project(project)
-
         return { project: nil, errors: [result[:message]] } if result[:status] == :error
 
         {
diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
index 6361c3f2760644..d3dbbcec5349d7 100644
--- a/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/assign_security_policy_project_spec.rb
@@ -16,7 +16,7 @@
   subject { post_graphql_mutation(mutation, current_user: current_user) }
 
   def mutation
-    variables = { project_path: project.full_path, security_policy_project_id: GitlabSchema.id_from_object(policy_project).to_s }
+    variables = { project_path: project.full_path, security_policy_project_id: policy_project_id.to_s }
 
     graphql_mutation(:security_policy_project_assign, variables) do
       <<-QL.strip_heredoc
@@ -29,7 +29,7 @@ def mutation_response
     graphql_mutation_response(:security_policy_project_assign)
   end
 
-  context 'when permission is set for user' do
+  context 'when licensed feature is available' do
     before do
       stub_licensed_features(security_orchestration_policies: true)
     end
@@ -40,7 +40,8 @@ def mutation_response
 
         orchestration_policy_configuration = project.security_orchestration_policy_configuration
 
-        expect(graphql_data_at[:errors]).to be_nil
+        expect(response).to have_gitlab_http_status(:success)
+        expect(mutation_response['errors']).to be_empty
         expect(orchestration_policy_configuration.security_policy_management_project).to eq(policy_project)
       end
     end
@@ -55,13 +56,13 @@ def mutation_response
       it_behaves_like 'a mutation that returns top-level errors',
                 errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
     end
-  end
 
-  context 'when policy_project_id is invalid' do
-    let_it_be_with_refind(:policy_project_id) { 'invalid' }
+    context 'when policy_project_id is invalid' do
+      let_it_be_with_refind(:policy_project_id) { "gid://gitlab/Project/#{non_existing_record_id}" }
 
-    it_behaves_like 'a mutation that returns top-level errors',
-                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+      it_behaves_like 'a mutation that returns top-level errors',
+                  errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+    end
   end
 
   context 'when feature is not licensed' do
diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
index bb2a011f6783d4..f5308d26b01e22 100644
--- a/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/create_security_policy_project_spec.rb
@@ -18,6 +18,10 @@ def mutation
 
     graphql_mutation(:security_policy_project_create, variables) do
       <<-QL.strip_heredoc
+        project {
+          id
+          name
+        }
         errors
       QL
     end
@@ -27,10 +31,11 @@ def mutation_response
     graphql_mutation_response(:security_policy_project_create)
   end
 
-  context 'when permission is set for user' do
+  context 'when licensed feature is available' do
     before do
-      # todo: investigate too many qeuries issue as part of Project Management Database and Query Performance
-      # epic: https://gitlab.com/groups/gitlab-org/-/epics/5804
+      # TODO: investigate too many qeuries issue as part of Project Management Database and Query Performance
+      # Epic: https://gitlab.com/groups/gitlab-org/-/epics/5804
+      # Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/348344
       stub_const('Gitlab::QueryLimiting::Transaction::THRESHOLD', 130)
       stub_licensed_features(security_orchestration_policies: true)
     end
@@ -41,8 +46,10 @@ def mutation_response
 
         orchestration_policy_configuration = project.security_orchestration_policy_configuration
 
-        expect(graphql_data_at[:errors]).to be_nil
-        expect(orchestration_policy_configuration.security_policy_management_project.name).to eq("#{project.name} - Security policy project")
+        expect(response).to have_gitlab_http_status(:success)
+        expect(mutation_response['errors']).to be_empty
+        expect(mutation_response.dig('project', 'id')).to eq(orchestration_policy_configuration.security_policy_management_project.to_gid.to_s)
+        expect(mutation_response.dig('project', 'name')).to eq("#{project.name} - Security policy project")
       end
     end
 
@@ -58,13 +65,6 @@ def mutation_response
     end
   end
 
-  context 'when policy_project_id is invalid' do
-    let_it_be_with_refind(:policy_project_id) { 'invalid' }
-
-    it_behaves_like 'a mutation that returns top-level errors',
-                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
-  end
-
   context 'when feature is not licensed' do
     before do
       stub_licensed_features(security_orchestration_policies: false)
diff --git a/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb b/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
index ab12aebd5c9406..30bb548e88f4ff 100644
--- a/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
+++ b/ee/spec/requests/api/graphql/mutations/security_policy/unassign_security_policy_project_spec.rb
@@ -8,8 +8,6 @@
   let_it_be_with_refind(:owner) { create(:user) }
   let_it_be_with_refind(:user) { create(:user) }
   let_it_be_with_refind(:project) { create(:project, namespace: owner.namespace) }
-  let_it_be_with_refind(:policy_project) { create(:project) }
-  let_it_be_with_refind(:policy_project_id) { GitlabSchema.id_from_object(policy_project) }
 
   let(:current_user) { owner }
 
@@ -29,17 +27,18 @@ def mutation_response
     graphql_mutation_response(:security_policy_project_unassign)
   end
 
-  context 'when permission is set for user' do
+  context 'when licensed feature is available' do
     before do
       stub_licensed_features(security_orchestration_policies: true)
     end
 
     context 'when user is an owner of the project' do
       context 'when there is no security policy project assigned to the project' do
-        it 'assigns the security policy project', :aggregate_failures do
-          subject
+        it 'unassigns the security policy project', :aggregate_failures do
+          expect { subject }.not_to change { ::Security::OrchestrationPolicyConfiguration.count }
 
-          expect(graphql_data_at[:errors]).to be_nil
+          expect(response).to have_gitlab_http_status(:success)
+          expect(mutation_response['errors']).to eq(["Policy project doesn't exist"])
         end
       end
 
@@ -50,7 +49,8 @@ def mutation_response
         it 'unassigns the security policy project', :aggregate_failures do
           expect { subject }.to change { ::Security::OrchestrationPolicyConfiguration.count }.by(-1)
 
-          expect(graphql_data_at[:errors]).to be_nil
+          expect(response).to have_gitlab_http_status(:success)
+          expect(mutation_response['errors']).to be_empty
         end
       end
     end
@@ -67,13 +67,6 @@ def mutation_response
     end
   end
 
-  context 'when policy_project_id is invalid' do
-    let_it_be_with_refind(:policy_project_id) { 'invalid' }
-
-    it_behaves_like 'a mutation that returns top-level errors',
-                errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
-  end
-
   context 'when feature is not licensed' do
     before do
       stub_licensed_features(security_orchestration_policies: false)
-- 
GitLab