Chapter 24Lesson 05~220 minutes

Checkpoint Lab — Secret Scanning, Push Protection, Custom Patterns, Bypass Controls, and Incident Response

The checkpoint integrates prevention, a fake leak fixture, revocation-first response, location scoping, bypass review, and history-rewrite decision-making. You will prove that a GitHub-documented dummy secret is blocked, run a simulated incident record through containment and remediation, and produce a production-ready leak/bypass runbook before moving to provenance in Chapter 25.

Checkpoint labLeak simulationRunbookVerificationChapter 25 bridge

Learning objectives

  • Predict and verify the repository/security state changes caused by enabling protection and attempting a blocked write.
  • Run a harmless leak simulation using a GitHub-published dummy secret without creating an authentic credential.
  • Execute a revocation-first simulated incident record, including non-Git location scope and dependent-system migration.
  • Write a bypass-review policy and a history-rewrite decision record with plan-dependent alternatives.
  • Produce a verification checklist that proves no live credential remains and closes the chapter with a production operating model.
Checkpoint assumptions: GitHub.com, GitHub Free, one public disposable personal repository, repository-admin rights, and GitHub CLI for read-only/API evidence. No cloud account, real secret, paid organization, custom pattern, delegated bypass, history rewrite, or production system is required.

1. Scenario and two predictions before changing state

You are the release engineer for a fictional service called Atlas Relay. A previous retrospective found that developers occasionally pasted credentials into configuration examples. You must prove prevention works, then demonstrate how the team would respond if a credential had already escaped into both Git and an issue comment.

Prediction Expected state after action How you will verify independently
P1: enabling repository push protection changes hosted security configuration, not Git history Security settings change; default branch SHA stays the same REST security_and_analysis + GitHub commit SHA before/after
P2: attempting to save the documented dummy secret is blocked and canceled No commit/file and no bypass alert is created UI block + contents API 404/absence + unchanged branch SHA + hidden-secret alert list
P3: simulated revocation changes incident state before any cleanup decision Fixture moves active-simulated → revoked-simulated Versioned incident JSON/diff, with no credential value present

Write your predictions into CHECKPOINT.md before the experiment. Prediction turns a lab from a click sequence into a causal test.

2. Setup and baseline evidence

OWNER=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" user --jq .login)
REPO="$OWNER/gh-secret-incident-checkpoint"

gh repo create "$REPO" --public --add-readme --description "Disposable Chapter 24 checkpoint"
DEFAULT_BRANCH=$(gh repo view "$REPO" --json defaultBranchRef --jq .defaultBranchRef.name)
BASE_SHA=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO/commits/$DEFAULT_BRANCH" --jq .sha)

gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO" \
  --jq '{id,full_name,visibility,default_branch,security_and_analysis}'
printf 'Baseline SHA: %s\n' "$BASE_SHA"

In the web UI, inspect account-level Push protection for yourself. Then inspect repository Settings → Advanced Security. Record what is already enabled before changing it. Public repositories can use Secret Protection features free; if the current UI already reports them enabled, do not toggle them off merely to create a before-state.

3. Enable/confirm repository Secret Protection and prove Git did not change

Enable Secret Protection and repository push protection if necessary. This is a security-setting mutation, so record who performed it and why. Re-read the repository object and compare the branch SHA to the baseline.

AFTER_SETTINGS_SHA=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO/commits/$DEFAULT_BRANCH" --jq .sha)

gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO" \
  --jq '.security_and_analysis'

printf 'baseline=%s after-settings=%s\n' "$BASE_SHA" "$AFTER_SETTINGS_SHA"
test "$BASE_SHA" = "$AFTER_SETTINGS_SHA" && echo "Prediction P1 confirmed: settings changed without a Git commit."

4. Leak-prevention test: the fake secret is blocked before persistence

Use the current GitHub web editor to create training/checkpoint-secret.txt. Paste only the official GitHub dummy value below, attempt to commit, observe the push-protection message, then cancel and discard. Do not bypass.

secret_scanning_EXAMPLE_DUMMY_TOKEN_NOT_REAL_12345

Capture the pattern/display name and blocked file/line from the UI as non-sensitive evidence. Do not screenshot or copy real repository secrets in production incidents. Then prove nothing was stored:

CURRENT_SHA=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO/commits/$DEFAULT_BRANCH" --jq .sha)
printf 'after-block=%s\n' "$CURRENT_SHA"

if gh api -H "X-GitHub-Api-Version: 2026-03-10" \
  "repos/$REPO/contents/training/checkpoint-secret.txt" >/dev/null 2>&1; then
  echo "Unexpected: file exists; stop and inspect before proceeding."
  exit 1
else
  echo "Expected: blocked/canceled file does not exist."
fi

gh api --paginate -H "X-GitHub-Api-Version: 2026-03-10" \
  "repos/$REPO/secret-scanning/alerts?hide_secret=true&per_page=100" \
  --jq '.[] | {number,state,secret_type,validity,resolution,push_protection_bypassed}'

P2 is satisfied when the write was blocked, the candidate file is absent, the branch SHA is unchanged, and no bypass alert was created by this canceled attempt. If you see unexpected state, stop and interpret it before continuing.

5. Simulate the incident that prevention failed to stop

Now create a redacted incident record. The fixture represents an already-exposed fictional credential but stores no secret. Commit this record because incident evidence belongs in a durable controlled channel; in a real organization that channel may be an incident-management system rather than the public repository.

mkdir -p training
cat > training/incident.json <<'JSON'
{
  "incident": "INC-CH24-CHECKPOINT",
  "credential": "fictional_atlas_deployer",
  "secret_value": "<redacted-never-recorded>",
  "issuer_status": "active-simulated",
  "exposure_window": "2026-08-19T17:00:00Z/2026-08-19T17:12:00Z",
  "locations": [
    "git-commit:SIMULATED_SHA:config/deploy.example:4",
    "issue-comment:SIMULATED_ISSUE_17_COMMENT_2"
  ],
  "consumers": ["staging-deploy", "release-bot"],
  "provider_audit": "pending-simulated",
  "history_rewrite": "undecided"
}
JSON

git clone "https://github.com/$REPO.git" ch24-checkpoint
cd ch24-checkpoint
mkdir -p training
cp ../training/incident.json training/incident.json
git add training/incident.json
git commit -m "Add redacted Chapter 24 incident fixture"
git push origin HEAD
Why committing this is safe: the fixture contains only synthetic identifiers and <redacted-never-recorded>. Never commit a real incident’s credential value to an incident record.

6. Execute the runbook: revocation before remediation

Before editing the simulated Git/issue locations, update the fixture to show provider containment. This models the sequencing decision. In a real incident, a credential owner/provider administrator would perform the actual revoke/rotate operation in the issuing service, not through GitHub secret scanning.

import json
from pathlib import Path
p = Path("training/incident.json")
data = json.loads(p.read_text())
data["issuer_status"] = "revoked-simulated"
data["provider_audit"] = "no-unauthorized-use-found-simulated"
data["consumers_migrated"] = {
    "staging-deploy": True,
    "release-bot": True
}
p.write_text(json.dumps(data, indent=2) + "\n")
print("Revocation simulation recorded before content cleanup.")
git add training/incident.json
git commit -m "Record simulated revocation and consumer migration"
git push origin HEAD
git log --oneline -3

Verify two directions: the old credential would be rejected (revoked-simulated) and both legitimate consumers are marked migrated. A real runbook must obtain independent evidence from the issuer/application rather than trusting the incident note alone.

7. Scope all locations, including non-Git surfaces

The fixture names a Git location and an issue comment. In a live secret-scanning alert, the locations endpoint can enumerate commit, wiki, issue, Discussion, PR and review locations. Use this shape in the runbook, but do not invent a real alert number for the checkpoint.

# TEMPLATE — run only when you have a real alert number and authorization.
ALERT_NUMBER=123
# gh api -H "X-GitHub-Api-Version: 2026-03-10" \
#   "repos/$REPO/secret-scanning/alerts/$ALERT_NUMBER/locations?per_page=100" \
#   --paginate --jq '.[] | {type,details}'

echo "Checkpoint uses synthetic locations; no real alert mutation is required."

For each location, record whether the credential value is still visible, who can access the surface, and how it will be removed/replaced. Because the credential is already revoked in the runbook sequence, this step reduces residual disclosure/reuse risk instead of pretending to contain authentication.

8. Write the history-rewrite decision

Add a decision to the incident file or runbook. For this fictional revocable deployment credential, choose not-required after revocation unless another policy/compliance reason exists. Explain that GitHub history rewriting changes commit hashes, may break signatures/PR diffs, requires collaborator/fork coordination, and cannot erase copies outside repository control.

import json
from pathlib import Path
p = Path("training/incident.json")
data = json.loads(p.read_text())
data["history_rewrite"] = {
    "decision": "not-required",
    "reason": "Credential is revocable and is simulated revoked; no non-revocable sensitive data is present.",
    "reconsider_if": [
        "regulated or non-revocable data is discovered",
        "legal/compliance policy requires purge",
        "additional sensitive content remains beyond credential value"
    ]
}
p.write_text(json.dumps(data, indent=2) + "\n")
Do not execute git-filter-repo or a force/mirror push in this checkpoint. If a real incident requires history rewriting, use GitHub’s current sensitive-data removal procedure, freeze/coordinate repository writes, plan for changed SHAs/signatures/PRs/clones/forks, and obtain the required approvals/support.

9. Produce a deployment-quality bypass/exception policy

Your runbook must define bypass authority even though the mandatory personal repository does not require delegated bypass. Use a plan-dependent alternative: self-bypass with durable reason in simple public repositories; delegated bypass with independent reviewers in eligible Team organization repositories; exemptions only for trusted automation when redesign is impractical.

Policy field Checkpoint requirement
Default Remove the detected value; no bypass for real credentials.
Allowed reasons False positive or demonstrably non-secret test data; “fix later” requires incident owner and immediate containment plan.
Requester evidence Pattern, path, why safe, owner, expiry/cleanup ticket.
Approver Independent security/repository owner where delegated bypass is available.
Expiry Exception/bypass request must be time-bounded; current delegated requests expire after seven days.
Exemptions Rare, actor-specific, reviewed periodically, never granted to ordinary developers for convenience.
Metrics Bypass count by pattern/repo/actor/reason and repeat offenders/patterns.

10. Verification checklist and cleanup/rollback

  • The live GitHub dummy token was blocked and never persisted; no real credential was generated or copied.
  • Repository security state and branch SHA were recorded before/after enabling protection.
  • Alert inspection used hide_secret=true; no literal secret was printed to logs/transcripts.
  • The incident fixture records revocation before content cleanup, provider-use assessment, and consumer migration.
  • Both Git and non-Git exposure locations are represented in the incident scope.
  • History rewrite has an explicit decision/rationale and was not executed in the lab.
  • The bypass policy states requester evidence, reviewer authority, expiry, exemptions, and metrics.
git status --short
git log --oneline -5
git show HEAD:training/incident.json

gh api -H "X-GitHub-Api-Version: 2026-03-10" "repos/$REPO" \
  --jq '{full_name,visibility,archived,security_and_analysis}'

gh api --paginate -H "X-GitHub-Api-Version: 2026-03-10" \
  "repos/$REPO/secret-scanning/alerts?hide_secret=true&per_page=100" \
  --jq '.[] | {number,state,secret_type,validity,resolution,push_protection_bypassed}'

cd ..
# Reversible end-state: archive rather than deleting security evidence.
gh repo archive "$REPO" --yes

If you created an optional custom pattern or delegated-bypass configuration in an eligible disposable organization, remove that training-only policy after preserving its dry-run/review evidence. Do not disable organization protections that pre-existed the lab.

Knowledge check

The push-protection dialog appears before the commit is saved. What repository state should you predict if you cancel?

Why does the checkpoint change issuer_status before deleting simulated locations?

A secret-scanning alert appears only in an issue comment. Is a Git history rewrite useful for that location?

When should a revoked API token still trigger a history rewrite?

Why is “all writers may always bypass” weaker than delegated bypass?

What proves the incident is actually recovered?

11. Production operating model and Chapter 25 bridge

Chapter 24 adds a credential-leak control plane to the GitHub operating model: free/public historical detection, push-time prevention, provider/generic/custom pattern strategy, safe alert inspection, bypass governance, non-Git location scope, revocation-first containment, consumer migration, and an explicit history-rewrite decision. The durable rule is that a credential’s ability to authenticate is more important than the aesthetic cleanliness of repository history.

Chapter 25 changes the trust question from “did a credential leak?” to “can a consumer verify where an artifact came from and what build produced it?” You will carry forward the same evidence-first discipline into artifact attestations, SBOMs, build provenance, verification, and SLSA-oriented workflows.

Next chapter

Artifact Attestations, SBOMs, Build Provenance, Verification, and SLSA-Oriented Workflows: Concepts, Architecture, and Mental Model

Official references

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.