You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(guardrails): deny a guard row that exits 0 with no verdict under --fail-closed #8996
#7667 was filed to stop a guardrails fail-open: on Windows, a crashing guard row printed its deny and exited 0, so the tool call went ahead. #7923, #8563 and #8674 fixed the cases #7667 described. One case is still open. If a run-guards row crashes on Windows and ends as plain exit 0 with no output, exec-bash --fail-closed cannot tell it from a clean pass. Its low-byte-zero decode only covers codes ≥0x100 (plugins/guardrails/hooks/lib/exec-bash.mjs:502-509). In a security guard, that is the same fail-open #7667 set out to stop.
Fix direction
Have run-guards write a verdict marker on every completed run (allow or deny). Make exec-bash --fail-closed deny when a guard row exits 0 without that marker. #7681's rebrief covers the same marker idea, so build this with #7681 or fold it into it.
Acceptance criteria
A guard row that exits 0 with no verdict marker is denied under --fail-closed.
A row that completes normally still passes, on Linux and on Windows Git Bash.
The PR's CI runs the exec-bash and run-guards suites, and they pass on both OS lanes.
Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.
To hold this issue again, add needs-human (or status: needs-decision) and say why in a comment.
The work-resolve-issue run that agent-ready started failed or was cancelled before it reported, or it stopped or the token broker refused it because its workflow files differ from main's. work-unblock removed and added agent-ready back to start a fresh run on main's workflow files. If this run ends the same way, it re-fires the issue again, waiting longer each time.
The token broker refused the work-resolve-issue run that agent-ready started because the lanes kill switch was on, so it did no work. work-unblock removed and added agent-ready back to start a fresh run. A kill-switch refusal is no fault in this issue or the lanes, so it never counts against later re-fires; after limits.limit-stops-per-issue of them since a person last added agent-ready or a run last reported, work-unblock waits longer before each one, up to 24 hours.
The work-resolve-issue lane did not start this issue: it needs a person to make it clearer first.
Why, in the run's own words:
Open PR #10120 (for #7681, labeled needs-human) already builds this exact fix in the same files: lib/exec-bash.mjs and its 24 vendored copies, plugins/guardrails/hooks/run-guards.sh, hooks.json, and the exec-bash and run-guards suites. In that PR, run-guards writes a verdict marker to a launcher-made temp file (EXEC_BASH_VERDICT_FILE), and a new per-row --require-verdict flag, passed on all five --fail-closed rows, denies an exit 0 that has no marker. This issue says to build with #7681 or fold into it, and #7681's recorded decision says a human builds or merges it because it is structural. A second implementation from this lane would conflict with #10120 file for file. A person needs to decide: (1) fold #8996 into #10120 (add Closes #8996 there, or close #8996 as covered by it), or (2) keep #8996 as separate work, and if so, say what it should add beyond #10120. One example: making --fail-closed alone require the marker. #10120 makes the marker opt-in through --require-verdict, and this issue's first acceptance criterion says 'under --fail-closed'.
What the run says it did not do:
No implementation, review, build or test: this run pushed back before any edit, because the fix is already in flight in PR #10120.
The PR CI exec-bash and run-guards suites on both OS lanes (acceptance criterion 3) were not run: no PR was opened.
Closing: met on main by #10120 (merged 2026-10-27T02:35:29Z, #10120).
A guard row that exits 0 with no verdict marker is denied under --fail-closed: all five --fail-closed rows in plugins/guardrails/hooks/hooks.json (lines 45, 65, 84, 102, 120) pass --require-verdict; the launcher exits 2 when the marker is missing (plugins/guardrails/hooks/exec-bash.test.sh:115-118).
Addendum: a structural test guards the pairing, so a future fail-closed row cannot fail open silently. plugins/guardrails/hooks/exec-bash.test.sh:205-210 fails unless every guard row in hooks.json passes --fail-closed and then --require-verdict, and :216 pins the five dispatcher rows.
Activity
kyle-sexton commentedon Oct 25, 2026
Released for re-triage under the owner's 2026-10-24 rule: an issue stops for a person only for an intent or vision question, a security call, a host or attended run, or spend outside prepaid credit. The hold label came off and intake triage runs again now; it re-applies a hold, with a numbered question, when one of those applies.
To hold this issue again, add
needs-human(orstatus: needs-decision) and say why in a comment.melodic-automation-lanes commentedon Oct 26, 2026
The work-resolve-issue run that
agent-readystarted failed or was cancelled before it reported, or it stopped or the token broker refused it because its workflow files differ from main's. work-unblock removed and addedagent-readyback to start a fresh run on main's workflow files. If this run ends the same way, it re-fires the issue again, waiting longer each time.melodic-automation-lanes commentedon Oct 26, 2026
The token broker refused the work-resolve-issue run that
agent-readystarted because the lanes kill switch was on, so it did no work. work-unblock removed and addedagent-readyback to start a fresh run. A kill-switch refusal is no fault in this issue or the lanes, so it never counts against later re-fires; after limits.limit-stops-per-issue of them since a person last addedagent-readyor a run last reported, work-unblock waits longer before each one, up to 24 hours.melodic-automation-lanes commentedon Oct 26, 2026
The work-resolve-issue lane did not start this issue: it needs a person to make it clearer first.
Why, in the run's own words:
What the run says it did not do:
Run: https://github.com/melodic-software/claude-code-plugins/actions/runs/40390864338
To retry, answer the question here, remove
needs-humanand addagent-readyagain.kyle-sexton commentedon Oct 27, 2026
Closing: met on main by #10120 (merged 2026-10-27T02:35:29Z, #10120).
--fail-closed: all five--fail-closedrows inplugins/guardrails/hooks/hooks.json(lines 45, 65, 84, 102, 120) pass--require-verdict; the launcher exits 2 when the marker is missing (plugins/guardrails/hooks/exec-bash.test.sh:115-118).run-guards.shwrites the marker at each deliberate exit;test-bashandtest-windows-guards/test-windows-hooks/test-windows-libpassed on feat(guardrails): deny a blocking hook row whose dispatcher exits 0 without a verdict #10120.The per-row flag rather than an implicit
--fail-closedbehavior meets criterion 1, since every fail-closed row carries it.kyle-sexton commentedon Oct 27, 2026
Addendum: a structural test guards the pairing, so a future fail-closed row cannot fail open silently.
plugins/guardrails/hooks/exec-bash.test.sh:205-210fails unless every guard row inhooks.jsonpasses--fail-closedand then--require-verdict, and:216pins the five dispatcher rows.