Skip to content

[patch] MLAI-1333 - Fix skill governance on Windows - #118

Open
nadav-dvir wants to merge 1 commit into
mainfrom
bugfix/MLAI-1333-windows-skill-governance-launcher
Open

nadav-dvir wants to merge 1 commit into
mainfrom
bugfix/MLAI-1333-windows-skill-governance-launcher

Conversation

@nadav-dvir

Copy link
Copy Markdown
Collaborator

Summary

On Windows, the skill-governance hooks never ran: they were POSIX one-liners (${VAR:-…}, $(( ))), and Cursor runs hooks in the platform's default shell, so skills were allowed unchecked. This PR runs them through the shared launcher that JFrog agent hooks now vendors into plugins/jfrog/modules/core/enforce-skill.mjs (synced in #115 and #117). The hook is a single node command with a path relative to the plugin root, like the existing sessionStart hooks.

The launcher sets the same deadline (now + 25s) and fetch bounds, and passes Agent Guard's exit 0 and 2 through. On any other failure it answers {} with exit 0 and writes [jfrog-agent-guard] skill governance did not run (<cause>); this skill was not governed. to stderr, which Cursor keeps in its hook output log.

Changes

  • plugins/jfrog/hooks/hooks.json: beforeSubmitPrompt and preToolUse (Read) run node "./modules/core/enforce-skill.mjs" --client cursor, and preToolUse adds --prefer-offline as before. failClosed: false and the timeouts are unchanged.
  • scripts/validate-skill-governance.mjs:
    • Expect the launcher command with no shell syntax.
    • Check the deadline and fetch bounds on what the stub npx receives.
    • Require {} with exit 0 and the stderr cause on fail-open.
    • Drop the date(1) degrade check, because the clock is now read in node.
    • runHook now runs from the plugin root, which the relative path needs.
  • README: replace the "POSIX shell required" note.
  • Bump to 0.6.20.

MLAI-1310 payload delivery

All of the pipeline checks still pass:

  • every hook command is valid sh;
  • no command has a top-level ;, && or ||;
  • the payload reaches Agent Guard intact through Cursor's printf %s '<b64>' | base64 -d | <command> under sh, bash and zsh.

The launcher reads the payload from its stdin, which is that pipeline.

Not verified here: how Cursor on Windows delivers the payload. The pipeline above is the macOS and Linux path. Before merging, please run one governed skill on a Windows Cursor install and confirm it gets a verdict.

Testing

  • node scripts/validate-skill-governance.mjs: all 38 checks pass.
    • Run against the old hooks.json, 8 checks fail.
  • node scripts/validate-template.mjs passes.
  • node --test plugins/jfrog/scripts/*.test.mjs: 53 pass.

🤖 Generated with Claude Code

- Run beforeSubmitPrompt and preToolUse through the vendored
  ./modules/core/enforce-skill.mjs with --client cursor, so the hook is
  one node command with no POSIX syntax
- Update validate-skill-governance.mjs: assert the launcher command,
  check the fetch bounds, deadline and fail-open on what npx receives,
  and keep the payload-pipeline checks from MLAI-1310
- README: drop the POSIX shell requirement
- Bump the plugin to 0.6.20

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nadav-dvir
nadav-dvir requested review from a team as code owners November 12, 2026 15:24
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