Compliance framework controls cannot detect scans executed by scan execution policies

Summary

The compliance framework control "Dependency scanning running" (scanner_dep_scanning_running) incorrectly reports as FAILED when dependency scanning is executed via scan execution policies, despite the scans running successfully and producing artifacts. The control only passes when dependency scanning is explicitly included in the project's .gitlab-ci.yml file.

Steps to Reproduce

  1. Create a project on GitLab.com
  2. Configure a scan execution policy at the group level:
    • Navigate to SecurePolicies
    • Create a new scan execution policy
    • Configure it to run dependency scanning on the default branch
  3. Create a compliance framework with dependency scanning control:
    • Navigate to group → SecureCompliance centerFrameworks
    • Create a new framework (e.g., "Dependency-Scan-Test")
    • Add a requirement with the control: "Dependency scanning running" (scanner_dep_scanning_running)
  4. Apply the compliance framework to the project:
    • Project → SettingsGeneralCompliance framework
    • Select the framework created in step 3
  5. Trigger a pipeline on the default branch (e.g., push a commit)
  6. Verify the dependency scanning job runs successfully:
    • Pipeline shows green/passed status
    • Dependency scanning job completes successfully
    • Job produces artifacts (e.g., gl-sbom-*.cdx.json)
  7. Check compliance status:
    • Navigate to group → SecureCompliance centerStatus

Expected Behavior

  • Compliance control status: PASSED (failCount: 0, passCount: 1)
  • The compliance framework should recognize that dependency scanning ran successfully via the scan execution policy
  • The control should detect security scanning jobs regardless of how they were configured (manual .gitlab-ci.yml include vs. scan execution policy)

Actual Behavior

  • Compliance control status: FAILED (failCount: 1, passCount: 0)
  • Error message displayed: "Ensures dependency scanning is configured and running in the project's default branch pipeline."
  • The compliance framework does not recognize dependency scanning jobs created by scan execution policies
  • Workaround: Manually including Security/Dependency-Scanning.gitlab-ci.yml in .gitlab-ci.yml makes the control pass, even though it creates the exact same job with the same artifacts

Root Cause Analysis (using gitlab duo agent)

After investigating the GitLab codebase, the issue is caused by pipeline source filtering:

Code Location: ee/lib/compliance_management/compliance_requirements/project_fields.rb (lines 43-49)

def security_scanner_running?(scanner, project, _context = {})
  pipeline = project.latest_successful_pipeline_for_default_branch
  return false if pipeline.nil?
  return false unless SECURITY_SCANNERS.include?(scanner)
  
  pipeline.job_artifacts.send(scanner).any?
end

The Problem:

  1. project.latest_successful_pipeline_for_default_branch calls ci_pipelines.latest_successful_for_ref(default_branch)

  2. The ci_pipelines association is defined in app/models/project.rb (line 452):

     has_many :ci_pipelines, -> { ci_sources }, class_name: 'Ci::Pipeline'
  3. The ci_sources scope excludes security_orchestration_policy pipelines (defined in app/models/concerns/enums/ci/pipeline.rb, lines 99-101):

     def self.ci_sources 
       sources.except(*dangling_sources.keys)  # Excludes security_orchestration_policy 
     end
  4. Scan execution policies create pipelines with source: security_orchestration_policy, which is classified as a "dangling source" (lines 73-85)

  5. Result: Pipelines created by scan execution policies are filtered out and invisible to compliance framework checks

When manually including the template:

  • Pipeline source: push, web, or api (all in ci_sources)
  • Compliance framework can see these pipelines

When using scan execution policy:

  • Pipeline source: security_orchestration_policy (in dangling_sources)
  • Compliance framework cannot see these pipelines

Environment

  • GitLab version: 18.7.0
  • GitLab instance: GitLab.com (SaaS)
  • Subscription: Ultimate
  • Affected feature: Compliance Framework Controls
  • Scanner type: Dependency Scanning (SBOM-based)

Evidence

Pipeline created by scan execution policy:

  • Source: security_orchestration_policy
  • Job: gemnasium-python-dependency-scanning-0 (SUCCESS)
  • Artifact: gl-sbom-pypi-uv.cdx.json
  • Compliance status: FAILED

Pipeline created by manual .gitlab-ci.yml include:

  • Source: push
  • Job: gemnasium-python-dependency-scanning-0 (SUCCESS)
  • Artifact: gl-sbom-pypi-uv.cdx.json (identical)
  • Compliance status: PASSED

Impact

  • Organizations using scan execution policies for compliance cannot rely on compliance framework reporting
  • False negatives in compliance dashboards and audit reports
  • Confusion for security/compliance teams who see successful scans but failed compliance checks
  • Workaround requires duplicating security configuration (both scan execution policy AND manual .gitlab-ci.yml include)
  • Defeats the purpose of scan execution policies, which are designed to centrally enforce security scanning without requiring project-level configuration

Proposed Fix

Update the compliance framework to include security_orchestration_policy pipelines when checking for security scanners:

Option 1: Modify latest_successful_pipeline_for_default_branch to use all_pipelines or a new scope that includes security orchestration policy pipelines:

def latest_successful_pipeline_for_default_branch
  all_pipelines.ci_and_security_orchestration_sources
    .latest_successful_for_ref(default_branch)
end

Option 2: Create a dedicated method for compliance checks:

def latest_successful_pipeline_for_compliance_check(ref)
  all_pipelines
    .where(source: Enums::Ci::Pipeline.ci_and_security_orchestration_sources.values)
    .latest_successful_for_ref(ref)
end

Option 3: Update the security_scanner_running? method to explicitly check both ci_pipelines and security_orchestration_policy pipelines.

Additional Notes

The GitLab documentation states that compliance controls check for scans "running in the project's default branch pipeline" but does not specify that pipelines created by scan execution policies are excluded. This behavior is undocumented and contradicts the expected integration between security policies and compliance frameworks.

Scan execution policies are a recommended best practice for enforcing security scanning at scale, and compliance frameworks should natively support detecting scans executed through this mechanism.

Edited by 🤖 GitLab Bot 🤖