Skip to content

fix(hooks): false fail-closed H-09b block on semicolon-bearing commit messages#169

Merged
SUaDtL merged 4 commits into
mainfrom
fix/pre-bash-heredoc-args
Jul 2, 2026
Merged

fix(hooks): false fail-closed H-09b block on semicolon-bearing commit messages#169
SUaDtL merged 4 commits into
mainfrom
fix/pre-bash-heredoc-args

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

What

Fixes the "flaky" H-09b commit-gate failure that blocked 5 of 6 commit attempts on 2026-07-01. It was never timing: COMMIT_RE's args capture ([^|;&]*) truncated at the first ; inside the commit message body (heredoc or quoted -m). The unterminated $(cat <<'EOF' fragment defeated the heredoc stripper, message words leaked into the pathspec parse, and the token /ca:checkpoint) made git diff HEAD -- ... fatal ("outside repository") — added_lines returned None and H-09b failed closed. Deterministic per message shape; reproduced offline from the failing session's transcript, byte for byte.

Fix (no gate weakening — correctness over velocity, hierarchy L2)

  1. Heredoc bodies stripped from the whole command before matching COMMIT_RE/PUSH_RE/ADD_RE, with the raw command kept as a fallback matcher so a heredoc fed to a shell (bash <<EOF ... EOF) is still guarded. Detection is a union, never a substitution.
  2. Quote-aware args capture — quoted strings are consumed whole; the capture still stops at unquoted |/;/&, so && git push --force is still independently caught.
  3. Fail-closed block messages now carry git's actual stderr — the original block said only "git unavailable or timed out", which cost a session of root-causing in the wrong direction.
  4. project_root() trusts CLAUDE_PROJECT_DIR first (the harness's authoritative signal; also one git spawn saved per hook invocation). All hook-spawning test harnesses now pin/strip the variable so fixtures stay hermetic.

Verification

  • 592-test unittest suite, guard-logic matrix (102 asserts), migration backstop (31), pre-read + preview harnesses: all green.
  • 7 new regression tests covering: heredoc-in-command-substitution with ;, -F - heredoc with ;, quoted -m "a; b", git -C mentioned in a message, commit && push --force still blocked, heredoc tail pathspec still scanned, shell-fed heredoc commit still guarded.
  • The live installed hook (2.6.1 cache) was patched identically and three real commits were landed through it on this branch, each with a deliberately hostile message (;, |, &, $(cat <<'EOF', git -C, /ca:checkpoint)) — the exact shapes that failed last night.
  • auth-crypto-reviewer: PASS (0 CRITICAL/HIGH; 2 LOW residual-risk notes — env-first root trust, and -C inside a shell-fed heredoc body no longer steering the H-01 cwd — both consistent with the documented lexical-guard posture).

Closes the root cause behind the 2026-07-01 SECURITY-OVERRIDE log entry.

https://claude.ai/code/session_01PVTCDji6bEuf9SifQ8tfsa

SUaDtL added 4 commits July 1, 2026 22:03
The harness's own signal is authoritative; a hook subprocess is not
guaranteed to start inside the project (/ca:doctor, /ca:preview run
elsewhere too), and rev-parse from a foreign cwd can resolve to the
plugin's marketplace clone. Env-first is also cheaper; one git spawn
saved per hook invocation.

Every test harness that spawns hooks into fixture repos now pins or
strips the variable — a value leaking in from a live Claude session
would point every guard at the developer's real repo, not the fixture.
pre-bash's COMMIT_RE captured args with [^|;&]*, which stops at the
first `;`, `|`, or `&` even inside a quoted -m string or a heredoc
body. A commit message containing `diff-scoped; nothing` truncated
there; the unterminated `$(cat <<'EOF'` fragment defeated the heredoc
stripper, message words leaked into the pathspec parse, and a token
like `/ca:checkpoint)` made `git diff HEAD -- ...` fatal ("outside
repository") — so H-09b failed CLOSED on a clean, already-reviewed
commit (the 2026-07-01 "flaky hook"; it was deterministic per message
shape, not timing).

Three-part fix, no gate weakening: (1) heredoc bodies are stripped
from the whole command before matching, with the raw command kept as
a fallback matcher so a heredoc fed TO a shell (`bash <<EOF`) is
still guarded; (2) the args capture is quote-aware, consuming quoted
strings whole while still stopping at unquoted separators; (3) the
fail-closed block message now carries git's actual stderr, so a
future read failure is diagnosable in one look.

CHANGELOG: Fix a false fail-closed H-09b/H-14 block on commits whose
message body contains `;`, `|`, `&`, or a `git -C` mention (heredoc
and quoted -m forms); block messages now include the underlying git
error.
Payload change (hooks fix) requires the bump; the overrides.log line
is this session's /ca:dev entry, committed per the append-only
audit-trail rule (ORCHESTRATOR §7).
@SUaDtL
SUaDtL merged commit 8bd907d into main Jul 2, 2026
23 checks passed
@SUaDtL
SUaDtL deleted the fix/pre-bash-heredoc-args branch July 24, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant