Status: NOT DONE. Written 2026-10-12; run it in a quiet window (not 22 to 25 October; the plan recommends from 26 October).
Owner: michael.hay@mediumroast.io
Why: earlier commit messages (and possibly older file versions) mention the names of the lab’s machines and a private address. The working tree is clean and guarded
(scripts/check_hygiene.py, docs/plans/v4-documentation-update.md DP2), but anyone can still read the history. python3 scripts/check_hygiene.py --messages lists the commit
messages with findings; with a private deny-list (below) it also finds the machine names.
This rewrites history. Every clone, fork and open branch is affected, and commit hashes change. Nothing here is reversible once force-pushed except from the backup of step 1.
~/company_dns-private/denylist (one term per line, # comments) with the machine names and any other terms. A term may use * for “any run of letters, digits, dots and dashes” (10.20.30.* for every address in a network, *.corp.example for every host under a domain), and a line starting with re: is a regular expression (re:svc(42)?user); scripts/check_hygiene.py explains the format. It must never be committed. Also make
~/company_dns-private/replacements.txt for the rewrite, one rule per line in old==>new form, for example <name>==><build-node> and the private address ==><private-address>.git-filter-repo (brew install git-filter-repo, or from its repository). Check git filter-repo --version.git clone --mirror https://github.com/miha42-github/company_dns.git ~/company_dns-private/company_dns-backup.git
Keep it until the rewrite has been verified and a month has passed.
In a fresh clone (never your working checkout):
git clone https://github.com/miha42-github/company_dns.git company_dns-rewrite && cd company_dns-rewrite
HYGIENE_DENYLIST=~/company_dns-private/denylist python3 scripts/check_hygiene.py --messages # the messages
HYGIENE_DENYLIST=~/company_dns-private/denylist python3 scripts/check_hygiene.py --history # every line ever added to a file, with the same list (add --verbose for one line per finding)
Also run a secret scanner over the whole history (for example gitleaks detect --source . --log-opts="--all") and record what it finds; a found secret must be rotated, not just removed.
git filter-repo --replace-text ~/company_dns-private/replacements.txt --replace-message ~/company_dns-private/replacements.txt
git filter-repo removes the origin remote on purpose. Save the old-to-new commit map it writes (.git/filter-repo/commit-map) outside the repository: plans, the build log (v4/.build-log) and image labels quote old hashes.
HYGIENE_DENYLIST=~/company_dns-private/denylist python3 scripts/check_hygiene.py --messages
HYGIENE_DENYLIST=~/company_dns-private/denylist python3 scripts/check_hygiene.py --history
python3 scripts/check_hygiene.py
cd v4 && cargo test --workspace # the code still builds and passes
Everything must come back clean. Compare file contents of HEAD with the backup’s HEAD (git diff between the two checkouts should show only the replaced text).
git remote add origin https://github.com/miha42-github/company_dns.git
git push --force --all origin
git push --force --tags origin
If branch protection blocks the force-push, lift it for the push only, then restore it. GitHub keeps the old commits reachable by hash and in pull-request views for a while: open a support request asking GitHub to remove cached views and run garbage collection if the old messages must disappear, and delete the old pull-request refs if possible.
docs/ where they matter (the staging build tags name a commit: record the mapping).docs/plans/v4-documentation-update.md (DP2) and mark this runbook done.