Finding
.githooks/pre-commit builds the staged-file list for every validator with:
target_files=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)
git diff --cached --name-only quotes any path containing non-ASCII bytes,
because core.quotePath defaults to true. The validators then iterate that
list and do [ -f "$file" ] || continue, which is false for the quoted string —
so the file is silently skipped, and CHECKED is never incremented, so the
denominator under-reports too.
A validator that skips what it cannot name reports a pass.
Measured, not inferred
$ git init -q . && printf '// SPDX-License-Identifier: MPL-2.0\n' > 'café.rs' && git add -A
$ git config core.quotePath # unset -> default true
$ git diff --cached --name-only
"caf\303\251.rs"
$ n=$(git diff --cached --name-only | head -1); [ -f "$n" ] && echo FOUND || echo "NOT FOUND"
NOT FOUND
Scope
The list is built in the shared callers, run_validator (.githooks/pre-commit:45)
and run_validator_required (:63), so this is not a validate-spdx.sh bug —
it affects every validator fed by target_files.
| Validator | Uses the list | [ -f ] || continue | Affected |
|---|---|---|---|
| validate-k9.sh | yes | yes | yes |
| validate-spdx.sh | yes | yes | yes |
| validate-spdx-workflows.sh | yes | yes | yes |
| validate-sha-pins.sh | yes | yes | yes |
| validate-permissions.sh | yes | yes | yes |
| validate-bot-directives.sh | yes | yes | yes |
| validate-lint-format.sh | yes | no | passes a non-existent path to a linter |
| validate-codeql.sh | no | — | no |
| validate-gitleaks.sh | no | — | no |
The secret gate is NOT affected, and that is worth stating explicitly:
validate-gitleaks.sh:54 runs gitleaks protect --staged, which reads the
index directly and never sees target_files. A staged secret in a non-ASCII
path is still caught.
Why it is not hypothetical here
The estate already contains a literal-space directory _RSR _SET. The
word-splitting half of this problem was fixed in validate-spdx.sh (the
<<< / IFS= read -r loop, with a comment recording exactly that casualty).
The quoting half was not, and it is the same class of defect: the path the
validator is handed is not the path on disk.
Acceptance criteria
git -c core.quotePath=false diff --cached --name-only in both
run_validator and run_validator_required — fix it at the shared
caller, not in six validators, so a seventh validator cannot reintroduce it.
-z is a real answer: a path that reaches a validator and is not on disk
must be an error, not a continue. The silent skip is what made this
invisible; changing the quoting without changing the skip leaves the next
instance just as silent.
- A regression test under
scripts/tests/ staging a file with a non-ASCII
name and asserting the validator's CHECKED denominator includes it.
⚠ It must fail against the current code — a green suite against both
versions proves nothing.
Found while working #967 / #970. Filed separately rather than widening #961,
which is merged.
Finding
.githooks/pre-commitbuilds the staged-file list for every validator with:target_files=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true)git diff --cached --name-onlyquotes any path containing non-ASCII bytes,because
core.quotePathdefaults totrue. The validators then iterate thatlist and do
[ -f "$file" ] || continue, which is false for the quoted string —so the file is silently skipped, and
CHECKEDis never incremented, so thedenominator under-reports too.
A validator that skips what it cannot name reports a pass.
Measured, not inferred
Scope
The list is built in the shared callers,
run_validator(.githooks/pre-commit:45)and
run_validator_required(:63), so this is not avalidate-spdx.shbug —it affects every validator fed by
target_files.| Validator | Uses the list |
[ -f ] || continue| Affected ||---|---|---|---|
|
validate-k9.sh| yes | yes | yes ||
validate-spdx.sh| yes | yes | yes ||
validate-spdx-workflows.sh| yes | yes | yes ||
validate-sha-pins.sh| yes | yes | yes ||
validate-permissions.sh| yes | yes | yes ||
validate-bot-directives.sh| yes | yes | yes ||
validate-lint-format.sh| yes | no | passes a non-existent path to a linter ||
validate-codeql.sh| no | — | no ||
validate-gitleaks.sh| no | — | no |The secret gate is NOT affected, and that is worth stating explicitly:
validate-gitleaks.sh:54runsgitleaks protect --staged, which reads theindex directly and never sees
target_files. A staged secret in a non-ASCIIpath is still caught.
Why it is not hypothetical here
The estate already contains a literal-space directory
_RSR _SET. Theword-splitting half of this problem was fixed in
validate-spdx.sh(the<<</IFS= read -rloop, with a comment recording exactly that casualty).The quoting half was not, and it is the same class of defect: the path the
validator is handed is not the path on disk.
Acceptance criteria
git -c core.quotePath=false diff --cached --name-onlyin bothrun_validatorandrun_validator_required— fix it at the sharedcaller, not in six validators, so a seventh validator cannot reintroduce it.
-zis a real answer: a path that reaches a validator and is not on diskmust be an error, not a
continue. The silent skip is what made thisinvisible; changing the quoting without changing the skip leaves the next
instance just as silent.
scripts/tests/staging a file with a non-ASCIIname and asserting the validator's
CHECKEDdenominator includes it.⚠ It must fail against the current code — a green suite against both
versions proves nothing.
Found while working #967 / #970. Filed separately rather than widening #961,
which is merged.