From 259f36441d82b442fed21e885ea18aea5c5b69ad Mon Sep 17 00:00:00 2001
From: Hitesh Raghuvanshi <hraghuvanshi@gitlab.com>
Date: Sun, 27 Oct 2024 22:32:48 +0530
Subject: [PATCH 1/2] Adding adherence check for sast scanner run

Changelog: added
EE: true
---
 config/sidekiq_queues.yml                     |   4 +
 doc/api/graphql/reference/index.md            |   1 +
 .../compliance_standards/adherence.rb         |   3 +-
 .../standards/base_service.rb                 |   3 +-
 .../standards/gitlab/sast_service.rb          |  21 +++
 .../ee/ci/job_artifacts/create_service.rb     |  10 +-
 ee/app/workers/all_queues.yml                 |  18 +++
 .../standards/gitlab/sast_group_worker.rb     |  18 +++
 .../standards/gitlab/sast_worker.rb           |  19 +++
 .../standards/refresh_worker.rb               |   1 +
 .../enable_adherence_check_for_scanners.yml   |   9 ++
 .../adherence_check_name_enum_spec.rb         |   2 +-
 .../refresh_adherence_checks_spec.rb          |   8 +-
 .../standards/gitlab/sast_service_spec.rb     | 125 ++++++++++++++++++
 .../standards/refresh_service_spec.rb         |   2 +-
 .../ci/job_artifacts/create_service_spec.rb   |  51 ++++++-
 .../gitlab/sast_group_worker_spec.rb          |  45 +++++++
 .../standards/gitlab/sast_worker_spec.rb      |  41 ++++++
 18 files changed, 370 insertions(+), 11 deletions(-)
 create mode 100644 ee/app/services/compliance_management/standards/gitlab/sast_service.rb
 create mode 100644 ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
 create mode 100644 ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
 create mode 100644 ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
 create mode 100644 ee/spec/services/compliance_management/standards/gitlab/sast_service_spec.rb
 create mode 100644 ee/spec/workers/compliance_management/standards/gitlab/sast_group_worker_spec.rb
 create mode 100644 ee/spec/workers/compliance_management/standards/gitlab/sast_worker_spec.rb

diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 2b8efdda38b9fd..c6ca62028358db 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -241,6 +241,10 @@
   - 1
 - - compliance_management_standards_gitlab_prevent_approval_by_committer_group
   - 1
+- - compliance_management_standards_gitlab_sast
+  - 1
+- - compliance_management_standards_gitlab_sast_group
+  - 1
 - - compliance_management_standards_group_base
   - 1
 - - compliance_management_standards_refresh
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 1914c39ce20b84..ebaa6573bf35b2 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -37395,6 +37395,7 @@ Name of the check for the compliance standard.
 | <a id="compliancestandardsadherencechecknameat_least_two_approvals"></a>`AT_LEAST_TWO_APPROVALS` | At least two approvals. |
 | <a id="compliancestandardsadherencechecknameprevent_approval_by_merge_request_author"></a>`PREVENT_APPROVAL_BY_MERGE_REQUEST_AUTHOR` | Prevent approval by merge request author. |
 | <a id="compliancestandardsadherencechecknameprevent_approval_by_merge_request_committers"></a>`PREVENT_APPROVAL_BY_MERGE_REQUEST_COMMITTERS` | Prevent approval by merge request committers. |
+| <a id="compliancestandardsadherencechecknamesast"></a>`SAST` | Sast. |
 
 ### `ComplianceStandardsAdherenceStandard`
 
diff --git a/ee/app/models/concerns/enums/projects/compliance_standards/adherence.rb b/ee/app/models/concerns/enums/projects/compliance_standards/adherence.rb
index b3146299181a76..1cb7a9c133c00d 100644
--- a/ee/app/models/concerns/enums/projects/compliance_standards/adherence.rb
+++ b/ee/app/models/concerns/enums/projects/compliance_standards/adherence.rb
@@ -13,7 +13,8 @@ def self.check_name
             ComplianceManagement::Standards::Gitlab::PreventApprovalByAuthorService::CHECK_NAME => 0,
             ComplianceManagement::Standards::Gitlab::PreventApprovalByCommitterService::CHECK_NAME => 1,
             ComplianceManagement::Standards::Gitlab::AtLeastTwoApprovalsService::CHECK_NAME => 2,
-            ComplianceManagement::Standards::Soc2::AtLeastOneNonAuthorApprovalService::CHECK_NAME => 3
+            ComplianceManagement::Standards::Soc2::AtLeastOneNonAuthorApprovalService::CHECK_NAME => 3,
+            ComplianceManagement::Standards::Gitlab::SastService::CHECK_NAME => 4
           }
         end
 
diff --git a/ee/app/services/compliance_management/standards/base_service.rb b/ee/app/services/compliance_management/standards/base_service.rb
index 3855d690cb1f85..ade221ddc9cc53 100644
--- a/ee/app/services/compliance_management/standards/base_service.rb
+++ b/ee/app/services/compliance_management/standards/base_service.rb
@@ -46,7 +46,8 @@ def attributes
           namespace_id: project.namespace_id,
           status: status,
           check_name: self.class::CHECK_NAME,
-          standard: self.class::STANDARD
+          standard: self.class::STANDARD,
+          updated_at: Time.current
         }
       end
 
diff --git a/ee/app/services/compliance_management/standards/gitlab/sast_service.rb b/ee/app/services/compliance_management/standards/gitlab/sast_service.rb
new file mode 100644
index 00000000000000..80519b3cf49c26
--- /dev/null
+++ b/ee/app/services/compliance_management/standards/gitlab/sast_service.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module ComplianceManagement
+  module Standards
+    module Gitlab
+      class SastService < BaseService
+        CHECK_NAME = :sast
+
+        private
+
+        def status
+          pipeline = project.latest_successful_pipeline_for_default_branch
+
+          return :fail if pipeline.nil?
+
+          pipeline.job_artifacts.sast.count > 0 ? :success : :fail
+        end
+      end
+    end
+  end
+end
diff --git a/ee/app/services/ee/ci/job_artifacts/create_service.rb b/ee/app/services/ee/ci/job_artifacts/create_service.rb
index 6dbfeb1ff67cf6..f07a4254d28d59 100644
--- a/ee/app/services/ee/ci/job_artifacts/create_service.rb
+++ b/ee/app/services/ee/ci/job_artifacts/create_service.rb
@@ -11,9 +11,15 @@ module CreateService
         override :track_artifact_uploader
         def track_artifact_uploader(artifact)
           super
-          return unless artifact.file_type == 'metrics'
 
-          track_usage_event(METRICS_REPORT_UPLOAD_EVENT_NAME, job.user_id)
+          if artifact.file_type == 'metrics'
+            track_usage_event(METRICS_REPORT_UPLOAD_EVENT_NAME, job.user_id)
+          elsif ::Feature.enabled?(:enable_adherence_check_for_scanners, project) &&
+              artifact.file_type == 'sast' &&
+              artifact.job.pipeline.ref == artifact.project.default_branch
+            ::ComplianceManagement::Standards::Gitlab::SastWorker
+              .perform_async({ 'project_id' => project.id, 'user_id' => job.user_id })
+          end
         end
       end
     end
diff --git a/ee/app/workers/all_queues.yml b/ee/app/workers/all_queues.yml
index 5289206e95ceae..4fdc35b96fb72b 100644
--- a/ee/app/workers/all_queues.yml
+++ b/ee/app/workers/all_queues.yml
@@ -1299,6 +1299,24 @@
   :weight: 1
   :idempotent: true
   :tags: []
+- :name: compliance_management_standards_gitlab_sast
+  :worker_name: ComplianceManagement::Standards::Gitlab::SastWorker
+  :feature_category: :compliance_management
+  :has_external_dependencies: false
+  :urgency: :low
+  :resource_boundary: :unknown
+  :weight: 1
+  :idempotent: true
+  :tags: []
+- :name: compliance_management_standards_gitlab_sast_group
+  :worker_name: ComplianceManagement::Standards::Gitlab::SastGroupWorker
+  :feature_category: :compliance_management
+  :has_external_dependencies: false
+  :urgency: :low
+  :resource_boundary: :unknown
+  :weight: 1
+  :idempotent: true
+  :tags: []
 - :name: compliance_management_standards_group_base
   :worker_name: ComplianceManagement::Standards::GroupBaseWorker
   :feature_category: :compliance_management
diff --git a/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb b/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
new file mode 100644
index 00000000000000..2f486b0fabb4b0
--- /dev/null
+++ b/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module ComplianceManagement
+  module Standards
+    module Gitlab
+      class SastGroupWorker < GroupBaseWorker
+        data_consistency :sticky
+        idempotent!
+        urgency :low
+
+        feature_category :compliance_management
+        def worker_class
+          ::ComplianceManagement::Standards::Gitlab::SastWorker
+        end
+      end
+    end
+  end
+end
diff --git a/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb b/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
new file mode 100644
index 00000000000000..50bfe72e5dc145
--- /dev/null
+++ b/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module ComplianceManagement
+  module Standards
+    module Gitlab
+      class SastWorker < BaseWorker
+        data_consistency :sticky
+        idempotent!
+        urgency :low
+
+        feature_category :compliance_management
+
+        def service_class
+          ComplianceManagement::Standards::Gitlab::SastService
+        end
+      end
+    end
+  end
+end
diff --git a/ee/app/workers/compliance_management/standards/refresh_worker.rb b/ee/app/workers/compliance_management/standards/refresh_worker.rb
index 3e4a28ba140565..26728ecf9c9c91 100644
--- a/ee/app/workers/compliance_management/standards/refresh_worker.rb
+++ b/ee/app/workers/compliance_management/standards/refresh_worker.rb
@@ -15,6 +15,7 @@ class RefreshWorker
         ::ComplianceManagement::Standards::Gitlab::PreventApprovalByAuthorGroupWorker,
         ::ComplianceManagement::Standards::Gitlab::PreventApprovalByCommitterGroupWorker,
         ::ComplianceManagement::Standards::Gitlab::AtLeastTwoApprovalsGroupWorker,
+        ::ComplianceManagement::Standards::Gitlab::SastGroupWorker,
         ::ComplianceManagement::Standards::Soc2::AtLeastOneNonAuthorApprovalGroupWorker
       ].freeze
 
diff --git a/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml b/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
new file mode 100644
index 00000000000000..f7fa3f06c1e5be
--- /dev/null
+++ b/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
@@ -0,0 +1,9 @@
+---
+name: enable_adherence_check_for_scanners
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440722
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163579/
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/492118
+milestone: '17.5'
+group: group::compliance
+type: gitlab_com_derisk
+default_enabled: false
diff --git a/ee/spec/graphql/types/projects/compliance_standards/adherence_check_name_enum_spec.rb b/ee/spec/graphql/types/projects/compliance_standards/adherence_check_name_enum_spec.rb
index ba312038ae7426..50177a34896aea 100644
--- a/ee/spec/graphql/types/projects/compliance_standards/adherence_check_name_enum_spec.rb
+++ b/ee/spec/graphql/types/projects/compliance_standards/adherence_check_name_enum_spec.rb
@@ -5,7 +5,7 @@
 RSpec.describe GitlabSchema.types['ComplianceStandardsAdherenceCheckName'], feature_category: :compliance_management do
   let(:fields) do
     %w[PREVENT_APPROVAL_BY_MERGE_REQUEST_AUTHOR PREVENT_APPROVAL_BY_MERGE_REQUEST_COMMITTERS AT_LEAST_TWO_APPROVALS
-      AT_LEAST_ONE_NON_AUTHOR_APPROVAL]
+      AT_LEAST_ONE_NON_AUTHOR_APPROVAL SAST]
   end
 
   specify { expect(described_class.graphql_name).to eq('ComplianceStandardsAdherenceCheckName') }
diff --git a/ee/spec/requests/api/graphql/mutations/compliance_management/standards/refresh_adherence_checks_spec.rb b/ee/spec/requests/api/graphql/mutations/compliance_management/standards/refresh_adherence_checks_spec.rb
index 89b65d6f3a4b17..7fed8fd53678fa 100644
--- a/ee/spec/requests/api/graphql/mutations/compliance_management/standards/refresh_adherence_checks_spec.rb
+++ b/ee/spec/requests/api/graphql/mutations/compliance_management/standards/refresh_adherence_checks_spec.rb
@@ -51,11 +51,11 @@
 
         mutate
 
-        expect(project.compliance_standards_adherence.count).to eq(4)
-        expect(sub_group_project.compliance_standards_adherence.count).to eq(4)
+        expect(project.compliance_standards_adherence.count).to eq(5)
+        expect(sub_group_project.compliance_standards_adherence.count).to eq(5)
         expect(mutation_response['adherenceChecksStatus']['startedAt']).to eq(Time.now.utc.iso8601)
-        expect(mutation_response['adherenceChecksStatus']['checksCompleted']).to eq(8)
-        expect(mutation_response['adherenceChecksStatus']['totalChecks']).to eq(8)
+        expect(mutation_response['adherenceChecksStatus']['checksCompleted']).to eq(10)
+        expect(mutation_response['adherenceChecksStatus']['totalChecks']).to eq(10)
       end
 
       context 'when refresh service errors', :freeze_time, :sidekiq_inline do
diff --git a/ee/spec/services/compliance_management/standards/gitlab/sast_service_spec.rb b/ee/spec/services/compliance_management/standards/gitlab/sast_service_spec.rb
new file mode 100644
index 00000000000000..0a519686c26a2b
--- /dev/null
+++ b/ee/spec/services/compliance_management/standards/gitlab/sast_service_spec.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ComplianceManagement::Standards::Gitlab::SastService,
+  feature_category: :compliance_management do
+  let_it_be_with_reload(:project) { create(:project, :in_group) }
+  let(:params) { {} }
+
+  let(:service) { described_class.new(project: project, params: params) }
+
+  before do
+    allow(project).to receive(:default_branch).and_return('master')
+  end
+
+  describe '#execute' do
+    context 'when group_level_compliance_dashboard feature is not available' do
+      let(:master_pipeline_success) { create(:ci_pipeline, :success, project: project, ref: "master") }
+      let(:ci_build_master_success) { create(:ci_build, pipeline: master_pipeline_success, project: project) }
+
+      before do
+        stub_licensed_features(group_level_compliance_dashboard: false)
+        create(:ci_job_artifact, :sast, project: project, job: ci_build_master_success)
+      end
+
+      it 'returns feature not available error' do
+        response = service.execute
+
+        expect(response.status).to eq(:error)
+        expect(response.message).to eq('Compliance standards adherence feature not available')
+      end
+    end
+
+    context 'when group_level_compliance_dashboard feature is available' do
+      before do
+        stub_licensed_features(group_level_compliance_dashboard: true)
+      end
+
+      shared_examples 'scanner run marked fail' do
+        it 'sets scanner run check as fail' do
+          response = service.execute
+
+          expect(response.status).to eq(:success)
+          expect(project.compliance_standards_adherence.last)
+            .to have_attributes(
+              project_id: project.id,
+              namespace_id: project.namespace_id,
+              status: 'fail',
+              check_name: 'sast',
+              standard: 'gitlab'
+            )
+        end
+      end
+
+      context 'when project has successful pipeline for default branch' do
+        let(:master_pipeline_success) { create(:ci_pipeline, :success, project: project, ref: "master") }
+        let(:ci_build_master_success) { create(:ci_build, pipeline: master_pipeline_success, project: project) }
+
+        context 'when the pipeline has sast job artifacts' do
+          before do
+            create(:ci_job_artifact, :sast, project: project, job: ci_build_master_success)
+          end
+
+          it 'sets scanner run as success' do
+            response = service.execute
+
+            expect(response.status).to eq(:success)
+            expect(project.compliance_standards_adherence.last)
+              .to have_attributes(
+                project_id: project.id,
+                namespace_id: project.namespace_id,
+                status: 'success',
+                check_name: 'sast',
+                standard: 'gitlab'
+              )
+          end
+
+          context 'when adherence check for scan already exists' do
+            let_it_be(:adherence) do
+              create(:compliance_standards_adherence, project: project, check_name: :sast, standard: :gitlab)
+            end
+
+            it 'updates the timestamp of the existing adherence check' do
+              initial_updated_at = adherence.updated_at
+
+              travel_to(2.days.from_now) do
+                response = service.execute
+
+                expect(response.status).to eq(:success)
+
+                expect((adherence.reload.updated_at.to_date - initial_updated_at.to_date).to_i).to eq(2)
+              end
+            end
+          end
+        end
+
+        context 'when the pipeline do not have sast job artifacts' do
+          it_behaves_like 'scanner run marked fail'
+        end
+      end
+
+      context 'when project does not have successful pipeline for default branch' do
+        let(:master_pipeline_failed) { create(:ci_pipeline, :failed, project: project, ref: "master") }
+        let(:ci_build_master_failed) { create(:ci_build, pipeline: master_pipeline_failed, project: project) }
+
+        before do
+          create(:ci_job_artifact, :sast, project: project, job: ci_build_master_failed)
+        end
+
+        it_behaves_like 'scanner run marked fail'
+      end
+
+      context 'when project has successful pipeline for non default branch with sast artifacts' do
+        let(:nonmaster_pipeline_success) { create(:ci_pipeline, :failed, project: project, ref: "nonmaster") }
+        let(:ci_build_nonmaster_success) { create(:ci_build, pipeline: nonmaster_pipeline_success, project: project) }
+
+        before do
+          create(:ci_job_artifact, :sast, project: project, job: ci_build_nonmaster_success)
+        end
+
+        it_behaves_like 'scanner run marked fail'
+      end
+    end
+  end
+end
diff --git a/ee/spec/services/compliance_management/standards/refresh_service_spec.rb b/ee/spec/services/compliance_management/standards/refresh_service_spec.rb
index f7665bfca1116a..d8299412e50e70 100644
--- a/ee/spec/services/compliance_management/standards/refresh_service_spec.rb
+++ b/ee/spec/services/compliance_management/standards/refresh_service_spec.rb
@@ -69,7 +69,7 @@
 
           expect(response).to be_success
           expect(response.payload).to eq({ started_at: Time.current.utc.to_s,
-                                           total_checks: "4", checks_completed: "0" })
+                                           total_checks: "5", checks_completed: "0" })
         end
       end
     end
diff --git a/ee/spec/services/ee/ci/job_artifacts/create_service_spec.rb b/ee/spec/services/ee/ci/job_artifacts/create_service_spec.rb
index 567fd764ee5627..cc886f4df9d43d 100644
--- a/ee/spec/services/ee/ci/job_artifacts/create_service_spec.rb
+++ b/ee/spec/services/ee/ci/job_artifacts/create_service_spec.rb
@@ -3,7 +3,7 @@
 require 'spec_helper'
 
 RSpec.describe Ci::JobArtifacts::CreateService, :clean_gitlab_redis_shared_state, feature_category: :job_artifacts do
-  let_it_be(:project) { create(:project) }
+  let_it_be(:project) { create(:project, :repository) }
 
   let(:service) { described_class.new(job) }
   let(:job) { create(:ci_build, project: project) }
@@ -62,5 +62,54 @@ def unique_metrics_report_uploaders
         expect(unique_metrics_report_uploaders).to eq(1)
       end
     end
+
+    context 'when artifact_type is sast' do
+      let(:params) { { 'artifact_type' => 'sast' }.with_indifferent_access }
+
+      before do
+        allow(job).to receive(:user_id).and_return(123)
+      end
+
+      context 'when enable_adherence_check_for_scanners is enabled' do
+        context 'when the artifact is for project default branch' do
+          it 'triggers the adherence worker' do
+            expect(::ComplianceManagement::Standards::Gitlab::SastWorker).to receive(:perform_async)
+              .with({ 'project_id' => project.id, 'user_id' => 123 })
+
+            subject
+          end
+        end
+
+        context 'when the artifact is not for project default branch' do
+          let(:merge_request) do
+            create(
+              :merge_request, source_project: project
+            )
+          end
+
+          let(:pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline, merge_request: merge_request) }
+
+          let(:job) { create(:ci_build, pipeline: pipeline, project: project) }
+
+          it 'does not trigger the adherence worker' do
+            expect(::ComplianceManagement::Standards::Gitlab::SastWorker).not_to receive(:perform_async)
+
+            subject
+          end
+        end
+      end
+
+      context 'when enable_adherence_check_for_scanners is disabled' do
+        before do
+          stub_feature_flags(enable_adherence_check_for_scanners: false)
+        end
+
+        it 'does not trigger adherence worker' do
+          expect(::ComplianceManagement::Standards::Gitlab::SastWorker).not_to receive(:perform_async)
+
+          subject
+        end
+      end
+    end
   end
 end
diff --git a/ee/spec/workers/compliance_management/standards/gitlab/sast_group_worker_spec.rb b/ee/spec/workers/compliance_management/standards/gitlab/sast_group_worker_spec.rb
new file mode 100644
index 00000000000000..22d9b37fb30941
--- /dev/null
+++ b/ee/spec/workers/compliance_management/standards/gitlab/sast_group_worker_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ComplianceManagement::Standards::Gitlab::SastGroupWorker,
+  feature_category: :compliance_management do
+  let_it_be(:worker) { described_class.new }
+  let_it_be(:user) { create(:user) }
+  let_it_be(:group) { create(:group) }
+  let_it_be(:project) { create(:project, namespace: group) }
+  let(:job_args) do
+    { 'group_id' => group_id, 'user_id' => user_id, 'track_progress' => true }
+  end
+
+  describe '#perform' do
+    context 'for non existent group' do
+      let(:group_id) { non_existing_record_id }
+      let(:user_id) { user.id }
+
+      it 'does not enqueue SastWorker' do
+        expect(ComplianceManagement::Standards::Gitlab::SastWorker).not_to receive(:new)
+
+        worker.perform(job_args)
+      end
+    end
+
+    context 'for non existent user' do
+      let(:user_id) { non_existing_record_id }
+      let(:group_id) { group.id }
+
+      it 'enqueues SastWorker' do
+        expect(::ComplianceManagement::Standards::Gitlab::SastWorker)
+          .to receive(:bulk_perform_async)
+                .with([[{ 'project_id' => project.id, 'user_id' => nil, 'track_progress' => true }]]).and_call_original
+
+        worker.perform(job_args)
+      end
+    end
+
+    it_behaves_like 'an idempotent worker' do
+      let(:user_id) { user.id }
+      let(:group_id) { group.id }
+    end
+  end
+end
diff --git a/ee/spec/workers/compliance_management/standards/gitlab/sast_worker_spec.rb b/ee/spec/workers/compliance_management/standards/gitlab/sast_worker_spec.rb
new file mode 100644
index 00000000000000..182a1acbf48b54
--- /dev/null
+++ b/ee/spec/workers/compliance_management/standards/gitlab/sast_worker_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ComplianceManagement::Standards::Gitlab::SastWorker, feature_category: :compliance_management do
+  let_it_be(:worker) { described_class.new }
+  let_it_be(:project) { create(:project) }
+  let_it_be(:user) { create(:user) }
+  let(:job_args) do
+    { 'project_id' => project_id, 'user_id' => user_id }
+  end
+
+  describe '#perform' do
+    context 'for non existent project' do
+      let(:project_id) { non_existing_record_id }
+      let(:user_id) { user.id }
+
+      it 'does not invoke AtLeastTwoApprovalsWorker' do
+        expect(ComplianceManagement::Standards::Gitlab::SastService).not_to receive(:new)
+
+        worker.perform(job_args)
+      end
+    end
+
+    context 'for non existent user' do
+      let(:user_id) { non_existing_record_id }
+      let(:project_id) { project.id }
+
+      it 'invokes AtLeastTwoApprovalsService' do
+        expect(ComplianceManagement::Standards::Gitlab::SastService)
+          .to receive(:new).and_call_original
+
+        worker.perform(job_args)
+      end
+    end
+
+    it_behaves_like 'an idempotent worker' do
+      let(:job_args) { { 'project_id' => project.id, 'user_id' => user.id } }
+    end
+  end
+end
-- 
GitLab


From 2c58f20d62f4384a865b6d8f8b938c266c348102 Mon Sep 17 00:00:00 2001
From: Hitesh Raghuvanshi <hraghuvanshi@gitlab.com>
Date: Mon, 28 Oct 2024 19:45:35 +0530
Subject: [PATCH 2/2] Marking consistency delayed

---
 .../compliance_management/standards/gitlab/sast_group_worker.rb | 2 +-
 .../compliance_management/standards/gitlab/sast_worker.rb       | 2 +-
 .../gitlab_com_derisk/enable_adherence_check_for_scanners.yml   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb b/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
index 2f486b0fabb4b0..c3995fcc562827 100644
--- a/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
+++ b/ee/app/workers/compliance_management/standards/gitlab/sast_group_worker.rb
@@ -4,7 +4,7 @@ module ComplianceManagement
   module Standards
     module Gitlab
       class SastGroupWorker < GroupBaseWorker
-        data_consistency :sticky
+        data_consistency :delayed
         idempotent!
         urgency :low
 
diff --git a/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb b/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
index 50bfe72e5dc145..bd05246dccf19d 100644
--- a/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
+++ b/ee/app/workers/compliance_management/standards/gitlab/sast_worker.rb
@@ -4,7 +4,7 @@ module ComplianceManagement
   module Standards
     module Gitlab
       class SastWorker < BaseWorker
-        data_consistency :sticky
+        data_consistency :delayed
         idempotent!
         urgency :low
 
diff --git a/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml b/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
index f7fa3f06c1e5be..fe91ece259c7c2 100644
--- a/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
+++ b/ee/config/feature_flags/gitlab_com_derisk/enable_adherence_check_for_scanners.yml
@@ -3,7 +3,7 @@ name: enable_adherence_check_for_scanners
 feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440722
 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163579/
 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/492118
-milestone: '17.5'
+milestone: '17.6'
 group: group::compliance
 type: gitlab_com_derisk
 default_enabled: false
-- 
GitLab