Skip to content

Commit 4dc6f28

Browse files
committed
Prevent the nested-repo accident, not just detect it; control the CSV check
Two corrections from an adversarial review of the previous commit. Both hold. **The CI check fires too late.** It runs `on: push`, so a nested private clone swept in by `git add -A` would already be on GitHub when the job goes red, and deleting the branch would not remove it -- GitHub keeps `refs/pull/N/head` permanently, which is why a sibling repository had to be deleted and recreated rather than force-pushed. Detection after publication is not prevention. Calling the previous commit a structural fix was wrong; it was a structural alarm. `tools/pre-commit` is the half that prevents, with install instructions and its own negative control in the header. `.git/hooks` is per-clone and not committed, so the hook ships as a file to copy and CI remains the backstop for anyone who has not installed it. **The byte-identity check had no negative control.** It re-runs the extractor and requires `data/labels.csv` to be unchanged -- which is trivially true if the extractor were reading the CSV rather than the Markdown. The check would then be green forever and catch nothing, the same vacuity as a proof whose hypothesis is its conclusion. It now mutates a label in the Markdown source and requires the check to fail, then restores and requires it to pass. Both controls run, in both directions, before this commit: mutating bandit-classification.md moves labels.csv and restoring it restores the file byte-for-byte; the hook refuses a commit with a planted nested repository and allows one without it. The review also asked whether the accident happened in the tree the gate covers. It did -- the private clone was inside this repository's worktree. That was never the weak point; the timing was.
1 parent 964cff7 commit 4dc6f28

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

tools/pre-commit

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/sh
2+
# Refuse a commit while a nested git repository is in the worktree.
3+
#
4+
# WHY THIS EXISTS AND WHY CI IS NOT ENOUGH
5+
# 2026-08-07: a clone of a PRIVATE repository sat in this worktree during an
6+
# edit. `git add -A` would have committed it, and its history names an
7+
# organisation under coordinated disclosure. It was caught by reading
8+
# `git status` before staging -- attention, not a control.
9+
#
10+
# The reproducibility workflow also checks for nested repositories, but it
11+
# runs `on: push`. By the time it goes red the objects are already on
12+
# GitHub, and deleting a branch does not remove them: GitHub keeps
13+
# `refs/pull/N/head` permanently, which is why the WarmLogic staging repo had
14+
# to be deleted and recreated rather than force-pushed. Detection after
15+
# publication is not prevention. This hook is the half that prevents.
16+
#
17+
# INSTALL (per clone -- .git/hooks is not committed)
18+
# cp tools/pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
19+
#
20+
# NEGATIVE CONTROL -- run both before trusting it
21+
# 1. mkdir -p x/.git && git commit --allow-empty -m t -> expect REFUSED
22+
# 2. rm -rf x && git commit --allow-empty -m t -> expect a commit
23+
# A gate that has only been seen to allow has not been tested.
24+
#
25+
# `--no-verify` bypasses this, deliberately: the failure being prevented is the
26+
# accidental one.
27+
28+
set -eu
29+
30+
nested=$(find . -mindepth 2 -name .git -not -path './.git/*' -print 2>/dev/null || true)
31+
if [ -n "$nested" ]; then
32+
printf '%s\n' \
33+
'REFUSED: a nested git repository is in this worktree.' \
34+
'' \
35+
"$nested" \
36+
'' \
37+
'A clone left here can be swept in by `git add -A`. If it is a clone of a' \
38+
'private repository, that publishes it -- and the objects survive a later' \
39+
'branch delete via refs/pull/N/head.' \
40+
'' \
41+
'Move it out of the worktree, or commit explicit paths with --no-verify if' \
42+
'you genuinely mean to keep it here.' >&2
43+
exit 1
44+
fi

0 commit comments

Comments
 (0)