Chapter 07Lesson 05~220 minutes

Checkpoint Lab — Secrets, Environments, Variables, Redaction, and Credential Hygiene

The checkpoint assembles Chapter 07 into an auditable synthetic credential lifecycle. You will record ownership and scope, create a repository secret and environment-scoped secret, consume them without printing values, verify that no artifact/log intentionally contains the credential, rotate the repository secret with a non-secret generation marker, delete it, prove a fresh run fails because the secret is absent, and finish with a credential data-flow diagram plus cleanup record.

CheckpointCredential lifecycleRotationRevocationData-flow evidence

Learning objectives

  • Define owner, purpose, scope, trust boundary, rotation rule, and revocation criteria before creating the fake credential.
  • Run repository- and environment-scoped secret consumers that emit only presence and run-identity evidence.
  • Inspect logs and staged output paths for accidental exposure without dumping secret-bearing state.
  • Rotate and revoke the repository secret, preserving evidence from pre-rotation, post-rotation, and post-revocation runs.
  • Produce a data-flow diagram and final operating contract that distinguishes GitHub removal from external issuer revocation.

1. Preflight contract

Field Checkpoint value
Repository Learner-owned disposable repository only.
Runner ubuntu-24.04.
Permissions permissions: {}; no GitHub mutation required.
Repository secret LAB_REPO_CREDENTIAL, synthetic and authority-free.
Environment secret LAB_ENV_CREDENTIAL on lab-gate, synthetic and authority-free.
Configuration LAB_STAGE=training; LAB_SECRET_GENERATION=v1 then v2.
External systems None. No cloud, registry, database, package, or SaaS request.
Abort Stop if any value has real authority or a credential value appears in logs/files.

2. Write predictions before execution

  1. Run A: repository secret present; environment secret present only in the job that references lab-gate.
  2. Run B after rotation: repository secret still present; non-secret generation marker is v2.
  3. Run C after deletion: repository secret resolves empty and the repository job fails before any external action; environment job remains independent.
  4. No job requires write token permissions, third-party actions, artifacts, caches, or cloud credentials.

3. Checkpoint workflow

name: Chapter 07 credential lifecycle checkpoint
on:
  workflow_dispatch:

permissions: {}

env:
  LAB_STAGE: ${{ vars.LAB_STAGE }}
  LAB_SECRET_GENERATION: ${{ vars.LAB_SECRET_GENERATION }}

jobs:
  repository_secret:
    runs-on: ubuntu-24.04
    env:
      LAB_REPO_CREDENTIAL: ${{ secrets.LAB_REPO_CREDENTIAL }}
    steps:
      - name: Record safe run identity
        run: |
          printf 'run_id=%s attempt=%s sha=%s stage=%s generation=%s\n' \
            "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" \
            "$LAB_STAGE" "$LAB_SECRET_GENERATION"

      - name: Require repository secret without printing it
        run: |
          set -euo pipefail
          if [[ -z "$LAB_REPO_CREDENTIAL" ]]; then
            echo 'repo_secret_state=missing'
            exit 40
          fi
          echo 'repo_secret_state=present'

      - name: Pass the fake credential to a child process through stdin
        run: |
          set -euo pipefail
          printf '%s' "$LAB_REPO_CREDENTIAL" | python3 -c \
            'import sys; assert sys.stdin.read(); print("stdin_secret_consumed=true")'

      - name: Create only non-sensitive checkpoint evidence
        run: |
          set -euo pipefail
          mkdir -p checkpoint-evidence
          printf 'run_id=%s\nrun_attempt=%s\nsource_sha=%s\ngeneration=%s\nsecret_value_recorded=false\n' \
            "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" "$GITHUB_SHA" \
            "$LAB_SECRET_GENERATION" > checkpoint-evidence/state.txt
          find checkpoint-evidence -type f -printf '%P\n'

  environment_secret:
    runs-on: ubuntu-24.04
    environment: lab-gate
    env:
      LAB_ENV_CREDENTIAL: ${{ secrets.LAB_ENV_CREDENTIAL }}
    steps:
      - name: Require environment secret without printing it
        run: |
          set -euo pipefail
          if [[ -z "$LAB_ENV_CREDENTIAL" ]]; then
            echo 'environment_secret_state=missing'
            exit 41
          fi
          echo 'environment_secret_state=present'

The checkpoint deliberately does not upload checkpoint-evidence. The file is local, non-sensitive state used to practice manifest inspection. Chapter 13 will teach artifact transport and retention explicitly.

4. Create synthetic state and execute Run A

  1. Create the two repository variables and repository secret.
  2. Create lab-gate and its environment secret, or use the documented simulation if your private repository/plan does not expose environment secrets.
  3. Dispatch the workflow.
  4. Record run ID, attempt, source SHA, job conclusions, environment association, generation v1, and the two present states.
  5. Review the log manually for unexpected values; do not search by pasting the actual secret into a browser or script.

5. Produce the credential data-flow diagram

Checkpoint credential flow — values remain opaque
flowchart TD
    A[Credential owner creates synthetic value] --> B[Repository secret store]
    A --> C[Environment lab-gate secret store]
    D[workflow_dispatch] --> E[repository_secret job]
    D --> F[environment_secret job]
    B --> E
    C --> G{Environment rules satisfied?}
    G -->|Yes| F
    G -->|No / pending| H[Secret unavailable / job waits]
    E --> I[Process env then stdin]
    F --> J[Process env]
    I --> K[Boolean evidence only]
    J --> K
    K --> L[Rotation / revocation record]

Annotate the diagram with who owns each secret, which job can receive it, what is logged, and which cleanup event closes the lifecycle.

6. Exposure inspection without dumping state

For each run, verify:

  • no step prints LAB_REPO_CREDENTIAL or LAB_ENV_CREDENTIAL;
  • no set -x, verbose HTTP trace, whole env dump, or secrets/context dump exists;
  • local checkpoint-evidence/state.txt contains only run identity, generation, and secret_value_recorded=false;
  • no artifact/cache step is present;
  • no external service received the fake credential.

7. Rotate and execute Run B

  1. Update LAB_REPO_CREDENTIAL to a new synthetic value.
  2. Update LAB_SECRET_GENERATION=v2.
  3. Dispatch Run B after the settings update.
  4. Verify generation=v2, repo_secret_state=present, and the same source/workflow expectations.
  5. Record the settings/audit change time if available; do not record either secret value.

8. Revoke and execute Run C

  1. Delete LAB_REPO_CREDENTIAL.
  2. Dispatch a fresh Run C.
  3. Preserve the expected repo_secret_state=missing and exit 40 evidence.
  4. Do not “repair” Run C by weakening the presence check; its failure is the proof of GitHub-side revocation.

If this were a real external credential, the checkpoint would also require revocation at the external issuer and provider-side evidence that the old credential can no longer authenticate.

9. Final evidence packet

Evidence Required statement
Run A generation v1; repository/environment secrets present; no external side effect.
Run B generation v2; repository secret present after documented rotation event.
Run C repository secret missing after deletion; intentional failure preserved.
Workflow SHA Exact source revision for each run.
Trust boundary Manual dispatch in learner-owned disposable repository; no fork/Dependabot input.
Residue review No secret in logs, local evidence file, artifact/cache, source, or external service.
Environment lab-gate association/protection result or simulation note.
Limitations Presence/rotation are synthetic; no real provider authentication was performed.

10. Cleanup / rollback

  1. Delete the environment secret and repository variables.
  2. Remove lab-gate if it is lab-only.
  3. Keep or delete the disposable repository according to your study evidence policy.
  4. Confirm no real credential was ever created, stored, or transmitted.

11. Chapter 07 production operating contract

Chapter 07 adds a credential lifecycle contract: every confidential value has an owner, issuer, purpose, narrow scope, eligible event/job boundary, injection mechanism, residue policy, rotation rule, emergency revocation procedure, and evidence trail. Log masking is defense in depth, not authorization. Secret removal from GitHub is distinct from provider revocation. Untrusted fork/Dependabot code remains outside privileged credential zones, and long-lived cloud keys are candidates for OIDC replacement.

Chapter 08 moves to GitHub-hosted runners, images, labels, hardware, and runtime behavior. That chapter explains the compute environment that receives these values: image mutability, labels, filesystem isolation, preinstalled tools, job boundaries, and runtime evidence.

Next lesson

GitHub-Hosted Runners, Images, Labels, Hardware, and Runtime Behavior: 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 are the three checkpoint runs intended to prove?

Why does the checkpoint not upload its evidence directory?

What does secret_value_recorded=false prove?

If Run C fails after deleting the GitHub secret, is a real provider credential necessarily revoked?

What production contract does Chapter 07 add?

Official references and version notes

  • Secrets concept — current model for repository, organization, and environment Actions secrets and how workflows receive them.
  • Secrets reference — current naming, precedence, size/count limits, queue/start read timing, and automatic redaction behavior.
  • Using secrets in GitHub Actions — current workflow injection patterns, missing-secret behavior, fork/Dependabot restrictions, masking guidance, CLI setup, and OIDC recommendation.
  • Variables concept — current distinction between non-sensitive configuration variables and secrets.
  • Variables reference — current vars scope, precedence, limits, and environment-variable semantics.
  • Deployments and environments — current environment secret availability, protection-rule timing, plan/visibility boundaries, and self-hosted-runner warning.
  • Events that trigger workflows — current fork pull-request secret restrictions and read-only token behavior.
  • Dependabot on GitHub Actions — current Dependabot-specific token and secret restrictions.
  • Workflow syntax — current secrets, environment, reusable-workflow secret passing, and conditional semantics.
  • Workflow commands — current ::add-mask:: behavior and environment-file commands.
  • Secure use reference — current guidance for rotating/removing secrets, approval gates, untrusted input, and credential hygiene.
  • OpenID Connect — current model for exchanging GitHub OIDC identity for short-lived provider credentials instead of storing long-lived cloud secrets.
  • Reuse workflows — current explicit secret passing, secrets: inherit, and directly-called workflow boundaries.
Version and compatibility note

Version-sensitive secrets/environment behavior was rechecked against current primary GitHub documentation on 2026-09-09. Mandatory executable workflows use a learner-owned disposable repository, ubuntu-24.04, built-in Bash/Python only, synthetic credentials, and permissions: {}; no third-party action, PAT, real API key, cloud account, package publication, deployment, or self-hosted runner is required. At verification time, Actions secrets can exist at organization, repository, or environment scope; a lower scope wins on a same-name collision (environment over repository over organization). Organization/repository secrets are read when a workflow run is queued, while environment secrets are read when the job referencing that environment starts. A secret that is not set resolves to an empty string; normal Actions secrets are not passed to fork-origin pull-request workflows (except the special automatic GITHUB_TOKEN behavior) and are not available to Dependabot-triggered runs. Secrets are limited to 48 KB; current counts are up to 1,000 organization, 100 repository, and 100 environment secrets. GitHub log redaction is a safety layer, not a confidentiality proof; transformed/structured values, artifacts, caches, process arguments, and third-party systems remain separate leakage surfaces. For cloud providers that support OIDC, the course recommends short-lived federation instead of long-lived provider keys; the full OIDC trust-policy implementation is deferred to Chapter 20. The checkpoint intentionally contains no artifact upload, third-party action, provider authentication, real secret, or repository mutation. It practices lifecycle evidence while keeping all credential values opaque.

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.