Chapter 08Lesson 05~220 minutes

Checkpoint Lab — GitHub-Hosted Runners, Images, Labels, Hardware, and Runtime Behavior

The checkpoint combines the chapter into one reviewable experiment. You will predict a two-OS run, execute a deterministic probe, capture runner/image/tool evidence, intentionally demonstrate one portability error, repair it, and produce a reproducibility manifest that explains exactly what can and cannot be reproduced from the retained evidence.

CheckpointTwo OSesPortability repairReproducibility manifestEvidence

Learning objectives

  • Predict runner/image/architecture and filesystem differences before executing the checkpoint.
  • Run the same deterministic logic on versioned Ubuntu and Windows hosted runners.
  • Preserve the first portability failure and repair it without hiding the causal evidence.
  • Produce a safe reproducibility manifest containing run, source, image, architecture and pinned-tool identity.
  • Explain why the manifest improves diagnosis without making the hosted VM permanently reproducible.

1. Checkpoint charter

Field Checkpoint value
Repository Learner-owned disposable repository only.
Mandatory runners ubuntu-24.04 and windows-2025.
Permissions permissions: {}; no API mutation.
Toolchain Python 3.13 via immutable actions/setup-python v7.0.0 commit.
Data Synthetic local text only; no secrets or external service.
Expected failure One OS-specific path/shell misuse captured before repair.
Evidence Run ID/attempt/SHA, requested label, runner OS/arch, ImageOS/ImageVersion, Python/Git versions, failure and repaired result.

2. Write predictions before execution

  1. Ubuntu and Windows jobs will receive different fresh instances and OS/shell semantics.
  2. The same Python line will be installed explicitly on both jobs even if preinstalled Python differs.
  3. A hard-coded Unix path will fail on Windows, and that failure will occur before any external side effect.
  4. The repaired workflow will use RUNNER_TEMP and PowerShell to produce equivalent local output on both OSes.

3. Run A — preserve a controlled portability failure

name: chapter08-checkpoint-broken
on: workflow_dispatch
permissions: {}

jobs:
  probe:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-24.04, windows-2025]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Runner identity
        shell: pwsh
        run: |
          "requested=${{ matrix.os }}"
          "runner_os=${{ runner.os }}"
          "runner_arch=${{ runner.arch }}"
          "image_os=$env:ImageOS"
          "image_version=$env:ImageVersion"
          "run_id=$env:GITHUB_RUN_ID"
          "attempt=$env:GITHUB_RUN_ATTEMPT"
          "sha=$env:GITHUB_SHA"

      - name: Set up Python 3.13
        uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
        with:
          python-version: '3.13'
          check-latest: false

      - name: Record Python
        shell: pwsh
        run: python --version

      - name: Intentionally non-portable step
        shell: bash
        run: |
          printf 'hello
' > /tmp/ch08.txt
          cat /tmp/ch08.txt

Preserve the Windows failure exactly. Do not edit the failed run or pretend the job tested your application. The failure belongs to workflow portability.

4. Run B — repair with runner-provided paths

      - name: Portable deterministic probe
        shell: pwsh
        run: |
          $p = Join-Path $env:RUNNER_TEMP 'ch08.txt'
          'hello' | Set-Content $p
          $text = (Get-Content $p -Raw).Trim()
          if ($text -ne 'hello') { throw "unexpected content" }
          "probe_result=$text"
          "temp_path=$env:RUNNER_TEMP"

Run B should make both matrix cells green. Record the new run ID/attempt and keep Run A as evidence of the original mistake.

5. Reproducibility manifest

Add this safe manifest step to Run B:

$m = [ordered]@{
  run_id        = $env:GITHUB_RUN_ID
  run_attempt   = $env:GITHUB_RUN_ATTEMPT
  source_sha    = $env:GITHUB_SHA
  requested_os  = '${{ matrix.os }}'
  runner_os     = '${{ runner.os }}'
  runner_arch   = '${{ runner.arch }}'
  image_os      = $env:ImageOS
  image_version = $env:ImageVersion
  python        = (python --version 2>&1 | Out-String).Trim()
  git           = (git --version | Out-String).Trim()
  setup_python  = '5fda3b95a4ea91299a34e894583c3862153e4b97'
  setup_release = 'v7.0.0'
  secrets_logged = $false
}
$m | ConvertTo-Json -Depth 3 | Set-Content "$env:RUNNER_TEMP/repro-manifest.json"
Get-Content "$env:RUNNER_TEMP/repro-manifest.json"

The manifest is evidence, not a VM snapshot. It lets another engineer identify the runner image release and explicit toolchain but does not freeze every kernel package, network condition, CPU scheduling decision, or upstream service.

6. Reconcile the two OS cells

Evidence Ubuntu Windows Interpretation
Requested label ubuntu-24.04 windows-2025 Workflow-controlled OS generation.
Architecture Record actual runner.arch Record actual runner.arch Runtime evidence, not assumption.
Image version Record exact value Record exact value GitHub image-release dependency.
Python 3.13 selected 3.13 selected Explicit toolchain contract.
Run A Expected pass Expected path/shell failure Workflow portability defect.
Run B Expected pass Expected pass Portable runner-temp design.

7. Verification checklist

  • Two requested versioned runner labels only.
  • Exact run IDs/attempts and source SHA preserved for Run A and Run B.
  • First Windows failure retained, not overwritten by narrative.
  • ImageOS/ImageVersion and runner.os/runner.arch recorded.
  • Python set explicitly with the immutable official action SHA.
  • No whole-environment dump, secret, token, artifact/cache, cloud service, package publication or deployment.
  • Repaired workflow uses runner-provided temp state and succeeds on both OSes.
  • Manifest states its limitation: evidence identity is not a bit-for-bit VM snapshot.

8. Cleanup / rollback

The hosted instances are destroyed automatically after each job. Remove the checkpoint workflow/branch if it is lab-only, or keep it as course evidence. There is no cloud resource, secret, package, environment, self-hosted runner, or external target to revoke.

9. Chapter 08 production operating contract

Chapter 08 adds a runner reproducibility contract: every important run records requested label, actual image release, architecture, relevant hardware class, explicit critical toolchain versions, job-local filesystem boundaries and external-network assumptions. -latest is a migration policy, not a frozen machine. Preinstalled software is convenient image state, not an undeclared application dependency.

Chapter 09 moves to self-hosted runners, runner groups, isolation, and operational security, where the fresh-hosted-instance assumption disappears and your organization becomes responsible for runner persistence, patching, cleanup, network reachability and trust.

Next lesson

Self-Hosted Runners, Runner Groups, Isolation, and Operational Security: Core Concepts and Mental Model

Continue with the next lesson to build on the current concepts, evidence, security boundaries, and operational practices.

Knowledge check

What is the purpose of keeping Run A after Run B succeeds?

Why is the manifest not a complete reproduction of the hosted VM?

What dependency is explicitly pinned in the checkpoint?

Why use RUNNER_TEMP instead of /tmp?

What changes in Chapter 09?

Official references and version notes

Version and compatibility note

Version-sensitive runner behavior was rechecked against current primary GitHub documentation on 2026-09-09. At verification time, ubuntu-latest maps to Ubuntu 24.04 x64, windows-latest to Windows Server 2025 x64, and macos-latest to macOS 26 Arm64; Ubuntu 26.04 and selected Arm64 images are available in preview. GitHub states that runner-image software is typically updated weekly and that -latest migrations are gradual, so a successful run must record the actual image version/toolchain rather than treating a label as a frozen machine. For standard hosted runners, every normal job receives a fresh hosted instance; steps inside one job share that instance, while separate jobs do not share its filesystem. The ubuntu-slim single-CPU option is a special container-on-shared-VM case and is not used in mandatory labs. Current public-repository standard Linux/Windows x64 runners provide 4 CPU/16 GB RAM/14 GB SSD, while private-repository standard Linux/Windows x64 runners provide 2 CPU/8 GB RAM/14 GB SSD; macOS and Arm64 classes have different specifications. Hardware figures are therefore plan/repository/image inputs, not universal constants. Larger runners are optional organization/enterprise features and are not required for course completion. Official actions/setup-python v7.0.0 is pinned in examples to 5fda3b95a4ea91299a34e894583c3862153e4b97. The checkpoint uses no real credential, external API, package publication, artifact/cache transport, deployment, larger runner or self-hosted runner.

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.