Skip to content

Generate approval notification when no scanners are present in the pipeline

Why are we doing this work

Currently we generate an approval notification in the form of a bot comment when there are scanners in the pipeline and the results are violating defined policies.

We would like to create a notification also when there are no scanners in the pipeline, but policies enforce approvals.

In addition to that, we should also cover a case when there is no pipeline configuration at all, as policies can still block MRs in these cases.

Example:

CleanShot_2023-07-11_at_15.57.20_2x

Implementation Plan

diff --git a/ee/app/services/security/scan_result_policies/update_approvals_service.rb b/ee/app/services/security/scan_result_policies/update_approvals_service.rb
index 7bbfe342940c..da3e04a63469 100644
--- a/ee/app/services/security/scan_result_policies/update_approvals_service.rb
+++ b/ee/app/services/security/scan_result_policies/update_approvals_service.rb
@@ -13,13 +13,22 @@ def initialize(merge_request:, pipeline:)
       end

       def execute
+        return if pipeline.pending?
+
         approval_rules = merge_request.approval_rules.scan_finding
         return if approval_rules.empty?

-        violated_rules, unviolated_rules = partition_rules(approval_rules)
+        actual_scans = pipeline.security_scans.pluck(:scan_type) # rubocop: disable CodeReuse/ActiveRecord
+
+        unenforceable_rules, enforceable_rules = approval_rules.partition do |approval_rule|
+          (approval_rule.scanners - actual_scans).any?
+        end
+
+        violated_rules, unviolated_rules = partition_rules(enforceable_rules)

         ApprovalMergeRequestRule.remove_required_approved(unviolated_rules) if unviolated_rules.any?
-        generate_policy_bot_comment(violated_rules.any?)
+
+        generate_policy_bot_comment(unenforceable_rules.any? || violated_rules.any?)
       end

       private
diff --git a/ee/app/workers/security/scan_result_policies/sync_findings_to_approval_rules_worker.rb b/ee/app/workers/security/scan_result_policies/sync_findings_to_approval_rules_worker.rb
index aacb1a630b6f..21694cb65a4b 100644
--- a/ee/app/workers/security/scan_result_policies/sync_findings_to_approval_rules_worker.rb
+++ b/ee/app/workers/security/scan_result_policies/sync_findings_to_approval_rules_worker.rb
@@ -15,7 +15,7 @@ class SyncFindingsToApprovalRulesWorker
       def perform(pipeline_id)
         pipeline = ::Ci::Pipeline.find_by_id(pipeline_id)

-        return unless pipeline && pipeline.can_store_security_reports?
+        return unless pipeline&.project&.can_store_security_reports?

         Security::ScanResultPolicies::SyncFindingsToApprovalRulesService.new(pipeline).execute
       end

Verification steps

  1. Enable feature flag security_policies_unenforceable_rules_notification
  2. Go to Secure -> Policies and create a new scan result policy. Sample YAML:
    type: scan_result_policy
    name: Sec & Lic
    description: ''
    enabled: true
    rules:
      - type: scan_finding
        scanners: []
        vulnerabilities_allowed: 0
        severity_levels: []
        vulnerability_states: []
        branch_type: protected
      - type: license_finding
        match_on_inclusion: true
        license_types:
          - BSD 3-Clause "New" or "Revised" License
        license_states:
          - newly_detected
        branch_type: protected
    actions:
      - type: require_approval
        approvals_required: 1
        role_approvers:
        - developer
    approval_settings:
      block_unprotecting_branches: true
      prevent_pushing_and_force_pushing: true

With no pipelines

  1. In a project where there is no .gitlab-ci.yml, create any MR (e.g. update README)
  2. Observe required approvals for Sec & Lic
  3. Observe a policy bot comment being created
  4. Change the target branch to a non-protected one (you can go to Code -> Branches and create a new branch from main)
  5. The policy bot comment should be updated to say the violations have been resolved
  6. Create a new MR targeting a non-protected branch from the beginning -> there should be no policy bot comment. Change the target branch to main and the bot comment should appear.

With missing scanners

  1. Create a .gitlab-ci.yml file and don't include dependency scanning. Sample YAML:
    include:
      - template: Jobs/Secret-Detection.gitlab-ci.yml
    #  - template: Jobs/Dependency-Scanning.gitlab-ci.yml
    
    build-job:
      script:
        - echo "Compiling the code..."
        - echo "Compile complete."
  2. Create MR and verify that bot comment is created and approvals should be still required after pipeline finishes

With all scanners present

  1. Update .gitlab-ci.yml again and include also the commented-out dependency scanning template. Add empty requirements.txt file in the repo.
  2. Create another MR. There should be no policy bot comment and no required approvals after pipeline finishes.

Relevant links

Edited by Martin Čavoj