MR pipeline created with 0 jobs and fails despite workflow:rules blocking merge_request_event, when CI/CD Components are included
Summary
When a project uses include: component: and has workflow:rules with when: never for merge_request_event, GitLab still creates a merge_request_event pipeline when an MR is opened via the REST API by a project access token bot user. The pipeline has 0 matching jobs (all component jobs exclude merge_request_event), instantly fails, and becomes the MR's head_pipeline — showing a red
Environment
- GitLab.com SaaS (latest)
- CI/CD Components (
include: component:)
Steps to Reproduce
-
Project A (upstream) has an import pipeline that:
- Pushes a branch to Project B using a project access token (
git push -o ci.skip) - Creates an MR on Project B via REST API (
POST /projects/:id/merge_requests)
- Pushes a branch to Project B using a project access token (
-
Project B
.gitlab-ci.yml:workflow: rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: never - if: $CI_PIPELINE_SOURCE == "pipeline" - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: never include: - component: $CI_SERVER_FQDN/my-group/my-component/review@main inputs: { sid: "BHF" } stages: [atc, report, publish] -
The included component defines jobs with rules that do NOT match
merge_request_event:.acr-rules-review: rules: - if: '$CI_PIPELINE_SOURCE == "pipeline" && $CI_COMMIT_REF_NAME =~ /^tr\//' - if: '$CI_PIPELINE_SOURCE =~ /^(push|api|web|trigger)$/ && $CI_COMMIT_REF_NAME =~ /^tr\//' -
Project A's pipeline creates the MR on Project B via API using the project access token (
project_{ID}_bot_{hash}user).
Expected Behavior
workflow:ruleswithwhen: neverformerge_request_eventshould prevent pipeline creation entirelygit push -o ci.skipshould also prevent pipeline creation on push- No
merge_request_eventpipeline should appear on the MR
Actual Behavior
- A
merge_request_eventpipeline IS created despiteworkflow:rulesblocking it - The pipeline has 0 matching jobs (all component jobs exclude
merge_request_event) - It instantly fails with status
failedand becomes the MR'shead_pipeline - The pipeline is created by the project access token bot user
- Neither
ci.skippush option norworkflow:rulesprevents this
Attempted Workarounds (all failed)
| Approach | Result |
|---|---|
workflow:rules with when: never for merge_request_event |
Pipeline still created |
git push -o ci.skip |
Only prevents push pipeline, not MR pipeline |
Remove merge_request_event from all job rules |
Pipeline created with 0 jobs, fails |
| API-based MR creation (no push options) | MR pipeline still created |
| Cancel pipeline via API | No-op (already failed) |
| Delete pipeline via API | 403 (requires Owner role) |
Create pipeline via POST /pipeline API |
400: insufficient permission on tr/* branches |
Working Workaround
Add a placeholder job that matches merge_request_event so the MR pipeline passes (green) instead of failing:
acr-mr-info:
stage: .pre
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- echo "Placeholder - actual review runs via downstream pipeline"Impact
- The failed MR pipeline becomes
head_pipeline, showing a red X on the MR even when the actual review pipeline succeeds - Cannot delete it (requires Owner role; project access tokens max out at Maintainer)
- Users see confusing dual pipelines on MRs
Root Cause Hypothesis
There appear to be two possible root causes (or a combination):
-
MR pipeline creation happens before CI config is evaluated: When a project access token bot user creates an MR via the REST API, GitLab may trigger the
merge_request_eventpipeline at the Git/MR level beforeworkflow:rulesare parsed and applied. -
include: component:interaction: When a.gitlab-ci.ymlcontainsinclude: component:, GitLab may evaluate the component's job rules before applyingworkflow:rules, or the component inclusion causes a different pipeline creation code path that bypassesworkflow:rulesenforcement.
The fact that the pipeline has 0 jobs (all job rules correctly exclude merge_request_event) but the pipeline itself is still created suggests workflow:rules is not being evaluated at the pipeline creation stage — only at the job scheduling stage.