Skip to content

Deny gated permissions in headless runs; drop the session wildcard (#26)#34

Merged
TheRealDinghyDog merged 1 commit into
opencode-conversionfrom
fix/issue-26-write-permissions
Jul 10, 2026
Merged

Deny gated permissions in headless runs; drop the session wildcard (#26)#34
TheRealDinghyDog merged 1 commit into
opencode-conversionfrom
fix/issue-26-write-permissions

Conversation

@TheRealDinghyDog

Copy link
Copy Markdown
Owner

Fixes #26 (review finding H-01).

Problem

Write turns created sessions with a bare {permission: "*", action: "allow", pattern: "*"} rule and answered every permission.asked with "always". Verified against OpenCode v1.17.15 source (Permission.merge + evaluate): session rules are appended after the agent's ruleset and each request resolves to the last matching rule, so the session wildcard silently stripped the stock build agent's safety guards (external_directory: ask, .env/.env.* reads: ask, doom_loop: ask) — and the auto-"always" responder would have approved any ask that survived. The rescue subagent defaults to --write, making this the default posture for delegated implementation tasks.

Fix

  • No session-level permission rules at all. The stock build agent's ruleset (wildcard allow + ask-guards + its machine-specific allowances for OpenCode's own tool-output directories) is exactly the intended headless write profile. Any session-level override — including a re-asserted guard — would clobber parts of it under last-match-wins.
  • Reject every headless permission ask, write mode included, with a progress diagnostic naming the gated category and patterns. Under the stock agents an ask only fires when a guard trips (or the user deliberately configured a category as interactive), so routine write turns remain approval-free while gated requests deterministically fail instead of being self-approved.
  • Fixed the misleading comment that claimed wildcard parity with the build agent; marked the original auto-approve design in docs/opencode-adaptation-plan.md as superseded.
  • README now documents that OpenCode permissions are approval-level controls, not an OS sandbox.

Tests

  • Fake fixture reworked to model the real contract: workspace edits are ungated (no permission round-trip); a gated ask must be denied, and only an (incorrect) approval emits the out-of-workspace edit.
  • Rewrote the write-task regression test: asserts no session permission override is sent, the gated ask is answered "reject", and only the workspace edit appears in touchedFiles.
  • npm test: 81 passed, 0 failed, 0 skipped (localhost integration included).

True end-to-end enforcement (a live model attempting an out-of-workspace edit) requires a provider-backed turn and is deferred to the release checklist, consistent with the review's own verification scope.

🤖 Generated with Claude Code

Write turns previously created sessions with a bare
`{permission: "*", action: "allow", pattern: "*"}` rule and answered every
permission.asked with "always". OpenCode merges session rules AFTER the
agent ruleset and resolves with the LAST matching rule, so the wildcard
silently stripped the stock build agent's safety guards
(external_directory/.env reads/doom_loop stay on "ask"), and the
auto-"always" responder would have approved any that survived.

Send no session-level permission rules at all — the stock build agent's
ruleset (wildcard allow + ask-guards, plus its own tool-output allowances)
is exactly the intended headless write profile — and reject every headless
permission ask with a diagnostic naming the gated category. Under the
stock agents an ask only fires when a guard trips, so routine write turns
stay approval-free.

Also documents that OpenCode permissions are approval controls rather than
an OS sandbox, updates the fake fixture so workspace edits are ungated
while a gated ask must be denied, and marks the original auto-approve
design in the adaptation plan as superseded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@TheRealDinghyDog
TheRealDinghyDog merged commit 16d2a8e into opencode-conversion Jul 10, 2026
1 check passed
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