Fix enforced_scans sync with inject_policy
What does this MR do and why?
When a pipeline_execution_policy with pipeline_config_strategy: inject_policy is created with a config YAML which conditionally includes security scans based on whether certain files exist in their project, we analyze this policy configuration to determine which scans will be enforced before knowing which specific project they'll be applied to. When the policy uses variables like $CI_PROJECT_PATH (which means "the project where the pipeline runs"), GitLab can't resolve these variables correctly during analysis because there's no actual pipeline running yet. This results in the extraction of scans from the config to work incorrectly resulting in no scans persisted in enforced_scans in security_policies. This causes the MR to require approval and blocked.
Bug description
When the pipeline_execution_policy is created/updated:
-
SyncPipelineExecutionPolicyMetadataWorkeris called - It calls
AnalyzePipelineExecutionPolicyConfigServiceto analyze the config - The service calls
Gitlab::Ci::Config.new(content, project: project, user: current_user)with the config project (not the target project) - The
existsrule fails because$CI_COMMIT_SHAcannot be computed as we don't pass the branch (ref) toGitlab::Ci::Config - The exists rule raises
Rules::Rule::Clause::ParseError(seelib/gitlab/ci/build/rules/rule/clause/exists.rb:176-179) - This is caught and re-raised as
InvalidIncludeRulesError(seelib/gitlab/ci/config/external/rules.rb:31-32) - The config validation fails, causing
AnalyzePipelineExecutionPolicyConfigServiceto return an error or have an incomplete config -
enforced_scansis empty - When MR approval policy checks
unblock_rules_using_execution_policies, it can't find the required scans inenforced_scans - Result: MR approval policy incorrectly blocks the merge request
References
Screenshots or screen recordings
| Before | After |
|---|---|
|
|
How to set up and validate locally
- In local GDK, enable import from repository URL by going to Admin -> Settings -> General -> Import and export settings
- Create a group and a project called
sppwithin the group - Create an MR with
.gitlab/security-policies/policy.yml:
---
pipeline_execution_policy:
- name: Inject
description: ''
enabled: true
pipeline_config_strategy: inject_policy
content:
include:
- project: <GROUP_PATH>/spp
file: policy-ci.yml
approval_policy:
- name: Dependency scanning and SAST approvals
description: ''
enabled: true
policy_scope:
projects:
excluding: []
rules:
- type: scan_finding
scanners:
- dependency_scanning
- sast
vulnerabilities_allowed: 0
severity_levels: []
vulnerability_states: []
branch_type: protected
actions:
- type: require_approval
approvals_required: 1
group_approvers_ids:
- 24
- type: send_bot_message
enabled: true
approval_settings:
block_branch_modification: false
block_group_branch_modification: false
prevent_pushing_and_force_pushing: false
prevent_approval_by_author: false
prevent_approval_by_commit_author: false
remove_approvals_with_new_commit: false
require_password_to_approve: false
fallback_behavior:
fail: closed
policy_tuning:
unblock_rules_using_execution_policies: true
- Create
policy-ci.yml:
include:
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
- local: 'Container-Scanning.latest.gitlab-ci.yml'
rules:
- exists:
paths:
- Dockerfile
- "**/Dockerfile"
- "**/*/Dockerfile"
- "container/*.dockerfile"
- '$CS_DOCKERFILE_PATH'
project: '$CI_PROJECT_PATH'
ref: '$CI_COMMIT_SHA'
- template: Jobs/Secret-Detection.latest.gitlab-ci.yml
- template: Jobs/SAST.gitlab-ci.yml
stages:
- .pipeline-policy-pre
- test
- .post
policy_enforced:
stage: .pipeline-policy-pre
script:
- echo "Hello from inject"
variables:
SECURE_ENABLE_LOCAL_CONFIGURATION: true
SECRET_DETECTION_EXCLUDED_PATHS: "node_modules/,bower_components/,vendor/,deps/,venv/,env/,.env/,.venv/,.mypy_cache/,__pycache__/,Pods/,Carthage/,elm-stuff/,.next/,.nuxt/,.angular/,.svelte-kit/,.gradle/,.terraform/,.dart_tool/"
FF_TIMESTAMPS: true # enables timestamp in pipeline logs. https://docs.gitlab.com/ee/ci/jobs/job_logs.html#job-log-timestamps
DOCKER_DIND_VERSION: "24.0.5"
# https://docs.gitlab.com/ee/ci/yaml/workflow.html
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# prevent multiple pipeline runs for the same branch when MR is open
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
# this is to prevent multiple pipeline runs for the same branch when Merge Request is open
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE != "web"
when: never
# always run pipeline for the default branch
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: always
# this runs pipeline after push to branch
- if: $CI_COMMIT_BRANCH && $CI_PIPELINE_SOURCE == "push"
when: always
- Link the project (
spp) as the security policy project by going to Secure -> Policies -> Edit policy project - Import a project (example) within the group
- Create an MR by updating the README.md and verify that the pipeline is created
- Verify that the approval is not required
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #582104 (closed)

