* fix(#3129): replace bypassed bash regex with token-walk git-cmd.js classifier Root cause: gsd-validate-commit.sh used: if [[ "$CMD" =~ ^git[[:space:]]+commit ]] This regex silently bypasses Conventional Commits enforcement for: git -C /path commit -m ... (working-directory prefix) GIT_AUTHOR_NAME=x git commit (env-var prefix) /usr/bin/git commit -m ... (full-path executable) Fix: introduces hooks/lib/git-cmd.js with isGitSubcommand(cmd, sub) — a token-walk classifier that handles all four forms by: 1. Skipping leading VAR=VALUE env assignments 2. Validating the git executable (basename check for full-path support) 3. Consuming git global options (-C <path>, --git-dir=, -p, etc.) 4. Checking the subcommand token The hook delegates to this classifier via node shell-out. node is already called twice in this hook (config check + JSON parse), so no new runtime dependency. This becomes the single source of truth for all hooks that gate on git subcommands (pre-commit-review-gate, post-push-verify, etc.). Regression test: 27 assertions — tokenize correctness, 12 must-match cases (including all 3 bypass forms), 8 must-not-match cases, 3 source checks. All are real behavioral tests, not string comparisons. Suite: 7035/7035. Closes #3129. * fix(lint+hook+changeset): allow-test-rule, fix HOOK_DIR quote injection, fix changeset pr+typo
This commit is contained in:
@@ -21,8 +21,15 @@ INPUT=$(cat)
|
||||
# Extract command from JSON using Node (handles escaping correctly, no jq needed)
|
||||
CMD=$(echo "$INPUT" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{try{process.stdout.write(JSON.parse(d).tool_input?.command||'')}catch{}})" 2>/dev/null)
|
||||
|
||||
# Only check git commit commands
|
||||
if [[ "$CMD" =~ ^git[[:space:]]+commit ]]; then
|
||||
# Only check git commit commands.
|
||||
# Delegates to hooks/lib/git-cmd.js isGitSubcommand() — the canonical token-walk
|
||||
# classifier that handles env-prefix, -C path, and full-path git invocations.
|
||||
# A naive `^git\s+commit` regex misses all three; this guard fixes that (#3129).
|
||||
HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
if GIT_CMD_LIB="$HOOK_DIR/lib/git-cmd.js" node -e "
|
||||
const {isGitSubcommand}=require(process.env.GIT_CMD_LIB);
|
||||
process.exit(isGitSubcommand(process.argv[1],'commit')?0:1);
|
||||
" "$CMD" 2>/dev/null; then
|
||||
# Extract message from -m flag
|
||||
MSG=""
|
||||
if [[ "$CMD" =~ -m[[:space:]]+\"([^\"]+)\" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user