Checkpoint Lab — workflow:rules, Job rules, if Expressions, changes, exists, Pipeline Sources, and Conditional Execution
The checkpoint asks you to design one compact rule set for branch, merge-request, and scheduled pipelines, prove which pipelines and jobs exist in each context, deliberately introduce a duplicate-pipeline bug, preserve the evidence, and repair the rule boundary without weakening unrelated execution paths.
Learning objectives
- Design branch, merge-request, and scheduled behavior before writing YAML and record expected pipeline/job state.
- Trigger or faithfully simulate each context and verify source/ref/SHA, workflow decision, and job presence independently.
- Introduce and diagnose a deliberate duplicate-pipeline bug while preserving both pipeline IDs and job graphs.
- Repair the bug with an explicit workflow boundary and verify that intended manual/API-like or triggered contexts are not accidentally blocked.
- Produce a compact evidence packet and bridge conditional execution into Chapter 09 DAG/stage/needs design.
1. Checkpoint scenario and success criteria
Your disposable repository has three intended pipeline classes:
- Feature branch without an open MR: lightweight branch verification.
- Merge request: MR verification with service-specific diff filtering.
- Nightly schedule: dependency audit regardless of ordinary source-code diff.
You must first implement a non-duplicating policy, then intentionally break the workflow to create branch+MR duplicates for one SHA, preserve the evidence, repair the defect, and verify that schedule behavior still works. No production deployments, real secrets, runner registration, cloud resources, packages, or policy/admin settings are involved.
2. Assumptions and preflight
- GitLab primary docs checked 2026-09-11; core rules used here are Free-compatible.
- Disposable branch:
glci/ch08-checkpoint. -
Synthetic paths:
services/api/app.txt,services/web/app.txt,deps.lock. - A project schedule is optional if your role/project permits it. Otherwise simulate schedule rule evaluation with CI Lint/prediction worksheet and mark runtime as not observed.
- Runner is optional for rule-state completion; if available, use a normal non-privileged runner and record Runner version/executor from safe job metadata.
- Do not supply real pipeline variables or API/trigger tokens.
3. Write predictions before the YAML
| Context | Pipeline creation | Expected jobs | State prediction |
|---|---|---|---|
| Feature push, no MR | Create push pipeline | context, branch_smoke |
No MR job; no scheduled audit |
| MR update touching API | Create MR pipeline only |
context, mr_verify,
api_tests
|
Suppress redundant push pipeline |
| MR update touching only web | Create MR pipeline only | context, mr_verify |
api_tests absent |
| Schedule | Create schedule pipeline | context, dependency_audit |
No branch/MR-specific jobs |
4. Implement the verified baseline
Validate this configuration before committing it. If your default branch or project model differs, change only the relevant trusted baseline assumptions and record them.
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 == "push" && $CI_COMMIT_BRANCH'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
- when: never
stages:
- inspect
- verify
context:
stage: inspect
script:
- printf 'source=%s\n' "$CI_PIPELINE_SOURCE"
- printf 'ref=%s\n' "$CI_COMMIT_REF_NAME"
- printf 'sha=%s\n' "$CI_COMMIT_SHA"
- printf 'pipeline=%s\n' "$CI_PIPELINE_ID"
- printf 'job=%s\n' "$CI_JOB_ID"
branch_smoke:
stage: verify
script: echo "synthetic branch smoke"
rules:
- if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH'
mr_verify:
stage: verify
script: echo "synthetic MR verify"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
api_tests:
stage: verify
script: echo "synthetic API tests"
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
paths:
- services/api/**/*
dependency_audit:
stage: verify
script: echo "synthetic scheduled dependency audit"
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
5. Prove the baseline contexts
- Branch: push the lab branch before opening an MR. Record the push pipeline ID, SHA, and jobs.
-
MR: open an MR, then change
services/api/app.txt. Record exactly one pipeline for the new SHA with sourcemerge_request_event; verifyapi_testsexists. -
MR diff negative: make a web-only commit. Verify
api_testsis absent whilemr_verifyremains. -
Schedule: if permitted, create a temporary
schedule for this disposable branch, run it once, record source
scheduleanddependency_audit, then remove the schedule. If not permitted, record the simulation limitation explicitly.
6. Inject the deliberate duplicate-pipeline bug
On the disposable branch only, replace the workflow with the broken version below. Do not alter job rules yet:
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
- when: always
With the MR still open, push a harmless commit. Expect two pipeline
attempts for the same SHA: one push and one
merge_request_event. Preserve both pipeline IDs, source
values, job graphs, and timestamps. This is the first-failure
evidence; do not delete it.
7. Diagnose causally before repairing
Answer these questions in the evidence packet:
- Did GitLab compile the configuration? If not, this is not the intended rules failure.
- Which two source values created pipelines for the same SHA?
-
Which workflow rule admitted the push pipeline? The final
when: always. - Did the runner cause the duplicate? No; duplication happened before job queueing.
-
Would changing
mr_verifyjob rules eliminate the redundant pipeline record? No; it could remove a job but would not fix pipeline creation.
8. Repair the workflow boundary
Restore the baseline workflow with the open-MR push suppression. Commit the repair, push once, and record the new SHA. Verify there is one MR pipeline rather than both branch and MR pipelines. Do not use a broad project setting change or disable merge-request pipelines to hide the defect.
Then re-run or simulate the schedule context and prove the repair
did not block schedule. This is regression evidence: a
narrow duplicate fix should not silently remove another intended
pipeline class.
9. API-like/manual reasoning without credentials
The checkpoint does not require an API token. Add this design
question to your evidence note: “What would happen if source were
api or web?” Under the baseline workflow,
neither is admitted, so no pipeline should be created. If your real
product needs either source, add it explicitly in a reviewed future
change. Never replace the final when: never with a
convenience catch-all.
10. Required evidence packet
Disposable project/path and exact CI configuration commit SHAs.
For each context: pipeline ID, source, ref, immutable SHA, timestamp.
Expected/admitted/rejected pipeline classes and the matching rule rationale.
Present/absent branch_smoke, mr_verify, api_tests, dependency_audit jobs.
API-changing MR versus web-only MR and api_tests presence/absence.
Both pipeline IDs for one broken SHA, sources push + merge_request_event.
One MR pipeline for repaired SHA plus schedule regression check.
Runner ID/version/executor if jobs executed; otherwise “not observed.”
Docs date, GitLab offering/version if known, role limits, schedule simulation note if used.
MR/branch/schedule/synthetic paths removed only from the disposable lab as intended.
11. Verification checklist
- Exactly the intended pipeline classes are admitted by workflow.
- The MR-open push does not create a redundant push pipeline after repair.
-
api_testsappears only for MR contexts with API path changes. -
dependency_auditappears only in the schedule context. - No secret values, tokens, production URLs, or privileged runner assumptions appear in logs/evidence.
- The original duplicate pipelines remain preserved as failure evidence.
- Cleanup is scoped only to resources created by this checkpoint.
12. Cleanup and rollback
- Delete the temporary project schedule if you created one.
- Close the disposable merge request.
-
Delete
glci/ch08-checkpointafter preserving non-secret learning evidence. - If the checkpoint was performed in an otherwise empty throwaway project, you may delete that exact project only after verifying its identity. Otherwise keep the project and remove only lab-owned files/refs.
13. What Chapter 08 adds to the production model
You can now prove conditional execution before runtime: which event/source/ref/SHA GitLab saw, whether workflow admitted a pipeline, which job rule matched first, what diff/tree evidence was evaluated, and which jobs entered the graph. This makes rules reviewable as operational policy instead of mysterious YAML.
Chapter 09 moves from which jobs exist to
how those jobs depend on one another: stages, DAGs,
needs, dependency ordering, critical path, and
dataflow. The distinction matters because a job omitted by rules
cannot participate in a dependency graph at all.
Knowledge check
What two state predictions should be written before running the checkpoint?
At minimum, which pipeline classes should exist for each source and which jobs should be present/absent inside each pipeline; also record expected diff-sensitive behavior.
After injecting the bug, what evidence proves duplicate pipelines rather than a retried job?
Two distinct pipeline IDs for the same SHA with different source values such as push and merge_request_event.
Why not fix duplicate pipelines by changing only mr_verify job rules?
That can change job membership but cannot stop the redundant pipeline record from being created.
What regression must be checked after restoring MR duplicate suppression?
The schedule pipeline must still be admitted and dependency_audit must still appear, proving the narrow fix did not remove another intended source.
What does this checkpoint deliberately avoid?
Real API/trigger credentials, production deployments, secret exposure, privileged runner changes, cloud resources, and paid/admin-only requirements.
Version and compatibility note
GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.
Official references and version notes
Documentation verification date: 2026-09-11. GitLab CI/CD rule semantics evolve; self-managed installations should confirm their deployed GitLab version before relying on newer syntax.
-
workflowkeyword — pipeline-creation rules, duplicate-pipeline avoidance, branch-to-MR switching, and current source examples. -
Specify when jobs run with
rules— first-match evaluation,CI_PIPELINE_SOURCEvalues, expressions, schedules,changes, and duplicate-pipeline guidance. -
CI/CD YAML syntax reference
— authoritative
rules,rules:changes,compare_to,rules:exists,when, and workflow syntax. - Predefined CI/CD variables — variable availability phases and safe source/ref/SHA metadata.
-
Debugging CI/CD pipelines
— current guidance for unexpected
changesbehavior and duplicate pipelines. - Troubleshooting merge request pipelines — evidence and repair guidance for branch + MR duplicates.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.