Skip to content

v3.37.0

Choose a tag to compare

@zerocodefast zerocodefast released this 09 Oct 15:54
3efd6a6

Guard 3.37.0 is a stable release cut from 3efd6a6.
36 commits • 35 merged pull requests • 8 contributors since Guard 3.36.1.

Features

  • gauntlet: Run the catalog through Claude Code, Codex and Cursor (#3818)
  • guard: Add agi-memory command safety extension (#2921)
  • extension: Add Formicx agent command safety extension (#2914)
  • guard: Add rungs command classification extension (#2818)
  • guard: Review Dispat release starts with an opt-in extension (#2813)
  • extensions: Add pyrig command protection (#3674)
  • guard: List detected CLIs and add a Cloudflare Wrangler profile (#3795)
  • extensions: Add publisher listing for mcp.mail-server (#3805)
  • extensions: Require approval for mcp-mail-server permanent deletion (#3278)
  • business: Classify business operations and add Drive export (#3798)
    • BusinessOperationV1::action_class() maps every operation to one of read, draft, send, share, export, update, delete or admin. The class comes from the operation alone. A producer cannot supply it, and…
    • drive_export is a Google Drive operation. Its audience must be private or unknown. A public or named export is Inconsistent, because handing a file to someone else is drive_share.
    • The policy schema (both copies) accepts drive_export, and a selector may now list up to 12 operations. The review summary, the review queue and the dashboard label it "Export Drive files".
  • guard: Detect package-runner CLIs such as npx wrangler (#3792)

Fixes

  • runtime: Name the business context floor for shell-wrapped Workspace CLIs (#3826)
  • guard: Repair extension-control catalog bound and error type (#3817)
    • ExtensionControlApiError was a @dataclass(frozen=True, slots=True) exception. contextlib assigns __traceback__ on raise, so super() inside the slots class raised TypeError: super(type, obj) and froze.…
    • Parallelized the coverage critical path: shards run xdist -n 3 --dist=loadfile --max-worker-restart 0; Rust nextest --test-threads 4. pytest_duration_report writes only from the controller so workers cannot…
    • Serialized the collection-time git diff/fetch in extension_freshness across xdist workers with an fcntl lock (concurrent module imports raced .git).
  • package-shims: Judge the dashboard intercept test by shell-profile PATH (#3827)
    • The dashboard Package managers -> Test action now judges PATH activation with package_shim_dashboard_status, the same shell-profile projection the status cards use. The resident daemon never loads shell profiles…
    • probe_package_shim_intercepts gains a project_shell_profile option. The CLI and runtime callers keep probing against the caller's real PATH.
    • New hol-guard package-shims test [--manager <name>] --json subcommand runs the intercept proof from a shell, behind the same approval gate as the dashboard action.
  • guard: Load Cursor hooks by replacing unsupported beforeWriteFile (#3825)
    • New hook entry. Guard now installs a preToolUse entry with failClosed: true. Its matcher is ^(Write|Edit|StrReplace|MultiEdit|Delete)$, so the entry only fires for file mutation tools. Shell, MCP, and read…
    • Review decisions become deny. Cursor only stops a preToolUse call when the answer is deny; an ask lets the tool run. Guard therefore answers review decisions for these tools with deny, the same way it…
    • Reinstall cleans up the old entry. Reinstalling or upgrading removes the beforeWriteFile entries that earlier Guard releases wrote, so Cursor loads the file again. Hooks written by other tools under that event…
  • sync: Scrub CLI credential arguments from synced receipt commands (#3824)
    • When a receipt had no full action envelope, envelopeRedacted was forwarded as stored, command included, even if the current sync level is full.
    • raw_command_text and the encoded receipt command were sanitized with redact_sensitive_text only. Cloud review events already use the stronger scrubber, which also removes those credential arguments.
  • guard: Let routine Codex apply_patch edits pass native review (#3821)
    • Parse the patch with the same grammar as Codex's own apply_patch parser, including where Codex trims a line before matching a hunk header. Every header Codex would act on is checked. Any line Codex would not accept…
    • Grant native_exact_safe_file_write only when every target passes the existing workspace write check (workspace or registered worktree, sensitive-path, hidden-path, hard-link and autostart checks).
    • Also refuse targets that are agent instruction files (AGENTS.md, CLAUDE.md and similar) or sit under agent or VCS metadata directories (.codex, .claude, .cursor, .agents, .git and others). Both the name…
  • runtime: Retire the managed resident when its Guard home is deleted (#3822)
  • codex: Stop holding ordinary Codex Git reads and skill reads, and explain authority repair (#3808)
    • Codex Git reads.** The Codex hook bridge did not forward its execution environment to the daemon. The Claude Code, OpenCode, and bounded CLI bridges already do. Without it, the native Git-helper check treated the…
  • daemon: Read camelCase toolInput from ZCode, Devin and Grok hooks (#3820)
    • native reviews never offered Always allow exact action; only "Allow just this once" appeared, and raw_command_text was empty
    • saved exact-action allow/block decisions were never looked up
    • custom extension rules (for example blocking wrangler delete) were ignored on the daemon path
  • daemon: Retire a superseded same-install daemon after a native-only upgrade (#3815)
    • A daemon left running across an in-place upgrade that changes only the native runtime is now retired instead of staying wedged on native_policy_not_ready.
    • The runtime manifest is part of the daemon runtime fingerprint, so a native-only upgrade changes the install's identity.
    • The daemon pins its fingerprint when it is constructed. A previous-generation process can no longer advertise the replacement install's identity by computing it lazily after the upgrade.
  • supply-chain: Restore paid first-time protection without approval loops (#3814)
    • Let paid Cloud access restore package protection before any shims are installed. Keep local-only recovery limited to tools already protected.
    • Check repair eligibility before asking for local approval. Refresh access before a repair and offer an access check instead of repeating password requests after a Cloud denial.
    • Show each recovery error once and use a single restore action with issue details collapsed.
  • uninstall: Rewrite group-writable user files and run self-uninstall from the desktop core (#3813)
    • Runtime transitions clear group and world write bits (mode & ~0o022) from the mode they publish when they rewrite an existing unpinned user file, so shell profiles and harness configs at 0664 (umask 0002) or 0666 no…
    • Still rejected: setuid/setgid/sticky bits, group- or world-writable modes requested for new files, and group-writable modes on pinned artifacts (expected_digest / artifact_identity).
    • file_mode_invalid now names the offending path.
  • dashboard: Keep extension inventory rendering when a launch kind is unknown (#3811)
    • mcp_launch.kind values the dashboard does not recognize now normalize to an unsupported launch for that entry. Previously one unknown value threw and the whole Extensions inventory failed to load when the daemon…
    • The MCP server defaults card shows an "update Guard" note for unsupported launches and offers no launch details for them.
    • Unknown icon.kind falls back to none, and an unknown surface drops only the MCP fields for that entry. Policy fields (trust_class, source, activation, modes, tool states) still reject unknown values.
  • runtime: Recover a stale resident-update marker and report the real native failure (#3812)
    • hol-guard daemon repair re-points a resident-update.v1.lock marker left behind by an interrupted update at the digest of the runtime Guard admits; when no compatible runtime is admitted it reports unavailable…
    • Marker writes no longer truncate first. The new value overwrites the old one in place, the file shrinks only afterwards, and a failed write (for example ENOSPC) restores the previous bytes. The file stays the flock…
    • native_mcp_descriptor_digest_unavailable now carries the transport's reason code, such as native_resident_runtime_identity_mismatch. The CLI prints native_*_unavailable errors as runtime errors instead of usage…
  • runtime: Require business context for local, Windows and launcher Google CLIs (#3799)
    • Windows .cmd shims (gws.cmd, GOG.CMD), which both extensions declare.
    • Package launchers: npx gws, npx -y @scope/gws@1.2.0, pnpm exec gog, bunx gws. The parser records the launcher as the executable.
    • Workspace-local paths (./gws, ./node_modules/.bin/gws). These already resolved by basename; the new test now pins them.
  • contracts: Raise managed-controls catalog payload cap to 8MB (#3816)
    • The daemon's extension-control catalog() response serializes the entire built-in command registry and is bounded by MAX_CATALOG_PAYLOAD_BYTES (1MB in managed-controls/v1).
    • Main is currently at 987,939 / 1,000,000 bytes across 127 extensions — ~12KB of headroom. Any merged extension larger than ~12KB now trips service.catalog() into 413 catalog_payload_limit_exceeded, and the…
    • Raising the shared bound to 8MB gives ~900 extensions of headroom at the current ~7.8KB average wire size, applied consistently to: the runtime constant, contracts/managed-controls/v1/limits.json, the catalog…
  • guard: Recognize npx wrangler as a CLI and parse yargs help rows (#3809)
    • npx wrangler paste was rejected. Recognize treats any package-launcher command as a possible MCP server. The stdio probe of npx wrangler failed, and the command was rejected with already_built_in. A package…
    • Wrangler help produced junk command ids. Wrangler prints yargs-style help, where every row starts with the program and parent path (wrangler d1 list List D1 databases). The parser took the first token, so it…
  • codex: Read app inventory from native daemons and bound tool summaries (9ed4ba2)
  • runtime: Refuse multi-record business dispatch (#3800)

Documentation

  • guard: List business app compatibility by command and mode (#3803)

Tests

  • policy: Add a canonical hash vector for business selectors (#3830)
  • gauntlet: Cover Google Workspace CLI calls under the business policy (#3802)

CI & automation

  • Report Google Discovery changes for reviewed gws methods (#3804)

Internal

  • release: 3.37.0 (#3801)
  • extensions: Publish missing command descriptors and resync stale fixtures (#3796)

Install

Install this release:

uv tool install "hol-guard[cisco]==3.37.0"

Full changelog: v3.36.1...v3.37.0

Thanks @zerocodefast, @kdbhalala, @Abbilaash, @ThroughTheWind, @yohimik, ZCF, @Winipedia, @yunfeizhu!

Package publication and Desktop update availability are separate. Desktop updates are ready when the signed Core assets and update manifests appear below; macOS feed status shows signing and verification progress.