Chapter 01Lesson 05~150 minutes

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.

CheckpointPredictionsEvidence packetVerificationOperating model

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:

  1. Push prediction: a commit to main containing the workflow creates a new run whose event is push, attempt is 1, and head/event SHA corresponds to that controlled revision.
  2. Manual prediction: dispatching the workflow from main creates a different run ID with event workflow_dispatch and attempt 1.
  3. Runner prediction: each job executes on GitHub-hosted Ubuntu 24.04, and its steps share the same job filesystem.
  4. Permission prediction: the workflow completes without repository API write permission or any secret.
  5. 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

  1. Record the current main SHA before adding the checkpoint file.
  2. Add/commit ch01-checkpoint.yml.
  3. Push the exact commit to main.
  4. Open the resulting Actions run and record its URL, run ID, attempt, event, ref, SHA, job conclusion, and runner information.
  5. 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

  1. Confirm the checkpoint workflow is present on the default branch.
  2. Open its Actions page and choose Run workflow.
  3. Select main.
  4. Before starting, write the expected current main SHA.
  5. 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 main push; 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

  1. Preserve the evidence packet and exact run URLs/IDs first.
  2. Restore any branch filter changed for the controlled-failure test.
  3. Remove only the optional broken workflow if you do not want to retain it.
  4. Either keep the disposable repository for Chapter 02 or delete that exact repository manually after confirming the evidence packet is stored elsewhere.
  5. 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.

Next lesson

Workflow Files, YAML Structure, Jobs, Steps, and Actions

Chapter 02 turns the execution model into precise authoring skill: understand workflow file structure, job/step boundaries, action invocation, shell behavior, and the configuration GitHub actually evaluates.

Knowledge check

Why must predictions be written before the checkpoint runs?

The checkpoint succeeds with permissions: {}. What can you conclude?

Why is a green checkpoint not a CI proof for the application source?

If you rerun the manual run, which identity should remain the same and which should change?

What should happen before deleting the disposable repository?

Official references and version notes

Version and compatibility note

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.