pre-commit-loop-detector: hook runs twice on non-loop failure, capture markers leak to stderr, JSONL repo field unescaped #26
Labels
No labels
blocked:needs-attention
blocked:needs-decision
bug
chore
in-progress
quickfix
security/high
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
AuWoMe/forgeflow#26
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Minor hardening findings in
scripts/hermes/pre-commit-loop-detector.sh(introduced by #23 fix, commit2e07772). Found by post-deploy probe (kanban cardt_5ecf9aa6).Actual behavior
run_commit_with_capture "$@"runsgit commit(line ~165) and discards its captured output, then the wrapper re-runsgit commit "$@"at lines 177-181 before loop detection. A non-loop failure (hook exits 1, no loop signature) therefore executes hooks twice.run_commit_with_captureechoes:::HERMES_COMMIT_CAPTURED_START:::/:::HERMES_COMMIT_CAPTURED_END:::/:::HERMES_COMMIT_RC::<rc>:::to stderr. These are consumed nowhere by the caller (the captured output is discarded) and appear in user-visible stderr.repofield is unescaped.log_fallbackembeds the repo identifier raw into the JSONL line ("repo":"%s"), unlike thecommandfield which is python-escaped. A repo name containing quotes/backslashes would corrupt the log line.Expected behavior
Reproduction steps
git committhrough the wrapper.:::HERMES_COMMIT_CAPTURED_*:::markers appear in stderr.Impact
Low — correctness of the wrapper's happy-path detection is unaffected, but duplicate hook execution can mislead hook authors and the marker leak pollutes output. Follow-on hardening candidate.
Filed by reporter lane from kanban card
t_5ecf9aa6(post-deploy probe of #23).All three findings fixed on main by commit
07599d0:run_commit_with_capturenow tees the first attempt's output to a capture file and the caller uses THAT output for loop detection — the wrapper no longer re-invokesgit commitjust to inspect output, so a plain non-loop failure runs hooks exactly once.:::HERMES_COMMIT_CAPTURED_*:::stderr echoes entirely (the captured output lives in a temp file, not stderr).repofield is now Python-json-escaped (same ascommand) instead of being spliced raw.Added regression test
test_non_loop_failure_runs_hooks_once_no_marker_leakasserting hook count == 1 and no:::HERMES_COMMIT_CAPTUREDin stderr. 9/9 pytest pass.