Repository navigation
feat(sidecar): auto-approve list + build e2e (v0.5.1 HGW-W11) - #83
SaulBuilds wants to merge 3 commits into
Conversation
… (HGW-5)
Owner decision 2026-10-15 (HGW (3), D-16 as amended): sandboxed,
offline, project-scoped read and build commands run without a card.
- The list is data: agent-sidecar/policy/auto_approve.toml (compiled
in; CITRATE_HERMES_AUTO_APPROVE=0 turns it off, an absolute path
replaces it). Rules are argv templates (program, subcommands, flags,
value flags with kinds, required flags, operand kind and count). The
shipped list: ls, pwd, cat, head, tail, wc, node <file>, npm run
<script>, npm test, npx tsc, forge build/test, cargo build/test/check
--offline, git init/status/diff/add/commit -m.
- shell_run releases a match without a card only when the session is
untainted, the OS sandbox is enforced, and the folder is inside a
project root; that run may write only the project (not the wider
grant). Network-capable or unlisted commands, or anything outside a
project, still ask. After taint every command asks (HGW-1).
- Each auto run is recorded write-ahead (kind shell.run.auto, actor
agent, HIC-2); if it cannot be recorded it asks instead. Its result
says so (run.approval = {mode: auto, rule, project}); member-approved
runs say {mode: member}.
- agent-loop: ToolOutcome::Vouched. An auto run's output derives from
the project's own files (no network, project-only writes, untainted
session), like a folder-grant file read, so it does not taint; the
worker wire maps it to Ok (fail closed across the process boundary).
- git through shell_run commits as "Hermes <hermes@citrate.invalid>"
(the scratch HOME has no identity; git refused to commit).
- shell_run's description now states the approval semantics and says
to ask, not retry, after a decline.
End to end (real Seatbelt, scratch home, scripted model): create the
project (one card) -> write package.json, build.js and a buggy source ->
git init/add/commit -> npm run build fails -> the model reads
"ReferenceError: greeet is not defined" from the tool result, fixes it
with fs_edit -> build passes -> commit; then untrusted output makes the
next listed command ask, with the taint reason on its card. Negative
checks in the same run: no write outside the project, no network, no
risky git state. Linux (bwrap) runs the same tests; they skip without
a working bwrap unless CITRATE_REQUIRE_BWRAP=1 (the CI lane).
Tests: auto_approve unit (+4), auto_approve_tests (+7), e2e (+1),
taint_tests vouched (+1), shell_run git identity (+1). Workspace:
2285 -> 2299 passed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018wWZZ8GRVU9USh3kKQHsFe
) Aligns HGW-5 with the HGW-W11 issue (#77): - npm run is auto-approved only for the script names build, test, lint and typecheck (new rule field operand_values); any other script asks; - every git run through shell_run gets command-scope config core.hooksPath=/dev/null and core.fsmonitor=false (outranks the repository's own config), so Hermes's git never runs hooks; - GET /shell/auto-approve returns the list in effect (enabled, conditions, rules) for the app's Settings, behind the bearer. Tests: matrix extended; route test (+1); git hooks/fsmonitor off (+1). Workspace: 2302 -> 2304 passed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wWZZ8GRVU9USh3kKQHsFe
BerryManifold
left a comment
There was a problem hiding this comment.
Holding auto-approval pending resolution of the blocking git-state security boundary issue confirmed in the #84 follow-up. The owner-approved command-list scope is understood; the blocker concerns enforcement around command effects. Reproduction details are retained privately under the organization security policy. Please complete the safeguard and add regression coverage before enabling this path.
…pendency updates, #85) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018wWZZ8GRVU9USh3kKQHsFe
BerryManifold
left a comment
There was a problem hiding this comment.
Approval submitted at the owner’s explicit direction. This does not retract or resolve the previously reported git-state cleanup finding; no new verification of a fix is claimed.
Matr0xshka
left a comment
There was a problem hiding this comment.
Approval submitted at the owner’s explicit direction. This does not retract or resolve the previously reported git-state cleanup finding; no new verification of a fix is claimed.
HGW Week 1, runtime, 5 of 5. Stack: #79 → #80 → #81 → #82 → this PR (base
hgw/w1-loop-capability). Green on its own. Refs #77 (HGW-W11). Owner decision 2026-10-15, HGW (3) (D-16 as amended). The command list needs owner confirmation before merge.What changes
The list is data:
agent-sidecar/policy/auto_approve.toml, compiled in.CITRATE_HERMES_AUTO_APPROVE=0turns it off; an absolute path replaces it.--is never allowed.Shipped list:
ls,pwd,cat,head,tail,wc(relative paths only)node <relative file>npm run build|test|lint|typecheck,npm test,npx tsc --noEmitforge build|test(no--ffi)cargo build|test|checkwith--offlineor--frozengit init,git status,git diff,git add <relative paths>,git commit -mWhen a listed command runs without a card (all must hold):
Anything unlisted, network-capable or outside a project asks, as before. After taint every command asks (#79). With no sandbox (Windows), nothing is auto-approved.
Records and results:
shell.run.auto, actoragent, HIC-2). If it cannot be recorded, it asks instead.run.approval = {mode: "auto", rule, project}; card runs carry{mode: "member"}.agent-loop:
ToolOutcome::Vouched. An auto run's output comes from the project's own files: no network, writes only in the project, untainted session. Like a folder-grant file read, it does not taint. The worker wire maps it toOk, which fails closed across the process boundary.git through
shell_run:Hermes <hermes@citrate.invalid>: the scratch HOME has no identity, so git refused to commit;core.hooksPath=/dev/nullandcore.fsmonitor=falseas command-scope config ([v0.5.1 HGW-W11] Auto-approve safe-command list (amended D-16) #77).Other:
GET /shell/auto-approvereturns{enabled, conditions, rules}for the app's Settings ([v0.5.1 HGW-W11] Auto-approve safe-command list (amended D-16) #77, "Settings shows the list").shell_run's description states the approval rules and says to ask, not retry, after a decline.End to end (
e2e_build_tests; real Seatbelt, scratch home, scripted model, real node, npm and git)project_create(the only card).package.json,build.jsand a source file with a bug.git init,git add,git commit.npm run buildfails. The model readsReferenceError: greeet is not definedfrom the tool result and fixes it withfs_edit.git status) then asks, with the taint reason on its card.Negative checks in the same run:
On Linux the same tests run under bwrap. They skip without a working bwrap unless
CITRATE_REQUIRE_BWRAP=1.Interface for the core lane
run.approval.mode == "auto"runs, showing the rule and project.GET /shell/auto-approve.Needs a decision
git init(needed so that later commands are not tainted by a cardedgit init) andnode <file>.forge/cargowithout--offline: forge is allowed without--offlinebecause the sandbox already blocks the network, whilecargomust pass--offlineor--frozen.Hermes <hermes@citrate.invalid>overrides the repo'suser.name/user.emailfor Hermes's git runs. Is that wording and policy right?Vouchedright? It treats auto-run output as trusted, consistent with the 2026-10-01 decision that folder-grant reads are trusted.Tests (red first)
auto_approveunit: +4. Covers the accept and refuse matrix (including the network cases,git -c,--ffi, unlisted npm scripts,--, absolute and..paths), list validation, and the environment switch.auto_approve_tests: +8. Real sandbox: no card for listed commands; asks off the list or outside a project; taint blocks auto; no sandbox means no auto; project-only writes; switch off; recorded; list route.e2e_build_tests: +1.taint_testsvouched: +1.shell_run: git identity +1, hooks and fsmonitor off +1.🤖 Generated with Claude Code
https://claude.ai/code/session_018wWZZ8GRVU9USh3kKQHsFe