Checkpoint Lab — GitHub Actions Foundations, Automation Model, and CI/CD Concepts
The checkpoint turns Chapter 01 into a reviewable operating habit. You will create one minimal CI skeleton in a disposable repository, predict its state transitions, trigger it once by push and once manually, collect a compact evidence packet, and state precisely what the successful runs prove—and what they cannot prove because source checkout, build/test, artifacts, deployment, and external health are intentionally outside this first chapter.
Learning objectives
- Plan a bounded GitHub Actions experiment with explicit repository, trigger, runner, permission, evidence, and cleanup assumptions.
- Predict at least two event/run/job/runner state changes before execution and verify each prediction independently.
- Capture push and manual-run evidence tied to exact SHAs, run IDs, attempts, runner context, and step conclusions.
- Diagnose one controlled mismatch without broadening permissions or destroying first-failure evidence.
- Produce a concise evidence packet and explain the chapter’s contribution to a secure production GitHub Actions operating model.
1. Checkpoint mission
Your deliverable is not merely a workflow file. It is a small evidence packet showing that you can reason from repository intent to observed execution state. Use only a disposable repository you control. No production code, real secret, cloud credential, package registry, protected enterprise runner, or deployment target is required.
| Checkpoint field | Required value |
|---|---|
| Repository |
Disposable training repository, e.g.
gha-ch01-lab.
|
| Workflow | .github/workflows/ch01-checkpoint.yml. |
| Triggers |
Push to main + manual
workflow_dispatch.
|
| Runner | ubuntu-24.04. |
| Permissions | permissions: {}. |
| Secrets | None. |
| External actions | None. |
| External side effects | None. |
| Evidence | Event/ref/SHA, run ID/attempt, job/step conclusions, runner identity, safe selected payload fields, assumptions/limitations. |
2. Write predictions before execution
Create checkpoint-predictions.md locally (it does not
need to be committed). Include at least these predictions:
-
Push prediction: a commit to
maincontaining the workflow creates a new run whose event ispush, attempt is 1, and head/event SHA corresponds to that controlled revision. -
Manual prediction: dispatching the workflow from
maincreates a different run ID with eventworkflow_dispatchand attempt 1. - Runner prediction: each job executes on GitHub-hosted Ubuntu 24.04, and its steps share the same job filesystem.
- Permission prediction: the workflow completes without repository API write permission or any secret.
- Boundary prediction: a green run cannot prove source build/test or deployment health because neither source checkout/build nor deployment exists in the checkpoint.
Predictions convert the lab from a click sequence into an experiment. If observations differ, preserve the difference and diagnose it; do not rewrite the prediction afterward.
3. Author the checkpoint workflow
name: Chapter 01 - Checkpoint Evidence
on:
push:
branches: [main]
workflow_dispatch:
permissions: {}
jobs:
evidence:
name: Capture execution evidence
runs-on: ubuntu-24.04
steps:
- name: Show bounded runtime identity
shell: bash
run: |
set -euo pipefail
printf 'event=%s\n' "$GITHUB_EVENT_NAME"
printf 'ref=%s\n' "$GITHUB_REF"
printf 'sha=%s\n' "$GITHUB_SHA"
printf 'run_id=%s\n' "$GITHUB_RUN_ID"
printf 'run_number=%s\n' "$GITHUB_RUN_NUMBER"
printf 'run_attempt=%s\n' "$GITHUB_RUN_ATTEMPT"
printf 'runner_os=%s\n' "$RUNNER_OS"
printf 'runner_arch=%s\n' "$RUNNER_ARCH"
- name: Extract selected event evidence
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import json, os
with open(os.environ['GITHUB_EVENT_PATH'], encoding='utf-8') as fh:
event = json.load(fh)
evidence = {
'event_name': os.environ['GITHUB_EVENT_NAME'],
'github_ref': os.environ['GITHUB_REF'],
'github_sha': os.environ['GITHUB_SHA'],
'payload_ref': event.get('ref'),
'payload_before': event.get('before'),
'payload_after': event.get('after'),
'repository': event.get('repository', {}).get('full_name'),
}
print(json.dumps(evidence, indent=2, sort_keys=True))
PY
- name: Prove step-to-step local continuity
shell: bash
run: |
set -euo pipefail
mkdir -p checkpoint
printf '%s\n' "$GITHUB_RUN_ID:$GITHUB_RUN_ATTEMPT:$GITHUB_SHA" \
> checkpoint/identity.txt
test -s checkpoint/identity.txt
- name: Read local continuity evidence
shell: bash
run: |
set -euo pipefail
test -f checkpoint/identity.txt
cat checkpoint/identity.txt
- name: Summarize bounded claims
shell: bash
run: |
{
echo '## Chapter 01 checkpoint'
echo
echo "- Event: \`$GITHUB_EVENT_NAME\`"
echo "- Ref: \`$GITHUB_REF\`"
echo "- SHA: \`$GITHUB_SHA\`"
echo "- Run ID: \`$GITHUB_RUN_ID\`"
echo "- Attempt: \`$GITHUB_RUN_ATTEMPT\`"
echo "- Runner: \`$RUNNER_OS/$RUNNER_ARCH\`"
echo
echo 'This run does not claim source build/test or deployment success.'
} >> "$GITHUB_STEP_SUMMARY"
The workflow contains no uses: dependency. That is
intentional for this checkpoint. There is no source checkout and
therefore no claim about application source files. The only tested
behavior is event-driven execution and same-job local state.
4. Execute controlled run A: push
-
Record the current
mainSHA before adding the checkpoint file. - Add/commit
ch01-checkpoint.yml. - Push the exact commit to
main. - Open the resulting Actions run and record its URL, run ID, attempt, event, ref, SHA, job conclusion, and runner information.
- Verify each step's expected output. Do not copy full environment/context dumps into the packet.
If no run appears, stop. Inspect the workflow location, default branch, event filter, Actions policy, and the pushed revision. Do not “fix” the problem by adding permissions because permissions are evaluated only after a run/job exists.
5. Execute controlled run B: manual dispatch
- Confirm the checkpoint workflow is present on the default branch.
- Open its Actions page and choose Run workflow.
- Select
main. -
Before starting, write the expected current
mainSHA. - Run it, then capture the same evidence fields as run A.
The manual run should have a new run ID, not attempt 2 of run A. If
you intentionally rerun run B afterward for learning, preserve
attempt 1 first; then verify the run ID remains stable while
GITHUB_RUN_ATTEMPT increments.
6. Build the evidence packet
Create a local folder:
chapter01-evidence/
├── assumptions.md
├── predictions.md
├── workflow.yml
├── push-run.md
├── manual-run.md
├── comparison.md
└── limitations.md
Minimum content:
| File | Required evidence |
|---|---|
assumptions.md |
Date 2026-09-09 verification basis; disposable repository;
hosted ubuntu-24.04; no
secret/action/deployment; permission boundary.
|
predictions.md |
Predicted event/run/job/runner/permission outcomes written before runs. |
workflow.yml |
Exact workflow revision used for the checkpoint. |
push-run.md |
Run URL/ID, attempt, push event, ref/SHA, runner, step/job conclusions. |
manual-run.md |
Run URL/ID, attempt, workflow_dispatch event, selected ref/SHA, runner, conclusions. |
comparison.md |
What changed between events and what remained invariant. |
limitations.md |
No source checkout/build/test, artifact, required check, secret, OIDC, release, deployment, external health, or self-hosted runner claim. |
If you already use GitHub CLI, you may add read-only API JSON using
gh run view or gh api. CLI use is
optional; the packet can be assembled from the UI and logs.
7. Verify predictions independently
For each prediction, record prediction → observation → evidence → interpretation. Example:
Prediction: manual dispatch creates a new run ID with attempt 1.
Observation: run ID 123... differs from push run; attempt = 1.
Evidence: Actions run page + bounded runtime identity step.
Interpretation: workflow_dispatch created a separate run, not a rerun.
Do not count the workflow's own printed sentence as the only evidence for a claim it makes about GitHub state. Corroborate with the run UI/API where practical. This prevents a script from “proving” its own assumption.
8. Controlled diagnostic test
Choose exactly one safe mismatch:
-
Option A: temporarily use a nonmatching push
branch filter and prove no run is selected for a
mainpush; or - Option B: create the Lesson 4 two-job local-file workflow and prove the consumer job cannot see the producer's filesystem.
Preserve the failed/non-run evidence and write the causal layer. Apply one correction only. Do not broaden token permissions, print secrets/contexts, switch to a privileged runner, or delete the original evidence.
9. Explain what “green” proves and does not prove
| Observed green state | It proves | It does not prove |
|---|---|---|
| Workflow run success | Required jobs in that run reached successful conclusions under observed context. | That unexecuted workflows, other events, or external systems are correct. |
| Evidence job success | The shell/Python steps succeeded on the assigned runner. | Application source compiles/tests; source was not checked out. |
| Same-job file read | Steps in this job shared the runner filesystem as expected. | Separate jobs or future runs share that file. |
permissions: {} workflow success |
This lab did not need repository API permissions for its local work. | Later build/release/deployment jobs need no permissions. |
| Manual dispatch success | Manual trigger selected and executed the workflow for the selected ref. | A push filter or scheduled event behaves identically. |
10. Cleanup / rollback
- Preserve the evidence packet and exact run URLs/IDs first.
- Restore any branch filter changed for the controlled-failure test.
- Remove only the optional broken workflow if you do not want to retain it.
- Either keep the disposable repository for Chapter 02 or delete that exact repository manually after confirming the evidence packet is stored elsewhere.
- Do not delete unrelated runs/repositories or change organization-wide Actions settings.
There is no cloud/registry/deployment rollback because the checkpoint created no external side effect. That absence is itself a design property of the first chapter.
11. Production operating-model addition
Chapter 01 adds an execution-evidence contract: every automation claim should be tied to the triggering event, immutable revision, workflow/run identity, job/runner context, evaluated authority, step evidence, and any external side effects. Different green states must remain separate. First-failure evidence is preserved before rerun. Runner-local state is treated as ephemeral. Permissions start narrow. External target health is proved by the target, not inferred from a workflow badge.
This contract becomes the foundation for the rest of the course. Chapter 02 adds precise workflow/YAML/job/step/action structure on top of it; later chapters add events, contexts, outputs, permissions, secrets, runners, matrices, artifacts, OIDC, deployments, provenance, governance, recovery, and enterprise platform design without losing the evidence chain.
Knowledge check
Why must predictions be written before the checkpoint runs?
So observations can test a prior model instead of being retrofitted into a story after the result is known.
The checkpoint succeeds with permissions: {}. What
can you conclude?
Only that this local evidence workflow did not need repository API permissions. It says nothing about the minimum permissions required by later checkout, publication, or deployment workflows.
Why is a green checkpoint not a CI proof for the application source?
The checkpoint intentionally does not check out, build, lint, or test source. Its claim is limited to the GitHub Actions execution lifecycle and evidence.
If you rerun the manual run, which identity should remain the same and which should change?
The run ID remains the same for that logical run;
GITHUB_RUN_ATTEMPT increments for the rerun
attempt.
What should happen before deleting the disposable repository?
Preserve the evidence packet, run IDs/URLs, exact workflow content, predictions, observations, and limitations so the chapter remains reviewable after cleanup.
Official references and version notes
- Understanding GitHub Actions — current component model for workflows, events, jobs, steps, actions, and runners.
- Workflow syntax for GitHub Actions — authoritative workflow keys, permissions, jobs, runner selection, and manual dispatch syntax.
- Variables reference — definitions of GITHUB_SHA, GITHUB_REF, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT, and related default variables.
- GitHub-hosted runners reference — current hosted-runner labels, VM behavior, hardware, and image caveats.
- Billing and usage — current availability, public-repository standard-runner usage, private-repository quotas, and usage boundaries.
- Events that trigger workflows — authoritative event behavior and event-specific ref/SHA definitions.
- GITHUB_TOKEN concepts — current job-token lifecycle and repository-scoped authentication model; the checkpoint intentionally requests no permissions.
Rechecked on 2026-09-09. The checkpoint is deliberately free/disposable-compatible and does not require an external action, secret, protected environment, self-hosted/larger runner, cloud account, registry, or deployment target. Standard hosted-runner availability, usage, workflow syntax, default variables, and token behavior remain platform-sensitive and should be revalidated when regenerated.
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.