Skip to content

chore(hardening): enforce configured permission rules and fail closed on approval - #2

Merged
devGregA merged 1 commit into
mainfrom
hardening/permission-enforcement
Aug 13, 2026
Merged

chore(hardening): enforce configured permission rules and fail closed on approval#2
devGregA merged 1 commit into
mainfrom
hardening/permission-enforcement

Conversation

@devGregA

Copy link
Copy Markdown
Contributor

Problem

Three gaps in how the v2 permission layer enforces its own configuration:

  1. Configured [permission] rules were inert. The config section parses deny / allow / ask into rules, and the user-configured-* policies read them — but addRules had no caller anywhere in the repo, and the backing Op is persist: false, so the model always stayed empty. An operator setting deny = ["Bash"] got a silent no-op.
  2. Auto mode waived the content-sensitive asks. auto-mode-approve sat at position 3 in the policy chain, ahead of sensitive-file-access-ask (7) and git-control-path-access-ask (8), so neither was reachable once auto mode was on.
  3. A missing approval broker meant "approved." An embedding host that never bound ISessionApprovalService silently auto-approved every call that reached the ask path.

What changed

  • Seed rules at agent bootstrap (agentLifecycleService.bindBootstrap), immediately after the existing defaultPermissionMode seeding and using the same IConfigService pattern. Because the Op is not persisted, seeding happens per agent scope.
  • Reorder the policy chain so auto-mode-approve sits after the sensitive-file and git-control asks. Deliberately minimal: session-approval-history and user-configured-allow keep their existing precedence over the asks, so anything already approved (or explicitly allowed by the user) does not start re-prompting. Only the auto-mode blanket approval moved.
  • Fail closed in requestToolApproval when no broker is bound — the request resolves to a veto rather than an approval.

Behaviour change worth flagging to reviewers

Auto mode (including headless -p, which sets it) will now prompt on sensitive-file and .git control-path access instead of proceeding silently. That is the intent, but it means an unattended run that touches those paths will now block on a prompt rather than continue. Worth knowing before this is wired into any automation.

Testing

  • New: sensitive-file and git-control asks still fire in auto mode; config rules are seeded onto a created agent; no rules when config has no permission section.
  • Updated: the test that pinned the old fail-open broker behaviour now asserts the veto.
  • Verified as real tests: with the three source changes reverted, exactly those 4 tests fail; with them applied all pass.
  • Full agent-core-v2 suite green: 310 files / 4875 tests, so the chain reorder causes no regressions elsewhere.
  • oxlint and tsc --noEmit clean.

Checklist

  • Problem explained above (fork-local hardening; no upstream issue).
  • Tests added that prove the change works.
  • Changeset added (minor — behavioural change).
  • No doc update needed.

… on approval

Seed each agent scope with the user's [permission] rules at bootstrap,
next to where the default permission mode is applied. The
permission.rules.add Op is not persisted, so the rules model always
started empty and a configured allow/deny/ask never reached the policy
chain.

Move the sensitive-file and git-control asks ahead of the blanket
auto-mode approval in the policy chain so auto mode does not waive them.
Session approval history and user allow rules keep their existing
precedence, so an already-approved access does not re-prompt.

Treat a missing approval broker as a denial rather than an approval: if a
policy decided a call needs confirmation and there is nobody to ask, the
call is blocked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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