Checkpoint Lab — rules, workflow, Pipeline Sources, Changes, Conditions, and Dynamic Pipeline Creation
Design and prove a push/MR/tag/web pipeline matrix, predict every inclusion decision, reproduce one missing or duplicate-pipeline defect, reduce the rule set to a deterministic model, and clean up safely.
Learning objectives
- Write a complete expected inclusion matrix before running push, MR, tag, and web scenarios.
- Prove pipeline source/ref/SHA and job existence with independent evidence.
- Diagnose one intentionally missing or duplicate pipeline from creation-time evidence.
- Reduce the final workflow/job rules to the smallest deterministic set that satisfies the policy.
- Clean up synthetic refs/configuration and hand off a production-ready rule contract to Chapter 13.
workflow:rules, job rules,
rules:if, rules:changes,
rules:exists, parent-child pipelines, and dynamic child
pipelines are core GitLab CI/CD capabilities on Free, Premium, and
Ultimate across GitLab.com, Self-Managed, and Dedicated. Live
execution still requires eligible runner capacity; every mandatory
exercise therefore has a CI Lint/merged-configuration and prediction
path that does not require buying compute. Version-sensitive additions
are labeled: directory matching for rules:exists arrived
in GitLab 18.2, and rules:changes:regexp is new in GitLab
19.2 and is not required for this chapter.
1. Checkpoint mission
You are defining the first production-style pipeline creation contract for a small service. Requirements:
- Branch pushes get a lightweight branch pipeline while no MR is open.
- Once an MR is open, the same branch uses an MR pipeline instead of a duplicate branch pipeline.
- Tags may create a pipeline for release checks.
- Manual/web runs are allowed only for explicit operator diagnostics.
- Docs tests exist only when docs changed; an app marker job exists whenever a committed marker file exists.
- No deployment, registry push, secret creation, external-system mutation, or privileged runner is part of this checkpoint.
2. Preflight and assumptions
| Dimension | Assumption / safe fallback |
|---|---|
| Tier/offering | GitLab Free, Premium, or Ultimate on GitLab.com, Self-Managed, or Dedicated. |
| Role | Developer or equivalent ability to push a disposable branch/open MR; tag/manual permissions may vary by protection policy. |
| Runner | Optional for creation/inclusion proof; if no runner exists, jobs may remain pending but pipeline/job objects still demonstrate rules. |
| Validation | Pipeline Editor/CI Lint before every changed rule set. |
| Secrets | None. Print only source/ref/SHA and synthetic markers. |
| Dynamic child | Optional fixture only; not required for passing checkpoint. |
3. Minimal candidate policy
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"'
when: never
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH'
stages: [inspect, test]
context_probe:
stage: inspect
script:
- printf 'source=%s
' "$CI_PIPELINE_SOURCE"
- printf 'ref=%s
' "$CI_COMMIT_REF_NAME"
- printf 'sha=%s
' "$CI_COMMIT_SHA"
rules:
- when: on_success
docs_check:
stage: test
script: echo "docs check"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- docs/**/*
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH'
changes:
- docs/**/*
feature_present:
stage: test
script: echo "marker present"
rules:
- exists:
- app/feature.flag
4. Prediction ledger — complete before any run
| Scenario | Expected source | Pipeline? | docs_check | feature_present |
|---|---|---|---|---|
| Push to lab branch, no MR, docs changed | push | Yes | Included | Included |
| Push to same branch after MR opens | merge_request_event is the intended pipeline; duplicate push suppressed | One intended MR pipeline | Depends on MR diff | Included |
| Tag push | push + CI_COMMIT_TAG present | Yes | Absent with current docs rules | Included |
| Manual UI run on lab branch | web | Yes | Absent with current docs rules | Included |
| App-only MR update | merge_request_event | Yes | Absent | Included |
5. Build synthetic state and validate
mkdir -p app docs ch12-evidence
printf 'print("checkpoint")
' > app/main.py
printf 'enabled=true
' > app/feature.flag
printf '# Checkpoint docs
' > docs/guide.md
# Save the candidate .gitlab-ci.yml, then validate in Pipeline Editor / CI Lint.
git status --short
If CI Lint reports an error, fix syntax/schema before creating any branch. Save the validation result with the commit SHA once committed.
6. Scenario A — branch push with no MR
git switch -c ch12/checkpoint
git add -- .gitlab-ci.yml app/main.py app/feature.flag docs/guide.md
git diff --cached --check
git commit -m "ch12: checkpoint pipeline matrix"
PUSH_SHA="$(git rev-parse HEAD)"
printf 'push_sha=%s
' "$PUSH_SHA" | tee ch12-evidence/push-sha.txt
git push -u origin ch12/checkpoint
Verify one pipeline object with source push, ref
ch12/checkpoint, and SHA equal to
PUSH_SHA. Verify both docs_check and
feature_present are present. A pending job because of
no runner is acceptable; job existence is the creation-time
evidence.
7. Scenario B — open MR, then push docs change
Open a disposable MR to the default branch. Change docs and push:
printf '
Second checkpoint line
' >> docs/guide.md
git add -- docs/guide.md
git commit -m "ch12: checkpoint MR docs update"
MR_SHA="$(git rev-parse HEAD)"
printf 'mr_sha=%s
' "$MR_SHA" | tee ch12-evidence/mr-sha.txt
git push
Verify the intended pipeline source is
merge_request_event. Confirm there is no second
branch-push pipeline for MR_SHA.
docs_check should exist because the MR diff contains
docs changes.
8. Scenario C — app-only MR change
printf '# app-only checkpoint change
' >> app/main.py
git add -- app/main.py
git commit -m "ch12: checkpoint app-only update"
APP_SHA="$(git rev-parse HEAD)"
printf 'app_sha=%s
' "$APP_SHA" | tee ch12-evidence/app-sha.txt
git push
Verify an MR pipeline exists; docs_check should now be
absent while feature_present remains present. This is
the clearest proof that change detection and existence detection are
separate controls.
9. Scenarios D/E — tag and web without destructive side effects
If project policy permits a disposable tag, create one such as
ch12-checkpoint-v0 at the current commit and verify a
tag pipeline. Delete the tag after evidence capture. If tag
protection prevents this, use CI Lint/prediction only—do not weaken
protected-tag policy.
For a web run, use the GitLab UI on the disposable branch if your
role permits. Verify source=web. Do not add ad-hoc
secret variables to make the run “interesting.”
10. Inject one duplicate-pipeline defect
Temporarily replace the workflow with an overly broad policy:
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- when: always
11. Repair without adding more exceptions
Restore the explicit MR-preference workflow from Section 3. Do not
fix the symptom by adding when: never to every job.
Push a new harmless commit and verify exactly one intended pipeline
for that SHA.
printf '# repair marker
' >> app/main.py
git add -- .gitlab-ci.yml app/main.py
git diff --cached --check
git commit -m "ch12: restore deterministic workflow"
REPAIR_SHA="$(git rev-parse HEAD)"
printf 'repair_sha=%s
' "$REPAIR_SHA" | tee ch12-evidence/repair-sha.txt
git push
12. Optional dynamic child proof
If you choose the optional child fixture, generate only reviewed
fixed YAML, store it as an artifact, trigger it, and verify the
child’s source is parent_pipeline. Record the generator
job ID, artifact, trigger job, and child pipeline ID. Then remove
the fixture. Do not pass secrets or unreviewed MR text into
generated YAML.
13. Final verification checklist
- ☐ Every tested pipeline is bound to a recorded commit SHA and source.
- ☐ Branch-without-MR and MR-with-open-MR behavior matches the prediction matrix.
- ☐ Duplicate-pipeline failure evidence was preserved before repair.
-
☐
docs_checkreflects the expected change comparison;feature_presentreflects repository existence. - ☐ No runner privilege, token, protected-resource policy, registry, package, deployment, or external system was changed.
- ☐ The repaired rule set has no unnecessary final catch-all.
- ☐ Optional dynamic child configuration, if used, was generated from reviewed fixed input and removed afterward.
14. Cleanup / rollback
Close the synthetic MR. Delete the disposable tag only if you created it and are authorized. Delete the lab branch after confirming evidence SHAs/notes you need are retained locally, or delete the entire disposable project. If this was a shared project, revert only your checkpoint CI and synthetic-file commits; do not rewrite shared history.
15. Production operating model and Chapter 13 bridge
Chapter 12 adds a creation-time policy layer to the GitLab operating model: every pipeline and job now has an explainable reason to exist based on source, ref state, change comparison, repository state, and ordered rules. Duplicate suppression is centralized, dynamic configuration is treated as executable policy, and non-creation is recognized as a security/cost control.
Chapter 13 moves from whether a job exists to what data and secrets the job receives: CI/CD variables, inputs, file variables, masking, protection, and scope. The trust-boundary discipline from this chapter becomes essential there.
Knowledge check
Why must the prediction matrix be written before running the checkpoint?
It separates intended policy from post-hoc interpretation and makes each observed pipeline/job state falsifiable.
What proves duplicate pipeline creation?
Two pipeline objects for the same change/SHA with different or overlapping sources, not merely two jobs in one pipeline.
Why is feature_present still included on an app-only commit?
The marker file exists in repository state; rules:exists is independent of whether that file changed.
Why not fix duplicate pipelines by adding exclusions to every job?
The defect is whole-pipeline creation policy; workflow:rules is the correct centralized layer.
What source should an optional child pipeline report?
parent_pipeline.
What is the Chapter 13 trust question that follows this chapter?
Once a job legitimately exists, which variables/inputs/secrets should it be allowed to receive, under which protection and scope rules?
Summary
The checkpoint completed the creation-time control loop: define a source matrix → validate → predict → execute/inspect → preserve a deliberate duplicate defect → repair the workflow at the correct layer → verify job inclusion semantics → clean up. The resulting pipeline topology is now deterministic enough to safely introduce variable and secret scoping in Chapter 13.
Official references
- GitLab Docs — workflow keyword
- GitLab Docs — Specify when jobs run with rules
- GitLab Docs — CI/CD YAML syntax reference
- GitLab Docs — Predefined CI/CD variables
- GitLab Docs — Where variables can be used
- GitLab Docs — Merge request pipelines
- GitLab Docs — Downstream pipelines
- GitLab Docs — Pipeline editor
- GitLab Docs — CI Lint
- GitLab Docs — CI/CD pipelines
- GitLab Docs — Pipelines API
- GitLab Docs — Use CI/CD configuration from other files
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.