Development record
The no-verify blockers miss the same bypass spelled as configuration: a commit or push that points core.hooksPath elsewhere for that one command, through -c, --config-env or the GIT_CONFIG environment, skips the repository hooks exactly as the no-verify flag does, and the matcher steps the -c value over unread. Found by review-guard finding 6 (pre-existing).
issueresolvedminoriss-2609251640464212
The no-verify blockers miss the same bypass spelled as configuration: a commit or push that points core.hooksPath elsewhere for that one command, through -c, --config-env or the GIT_CONFIG environment, skips the repository hooks exactly as the no-verify flag does, and the matcher steps the -c value over unread. Found by review-guard finding 6 (pre-existing).
Grounds
- pursued: every command-line spelling of a hooks-path override on commit or push blocks under the no-verify entries, while the same override on other subcommands and git config of the key stay allowed; an allow of an override spelling, or a block of status or log with it, would show it wrong
Frontmatter
| id | iss-2609251640464212 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2609251640464212-the-no-verify-blockers-miss-the-same.md
open on GitHub ↗ · commit history ↗
mentions1
- dcn-26092500000000142026-09-25 — The shell guard's unknown-word reading and the allows it deliberately keeps (fix round 2 of lane guard, run A, closing review2-guard). What a command substitution prints is not in the command line, so the tokenizer marks where it goes and a word holding one is an unknown word (`internal/core/guard/unknown.go`), failing closed in every role it could play: led by a dash it is every flag its known text can still become, after a value flag it is that flag's value, and as an operand it is one operand of unknown value. Four allows stay, each named so it is not mistaken for a miss. (1) A word that is WHOLLY a substitution is read as an operand, never as a flag: that is how an everyday command spells its commit message and its branch (`git commit -m "$(cat msg)"`, `git push -u origin "$(git branch --show-current)"`), and reading it as every flag would refuse both, so `git push $(printf -- --force) origin main` is not seen. (2) An operand's `+` refspec prefix is read from its known text only, for the same reason: `git push origin $(echo +main:main)` is not seen. (3) A commit or push after `git config core.hooksPath <dir>` in the same line is allowed: the guard reads configuration a command carries for itself (`-c`, `--config-env`, `GIT_CONFIG_*`), not configuration an earlier command writes to a file, and refusing every `git config core.hooksPath` would refuse the ordinary one-time hook setup a repository documents; the one-command spellings block (iss-2609251640464212). (4) Parameter expansions (`--$X`) and a substitution in command position are not yet unknown words; that is iss-2609251824244354, deferred with its reason. Two over-blocks are accepted in the other direction: a short flag's attached value holding a substitution (`git commit -m"$(cat msg)"`) reads as every short flag, because the guard does not know which short options take a value; and `… | xargs bash` reads as a shell reading the pipe, though xargs hands it arguments.