Skip to content

[patch] MLAI-1310 - Reapply the governed-hook pipeline fix reverted for the release - #91

Open
shmuelqwak wants to merge 1 commit into
mainfrom
bugfix/MLAI-1310-reapply-cursor-hook-payload-pipeline
Open

[patch] MLAI-1310 - Reapply the governed-hook pipeline fix reverted for the release#91
shmuelqwak wants to merge 1 commit into
mainfrom
bugfix/MLAI-1310-reapply-cursor-hook-payload-pipeline

Conversation

@shmuelqwak

Copy link
Copy Markdown
Collaborator

Reapplies #86, which merged as b2eba5f and was reverted by #87 for release scheduling — not for anything wrong with the change. Fixes MLAI-1310.

This is a revert of that revert, so the restored content is byte-identical to what was already reviewed and approved. The only edit on top is the version: main has since moved to 0.6.7, so both manifests go to 0.6.8.

What is broken on main right now

Cursor skill governance is non-functional again, exactly as before #86. Cursor concatenates the hook command onto a pipeline it builds and leaves the hook's own fd 0 as /dev/null:

printf %s '<b64>' | base64 -d | _JFAG_NOW=$(date +%s 2>/dev/null); npm_config_… npx … --enforce-skill

That top-level ; terminates the pipeline. base64 -d pipes into a bare assignment that reads nothing, and npx runs as a separate command inheriting the shell's stdin — /dev/null. agent-guard reads 0 bytes, cannot classify the event, and renders its no-opinion allow, which is byte-identical to "this prompt was not a skill invocation". Both governed surfaces allow every skill, silently, at exit 0.

Verified on main as it stands:

beforeSubmitPrompt   top-level ';': True
preToolUse           top-level ';': True

The fix, unchanged from #86

JF_AGENT_GUARD_ENFORCE_DEADLINE="$(_JFAG_NOW=$(date +%s 2>/dev/null); echo ${_JFAG_NOW:+$((_JFAG_NOW + 25))})" npx --yes …

Computing the deadline inside a command substitution scopes the ; and keeps the hook one simple command, so it stays the tail of Cursor's pipeline. The defensive clock read is preserved, not reverted — an unreadable clock still yields an empty deadline, which agent-guard ignores in favour of its own budget, rather than the 25 (an instant in 1970) that the older inline form produced and that would floor the budget at 500 ms and block every skill.

Verified on top of current main

skill-governance suite 41/41
validate-template pass
unit tests 53 pass, 0 fail (including those added by #89)

And the regression cannot return unnoticed — run against main's current hooks.json, the suite fails 10 ways:

FAIL beforeSubmitPrompt computes the deadline fresh, with no inheritable fallback
FAIL preToolUse computes the deadline fresh, with no inheritable fallback
FAIL no governed command has a top-level ';', '&&' or '||' (it is the tail of Cursor's pipeline)
FAIL the payload survives Cursor's pipeline under every shell Cursor may pick
FAIL beforeSubmitPrompt: forwards stdin verbatim and hands agent-guard the expected argv
FAIL beforeSubmitPrompt: hands agent-guard a deadline in the future, computed at invocation
FAIL beforeSubmitPrompt: with no date(1) on PATH, the deadline degrades to EMPTY and the payload still arrives
FAIL preToolUse: forwards stdin verbatim and hands agent-guard the expected argv
FAIL preToolUse: hands agent-guard a deadline in the future, computed at invocation
FAIL preToolUse: with no date(1) on PATH, the deadline degrades to EMPTY and the payload still arrives

Interaction with what landed meanwhile

AX-2205 - Add SH support (#89) touched neither hooks.json nor scripts/validate-skill-governance.mjs, so this reapply carries no interaction with it. The only merge conflict was the version manifests, resolved to 0.6.8.

Review feedback from #86 is already folded in: the manifest bump, the corrected date(1) sandbox comment, and the behavioural check that executes the empty-deadline degrade rather than asserting it in text.

…elease

Reapplies #86, which merged as b2eba5f and was reverted by #87 for release
scheduling rather than for anything wrong with the change. This is a revert of
that revert, so the restored content is byte-identical to what was reviewed and
approved; the only edit on top is the version, which main has since moved to
0.6.7, so both manifests go to 0.6.8.

Without it Cursor skill governance is non-functional again, exactly as it was
before #86: Cursor concatenates the hook command onto

  printf %s '<b64>' | base64 -d | <command>

and leaves the hook's own fd 0 as /dev/null, so the top-level ';' in
`_JFAG_NOW=$(date +%s 2>/dev/null); … npx …` terminates that pipeline. npx then
runs as a separate command inheriting /dev/null, agent-guard reads 0 bytes,
cannot classify the event, and renders its no-opinion allow — indistinguishable
from "this prompt was not a skill invocation". Both governed surfaces allow every
skill, silently, at exit 0.

Computing the deadline inside a command substitution scopes the ';' and keeps the
hook one simple command, so it stays the tail of Cursor's pipeline, while the
degrade-to-empty behaviour of the defensive clock read is preserved.

Verified on top of current main: the governance suite is 41/41, validate-template
passes, and the 53 unit tests (including those added by #89) pass. Against main's
current hooks.json the suite fails 10 ways, so the regression cannot return
unnoticed.

AX-2205 (#89) touched neither hooks.json nor the validator, so the reapply
carries no interaction with it.
@shmuelqwak
shmuelqwak requested a review from a team as a code owner September 6, 2026 12:03
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