[FIX] pre-commit: the size check word-split on paths and skipped them entirely
for file in $(git diff --cached --name-only) is unquoted, so a staged path
containing whitespace split into tokens, every token failed the [ -f ] guard, and
the file was never measured. A 17MB "my big file.dat" passed the 5MB ceiling
without the check ever running — REVIEWED-105's class (a check that passes
because it could not run), in the guard rather than in a declared check.
Now null-delimited (-z / read -d ''), fed by process substitution rather than a
pipe so `exit 1` still refuses the commit from inside the loop body.
Controls, run before committing:
space-in-name 17MB -> REFUSED (the fix; previously committed)
plain 17MB -> REFUSED (unchanged)
small file -> COMMITTED (unchanged)
staged deletion -> COMMITTED, no crash (the [ -f ] guard is intact)
newline+unicode name-> REFUSED (impossible under the old loop)
Narrows nothing and widens nothing: it makes the check do what it already said.
The 5MB ceiling and the LFS advice line are UNTOUCHED — that is the policy
question in PENDING-163, and it is the steward's.
Also files PENDING-163 AMENDMENT 1 (joins, replaces nothing), raised by the jurist
reading the item against REVIEWED-100/105 and verified empirically here:
- CONFIRMED: option (ii) does NOT widen permissions generally. git cat-file -s
reads the staged blob: an LFS-tracked 17MB file stages at 133 bytes, a plain
one stages at 17825792 and is still refused. The item's "widens what may be
committed everywhere" is withdrawn as false. That error is why the fork went
to the steward as a policy question at all.
- ACCEPTED: .gitattributes already is the per-repo versioned declaration that
option (iii) proposed to build. (iii) WITHDRAWN.
- CONFIRMED, and worse than visible from outside: (iii) inverts REVIEWED-100's
polarity, and the parser would refuse an exemption line as malformed.
- The jurist's fourth point does NOT hold — line 46's [ -f "$file" ] guard is
present, so staged deletions never reach wc -c. Flagged by them as inferred,
and it was. But the class they predicted is real, at line 45, by a different
mechanism. The inference was wrong; the instinct was not.
Recommendation changes from "(i) now, (iii) later" to "(ii)". Still the steward's.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NvZAKSf9aqratbqHbU9LK5
This commit is contained in:
co-authored by
Claude Opus 5
parent
171be14ab7
commit
ecee76b862
+13
-3
@@ -42,16 +42,26 @@ if echo "$added_lines" | grep -qE "(console\.log|debugger|binding\.pry|TODO:|FIX
|
||||
fi
|
||||
|
||||
# Check for large files (>5MB) — operates on file size, not diff content
|
||||
for file in $(git diff --cached --name-only); do
|
||||
#
|
||||
# -z / read -d '': the path list MUST be null-delimited. Unquoted $(git diff
|
||||
# --cached --name-only) word-splits, so a staged path containing whitespace broke
|
||||
# into tokens, every token failed the [ -f ] test below, and the file was skipped
|
||||
# ENTIRELY — a 17 MB "my big file.dat" passed this check without it ever running.
|
||||
# That is REVIEWED-105's class again (a check that passes because it could not
|
||||
# run), and it is why the loop is fed by process substitution rather than a pipe:
|
||||
# a pipe would put the body in a subshell where `exit 1` cannot refuse the commit.
|
||||
# Measured 2026-08-26 (PENDING-163 AMENDMENT 1). Narrows nothing, widens nothing —
|
||||
# it makes this check do what it already claimed to do.
|
||||
while IFS= read -r -d '' file; do
|
||||
if [ -f "$file" ]; then
|
||||
size=$(wc -c < "$file")
|
||||
if [ $size -gt 5242880 ]; then
|
||||
if [ "$size" -gt 5242880 ]; then
|
||||
echo -e "${RED}Error: $file is larger than 5MB${NC}"
|
||||
echo "Consider using Git LFS for large files"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done < <(git diff --cached --name-only -z)
|
||||
|
||||
# Check for secrets in ADDED lines only (basic check)
|
||||
if echo "$added_lines" | grep -qE "(password|secret|token|api_key)[[:space:]]*=[[:space:]]*[\"'][^\"']+[\"']"; then
|
||||
|
||||
Reference in New Issue
Block a user