Skip to content

fix(opencode): show what an OpenCode permission is for, safely - #1026

Merged
Juliusolsson05 merged 5 commits into
mainfrom
fix/opencode-permission-subject
Sep 19, 2026
Merged

Juliusolsson05 merged 5 commits into
mainfrom
fix/opencode-permission-subject

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Problem

#878 (release blocker). With OpenCode bundled, the structured runtime's permission modal said "OpenCode is requesting permission." with no subject, so users approved bash: ls -1 blind, and the question modal showed no question. The parsers didn't match the payload OpenCode actually sends.

Implemented

  • Package: bump opencode-headless to 62440add (fix(permissions): read permission and question subjects from the 1.18.30 payload opencode-headless#14, reviewed and merged). One shared subject parser, tested on recorded 1.18.30 streams:
    • bash shows the whole command (metadata.command), so cd x && … or export …&& prefixes can't hide;
    • other kinds show permission: patterns;
    • questions read questions[].question.
  • Modal (views.tsx): the subject is now populated for the first time, so render it safely:
    • the command goes in a bounded, scrolling, wrapping <pre>, untruncated, because this modal is the only place the user sees it. A 100-line heredoc can no longer push the buttons off-screen while the auto-focused "Allow once" answers Enter;
    • "Allow always covers …" is spelled out from the payload's own always list, with an explicit warning when it is * (edit, write and MCP asks mean every such request for the session). OpenCode's own UI confirms this scope; ours showed nothing.

Verification (fail-first, recorded input)

  • opencodePermissionView.renderer.test.tsx replays the recorded OpenCode 1.18.30 stream through the bumped package's real EventDispatcher into the real view. It asserts the subject is in the scroll container, the recorded always scope (ls *) is shown, and a derived 60-line heredoc renders in full.
  • Before the fix: 3/3 failed. The subject arrived, which proves the package bump end to end, but it was inline (SPAN) with no scope.
  • After the fix: 3/3 pass. The OpenCode renderer and unit suites are green (unit 39/39), and tsc -b is clean.

Follow-up

Questions are now visible but can only be rejected; answering them is a separate issue: #1025

🤖 Generated with Claude Code

Juliusolsson05 and others added 5 commits September 18, 2026 23:45
Refs #878

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ion subjects

Picks up Juliusolsson05/opencode-headless#14. One shared parser reads the
subject OpenCode actually sends. bash shows the whole command, and
questions read questions[].question. Tested on recorded 1.18.30 streams.

Refs #878

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The recorded stream is replayed through the bumped package's real
EventDispatcher and rendered by the real view. It fails first: the
subject arrives but sits inline, and nothing says what Allow always
covers.

Refs #878

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ways scope

With subjects populated for the first time, the modal has to render them
safely. The command goes in a bounded, scrolling, wrapping block,
untruncated, so a heredoc can no longer push the buttons off-screen
while Allow once holds focus. The modal also says what Allow always
covers, from the payload's own always list, and states plainly when that
is '*', meaning every such request for the session.

Fixes #878

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rue Allow-always reach

From the #1026 review. OpenCode's default rules allow bash and ask only
for external_directory, so for most users the shell prompt read
'external_directory: /work/old/*' while the command that runs sat unseen
in the payload's metadata. The modal now shows that command whenever
the subject does not already contain it.

The Allow-always line now names the permission and states its real
reach: OpenCode keeps the grant in the server's memory, so it covers
this agent and its subagents until the agent restarts, which is how
OpenCode's own TUI words it. The wildcard case reads 'every <kind>
request'. The scope line wraps long patterns, and the question body is
bounded and scrollable, since the only button (Reject) must stay on
screen now that questions render. Tests read the recording shipped in
the bumped package.

Refs #878

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Review round 1 (independent): CHANGES REQUESTED → resolved in 48bce88a:

  1. Medium-High, fixed: default OpenCode permissions ask external_directory for shell commands, so the modal now also shows the command from metadata.command whenever the subject does not contain it. Fail-first test on the recorded ask, reshaped to that default-permission shape.
  2. Fixed: the Allow-always reach now matches OpenCode's own wording: this agent and its subagents, until this agent restarts. The permission is named, and the wildcard case reads "every request". Tested.
  3. Fixed: the * warning is tested.
  4. Fixed: the question body is bounded and scrollable, so Reject stays on screen. Tested with the recorded question stream.
  5. Fixed: the scope line has break-words, and the unused data attribute is removed. The tests read the recording shipped in the bumped package.

Renderer suite 6/6; tsc -b clean.

@Juliusolsson05
Juliusolsson05 merged commit 1212d98 into main Sep 19, 2026
2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the fix/opencode-permission-subject branch September 19, 2026 07:50
Juliusolsson05 added a commit that referenced this pull request Sep 19, 2026
Co-Authored-By: Claude Opus 5 (1M context) <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