Chapter 21Lesson 05~205 minutes

Checkpoint Lab — Signing, Trust, Secret Removal, fsck, Safe Directories, and Repository Integrity

Checkpoint a complete repository-security incident using fake secret material, ephemeral signatures, evidence capture, current filter-repo remediation, post-rewrite integrity checks, re-signing, and publication/prevention planning.

CheckpointSigningSecret remediationSupply-chain trust

Learning objectives

  • Predict and verify commit-ID, signature, and reachability consequences of a sensitive-history rewrite.
  • Detect/document a fake leaked marker and simulate immediate rotation before cleanup.
  • Preserve refs, reflogs, fsck evidence, and a controlled pre-rewrite bundle.
  • Verify sanitized reachable history and establish a new signed attestation when a backend is available.
  • Write force-update, cache/fork/mirror cleanup, collaborator recovery, and prevention procedures.

1. Checkpoint scenario — a fake credential appears in a partially signed release history

You will create an unsigned baseline, a signed release candidate, and an unsigned commit containing the harmless marker FAKE_TOKEN_DO_NOT_USE_2026. You will detect the exposure, simulate immediate rotation, preserve evidence, analyze fsck output, rewrite in a fresh clone with the current recommended tool, then verify the sanitized history and create a new signed attestation.

2. Predict before running the checkpoint

  1. If a historical blob changes, will descendant commit IDs remain the same?
  2. If a real token is still active, does completing a Git rewrite make that token cryptographically unusable?
  3. Will an old commit/tag signature continue to attest to a rewritten object with a different payload?
  4. Can an unreachable commit appear in fsck output without repository corruption?

3. Create an isolated source and signing environment

Git Bash / Bash / zsh

mkdir git-security-checkpoint
cd git-security-checkpoint
export GNUPGHOME="$PWD/gnupg-home"
mkdir -m 700 "$GNUPGHOME"

git init -b trunk source
cd source
git config user.name "Learner Example"
git config user.email "learner@example.invalid"
printf "service=checkout\nstatus=baseline\n" > app.conf
git add app.conf
git commit -m "baseline: unsigned"
UNSIGNED=$(git rev-parse HEAD)

PowerShell

New-Item -ItemType Directory git-security-checkpoint | Out-Null
Set-Location git-security-checkpoint
$env:GNUPGHOME = Join-Path (Get-Location) 'gnupg-home'
New-Item -ItemType Directory $env:GNUPGHOME | Out-Null
git init -b trunk source
Set-Location source
git config user.name 'Learner Example'
git config user.email 'learner@example.invalid'

4. Signing preflight — use a free local backend if present

gpg --version
gpg --batch --passphrase '' --quick-generate-key \
  'Learner Example <learner@example.invalid>' ed25519 sign 0

KEY=$(gpg --batch --with-colons --list-secret-keys \
  'learner@example.invalid' |
  awk -F: '$1=="fpr" {print $10; exit}')

git config gpg.format openpgp
git config user.signingKey "$KEY"

If GPG is unavailable or this noninteractive key-generation form is unsupported, record “signing backend unavailable” and continue with integrity/secret-removal exercises. Do not import a real personal key merely to satisfy the lab.

5. Create signed and unsigned objects

printf "status=release-candidate\n" >> app.conf
git add app.conf
git commit -S -m "release: signed candidate"
SIGNED=$(git rev-parse HEAD)
git tag -s signed-v1 -m "Signed training release"

git verify-commit "$SIGNED"
git verify-tag signed-v1
git log -1 --show-signature --format='%H %G? %GF %GS %s'

Record the fingerprint and exit statuses in the evidence report. The key is disposable but the verification workflow mirrors production.

6. Commit the harmless marker, then remove it only from the current snapshot

printf "api_token=FAKE_TOKEN_DO_NOT_USE_2026\n" >> app.conf
git add app.conf
git commit -m "incident: fake credential committed"
LEAK=$(git rev-parse HEAD)

sed -i 's/FAKE_TOKEN_DO_NOT_USE_2026/ROTATED_FAKE_VALUE/' app.conf
git add app.conf
git commit -m "containment: current snapshot no longer has fake token"
TIP_BEFORE=$(git rev-parse HEAD)

7. Detect and document the exposure

grep -n 'FAKE_TOKEN_DO_NOT_USE_2026' app.conf || echo "current snapshot clean"
git log -S'FAKE_TOKEN_DO_NOT_USE_2026' --all --oneline -- app.conf
git grep 'FAKE_TOKEN_DO_NOT_USE_2026' $(git rev-list --all)

printf 'unsigned=%s\nsigned=%s\nleak=%s\ntip-before=%s\n' \
  "$UNSIGNED" "$SIGNED" "$LEAK" "$TIP_BEFORE" \
  > ../incident-oids-before.txt

Prediction check: history search still finds the marker even though the current file is clean.

8. Simulate immediate credential rotation before any rewrite

For a real credential, revoke/rotate it at the issuing service now. Git cannot perform that security action.
printf "credential=FAKE_TOKEN_DO_NOT_USE_2026\nrotation=SIMULATED_REVOKED\n" \
  > ../rotation-record.txt

9. Preserve pre-rewrite evidence and backup

git status --short --branch
git show-ref --head > ../refs-before.txt
git reflog --all --date=iso > ../reflog-before.txt
git log --graph --decorate --oneline --all > ../graph-before.txt
git fsck --strict --no-progress > ../fsck-before.txt 2>&1
git bundle create ../before-rewrite.bundle --all
git bundle verify ../before-rewrite.bundle

Do not publish the bundle: it intentionally preserves the fake leaked marker as evidence/recovery data.

10. Create and inspect an unreachable evidence object

TREE=$(git write-tree)
ORPHAN=$(printf 'checkpoint orphan evidence\n' | git commit-tree "$TREE")
git fsck --unreachable --no-reflogs --no-progress | tee ../unreachable-before.txt
grep "$ORPHAN" ../unreachable-before.txt

Prediction check: an unreachable commit can be reported without indicating corruption. Preserve it until the checkpoint cleanup.

11. Create a local no-account remote and fresh cleanup clone

cd ..
git init --bare -b trunk origin.git
git -C source remote add training-origin ../origin.git
git -C source push training-origin --all
git -C source push training-origin --tags

git clone --no-local origin.git cleanup
cd cleanup
git log --all --oneline --decorate --graph --max-count=20

12. Preflight the current recommended rewrite tool

git filter-repo --version
If unavailable, stop here and install git-filter-repo from its maintained documentation before continuing. Git's filter-branch manual recommends filter-repo instead; do not substitute filter-branch as a shortcut.
printf 'literal:FAKE_TOKEN_DO_NOT_USE_2026==>REMOVED_FAKE_TOKEN\n' \
  > ../replacement-expressions.txt

13. Rewrite the disposable fresh clone

History rewrite: commit IDs and signature relationships change. This command is intentionally confined to the fresh cleanup clone; the source and bundle remain as recovery/evidence copies.
git filter-repo \
  --sensitive-data-removal \
  --replace-text ../replacement-expressions.txt

Read filter-repo's report. Sensitive-data mode is designed to help identify additional cleanup work for other copies/refs; do not treat local completion as incident closure.

14. Verify reachable sanitized history

git log -S'FAKE_TOKEN_DO_NOT_USE_2026' --all --oneline -p
git grep 'FAKE_TOKEN_DO_NOT_USE_2026' $(git rev-list --all) \
  && echo "FAIL: marker remains" \
  || echo "PASS: marker absent from reachable rewritten history"

git fsck --strict --no-progress
git log --graph --decorate --oneline --all --max-count=30
TIP_AFTER=$(git rev-parse HEAD)
printf 'tip-after=%s\n' "$TIP_AFTER"

Prediction check: TIP_AFTER should differ from the pre-rewrite tip because an ancestor's content changed.

15. Verify signature impact honestly

Filter-repo rewrites commit/tag payloads through fast-export/import and strips signatures that cannot remain valid. Inspect the resulting objects:

git log --show-signature --oneline --all --max-count=10
git tag --list --format='%(refname:short) %(objecttype) %(objectname)'

Do not claim the old signed release still authenticates the rewritten history. Instead create a new attestation after verification.

16. Create and verify a new sanitized signed tag

If the ephemeral OpenPGP key is available in this shell:

git config user.name "Learner Example"
git config user.email "learner@example.invalid"
git config gpg.format openpgp
git config user.signingKey "$KEY"
git tag -s sanitized-v1 -m "Sanitized checkpoint history"
git verify-tag sanitized-v1

This new tag signs the new sanitized payload. It does not erase the incident; it establishes a new provenance point after cleanup.

17. Write the force-update coordination plan before publishing anywhere

Do not broad-force a real remote from this lesson. Publication is a coordinated incident step.
Publication coordination
1. Freeze writes and announce exact maintenance window.
2. Record authoritative remote branch/tag OIDs immediately before update.
3. Confirm every contaminated ref that must be replaced/deleted.
4. Use narrow refspecs and expected-old/force-with-lease protection where applicable.
5. Handle protected/hidden hosting refs through provider-specific administration.
6. Invalidate or replace contaminated CI caches, artifacts, mirrors, backups, and forks as policy permits.
7. Tell collaborators not to merge/push old history back; provide a clean re-clone/recovery procedure.
8. Re-run secret scans and integrity/signature checks after publication.

18. Add prevention to the incident closure checklist

  • Use an approved credential helper/SSO instead of embedding secrets in files/URLs.
  • Add local/CI/server secret detection appropriate to the organization.
  • Protect release/signing keys and map signer identities to policy.
  • Keep repository ownership and safe.directory exceptions narrow.
  • Enable inbound object-integrity checks where cost/threat model justify them.
  • Train developers to rotate first and preserve evidence before destructive cleanup.

19. Verification checklist

  • The repository and signing environment were disposable and used only fake secret material.
  • Unsigned and signed objects were distinguished by verification commands.
  • The fake marker was absent from the current snapshot but present in older reachable history before rewrite.
  • Credential rotation/revocation was simulated before rewriting.
  • Refs, reflog, fsck output, graph, and a controlled bundle were preserved.
  • An unreachable commit was interpreted as reachability evidence rather than corruption.
  • The rewrite path used git-filter-repo sensitive-data mode, not filter-branch.
  • Reachable rewritten history no longer contained the fake marker.
  • fsck passed after the rewrite.
  • Old signatures were not misrepresented as surviving the rewrite; a new sanitized tag was signed/verified when backend availability permitted.
  • The publication plan addressed force coordination, protected refs, caches, forks, mirrors, and re-cloning.

20. Cleanup

The checkpoint directory contains deliberately contaminated pre-rewrite evidence and the ephemeral training key. Confirm you are deleting only the disposable lab.
cd ../..
pwd
rm -rf git-security-checkpoint

PowerShell equivalent: Set-Location ../..; Remove-Item -Recurse -Force git-security-checkpoint.

21. Knowledge check

Question 1. Why must a real credential be revoked before history cleanup?

Question 2. Why did descendant commit IDs change after replacing one historical string?

Question 3. Why can an unreachable commit appear in a healthy repository?

Question 4. What happened to signatures associated with rewritten commits/tags?

Question 5. A teammate has an old contaminated clone after the server rewrite. What is the risk?

22. What Chapter 21 adds to a production Git operating model

You can now separate object integrity from signer authenticity, identity trust, authorization, credential secrecy, repository ownership trust, and history reachability. The resulting incident model is evidence-first: rotate credentials, preserve state, use the current rewrite tool carefully, coordinate every copy, then establish new provenance on sanitized history.

23. Chapter checkpoint summary

A trustworthy repository is not defined by one green check. It needs valid objects, explicit signer/identity policy where signatures are used, correct repository ownership, protected credentials, controlled history remediation, and clear evidence that the sanitized state is what delivery systems will consume.

Next chapter

Commit-Graphs, Multi-Pack Indexes, Maintenance, Garbage Collection, and Performance

Chapter 22 builds directly on this chapter's recovery caution by explaining object retention, packfiles, commit graphs, maintenance, and why aggressive pruning can trade performance for lost recovery opportunities.

Authoritative references

 Git signature formats
 git-fsck
 filter-branch warning
 git-filter-repo

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.