Enforce required stages in pipeline execution policies
What does this MR do and why?
Add support for enforcement of required stages in Pipeline execution policies (Epic: #475152 (closed)). Placement of required stages can be defined in the policy YAML and the stages become available in the main pipeline. Example policy CI:
name: Inject project CI
description: ''
enabled: true
pipeline_config_strategy: inject_ci
required_stages:
- name: ".pipeline-policy-test"
after: ['test', 'build', '.pipeline-policy-pre']
- name: ".pipeline-policy-build"
after: ['build']
- name: ".pipeline-policy-deploy"
after: ['deploy', '.pipeline-policy-test']
content:
include:
- project: gitlab-org/pipeline-execution-policies/compliance-project
file: override.yml
ref: main
Background
- We're seeing the need from the customers to use custom stages. For example:
- The need for custom stages is amplified by the fact that with
override_project_ci, no custom stages can be used. Any custom stages that could be used withinject_ciwhere they can be defined in project CI are ignored inoverride_project_ci. We ignore the project CI to prevent any invalid or missing configuration from running the pipelines. By ignoring the project CI, we only have option to utilize default and reserved stages foroverride_project_cistrategy. - We explored some stage injection in the scope of the PoC in !150156 (comment 1885060158) and !151061 (closed), but decided against it and only went forward with the reserved stages because it was unclear how to inject and merge stages from multiple pipelines.
Considerations
- I propose to define
required_stagesin the policy YAML instead of trying to use each pipeline'sstagesto merge them together. The concept of merging stages from multiple pipelines comes from the design of Pipeline execution policies and is not tied to the CI YAML. - Using pipeline's
stagesdoesn't provide enough information on how / where to inject a stage. There could be collisions between multiple policy pipelines, and the project pipeline. - Stage placement is defined using
afterkeyword, which defines preference for the stage placement. If a policy is enforced on a group level and there are many projects with different configurations, this gives policy makers some flexibility to say (as an example): "I want to add this stage aftertest, but iftestdoesn't exist, usebuild". - In the Pipeline execution design / PoC, we were considering
.pipeline-policy-teststage which would have implicit fallback[test, build, .pre]. Withafterkeyword, users can be explicit about the stage placement. -
afterkeyword is required to avoid any "magic" behavior - If policy makers define
afterconditions in such a way that is incompatible, the pipeline fails:-
after: [custom]butcustomstage is not present in the project pipeline - there are cyclic dependencies within the required stages:
[{ name: 'deploy', after: ['build', 'test'] }, { name: 'build', after: ['deploy'] }]
-
- If
required_stagesdefine a stage in a different place than.gitlab-ci.yml, the stage is rearranged according to the conditions inrequired_stages. For example:required_stages: [{ name: 'deploy', after: ['build', 'test'] }andstages: [build, deploy, test], the result isstages: [build, test, deploy]. - If multiple policies define the same custom stage, the most top-level group's placement configuration has priority over project-level policies.
- If a top-level group specifies a policy stage, it becomes available for all sub-group and project policies, they don't have to respecify it. It only needs to be specified it in the policy CI configuration in
stages(see the nuances below)
Caveats
- This design may not provide full stage order enforcement for
inject_cistrategy. Theoretically, the development team can decide to define a custom project stage where they deploy the application before compliance jobs run, for example withstages: [build, custom-deploy, test, deploy]. However:- Crucial checks could still be enforced in
.pipeline-policy-preto avoid unexpected surprises - If customers need this level of control, they could use
override_project_ci.
- Crucial checks could still be enforced in
Nuances
-
required_stagesdefinition in the policy YAML only allows the stage to be used in the policy CI configuration YAML. The policy CI configuration still needs to define any custom stage instages. This duplication could lead to some confusion. We could solve it by implicitly allowing anypolicy_stagein the same way as we allow the reserved stages, but this is not implemented yet in this PoC.
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Screenshots or screen recordings
Group policy config:
name: Group policy
description: ''
enabled: true
pipeline_config_strategy: inject_ci
required_stages:
- name: ".pipeline-policy-test"
content:
include:
- project: gitlab-org/pipeline-execution-policies/compliance-project
file: group.yml
ref: main
Project policy config:
name: Project policy
description: ''
enabled: true
pipeline_config_strategy: inject_ci
required_stages:
- name: ".pipeline-policy-build"
after:
- build
- name: ".pipeline-policy-deploy"
after:
- deploy
- ".pipeline-policy-test"
content:
include:
- project: gitlab-org/pipeline-execution-policies/compliance-project
file: override.yml
ref: main
| Before (custom stages ignored) | After | With invalid after conditions |
|---|---|---|
![]() |
![]() |
![]() |
How to set up and validate locally
- Enable the feature flag
Feature.enable(:custom_pipeline_execution_policy_stages) - Create a project
- Create a policy using the examples above, specifying a non-default stage in
required_stages - Create a pipeline and verify that stage is injected in the correct place
Related to #475152 (closed)
Edited by Martin Cavoj


