Skip to content

plugin: permission.evaluate ask verdicts are ignored on beta-19151 (deny still honored) #47495

Closed as not planned

Description

@whepper

Summary

On 0.0.0-beta-19151, an ask verdict set by a permission.evaluate plugin hook is ignored: the tool executes as if allowed and no prompt ever surfaces. A deny verdict from the same hook is still honored (permission.rejected). Any plugin implementing approval policies through this hook (ask-tier) is therefore silently bypassed on this beta, while deny-tier keeps working.

Environment

  • opencode version: opencode2 v0.0.0-beta-19151
  • OS: macOS, Darwin 25.5.0 (darwin arm64)
  • Terminal: VS Code integrated terminal (TERM_PROGRAM=vscode, TERM=xterm-256color)
  • Shell: /bin/zsh
  • Install/channel: beta
  • Active plugins: one local file plugin (~/.config/opencode/plugins/security-guard.js, V2 object form) plus, during the investigation only, a minimal tap plugin (removed afterwards; production state restored and verified healthy via scripts/doctor.mjs --live)

Reproduction

  1. Install a minimal tap plugin (V2 object form) at ~/.config/opencode/plugins/zzz-eval-tap.js:

    import { appendFileSync } from "node:fs"
    export default {
      id: "zzz-eval-tap",
      async setup(ctx) {
        await ctx.permission.hook("evaluate", (event) => {
          try {
            const res = Array.isArray(event?.resources) ? event.resources : []
            if (res.some((r) => String(r).includes("CANARY-ASK-TEST")) && event) {
              event.effect = "ask"
              event.message = "tap canary: direct ask, no plugin logic involved"
            }
            if (res.some((r) => String(r).includes("CANARY-DENY-TEST")) && event) {
              event.effect = "deny"
              event.message = "tap canary: direct deny, no plugin logic involved"
            }
            appendFileSync("/tmp/eval-tap.log", JSON.stringify({
              action: event?.action, effect: event?.effect, n: res.length,
            }) + "\n")
          } catch {}
        })
      },
    }
  2. Restart the service (opencode2 service restart).

  3. In an agent session, run echo CANARY-ASK-TEST.

  4. Observe: the command executes (CANARY-ASK-TEST is printed, no prompt), while /tmp/eval-tap.log contains {"action":"shell","effect":"ask","n":…} — proving the hook fired and the ask verdict was recorded, then ignored.

  5. Run echo CANARY-DENY-TEST. Observe: the command is blocked with permission.rejected carrying the tap message — deny is honored.

Expected Behavior

An ask verdict set by a permission.evaluate hook produces an approval prompt (the behavior on 0.0.0-beta-19086 for non-cd commands, per #47356), blocking execution until the user responds.

Actual Behavior

The ask verdict is silently dropped: execution proceeds as if the effect were allow. Consistently reproducible across many commands and several service restarts. deny from the same hook works correctly, and tool.execute.before throws still block — the gap is specific to the ask effect of the permission pipeline.

Impact: every ask-tier policy implemented via permission.evaluate (approval prompts for ambiguous operations) silently becomes allow on this beta. Only deny-tier enforcement can be relied on.

Additional Context

  • Related: plugin: permission.evaluate hook does not fire for cd-led shell commands #47356 (permission.evaluate not firing for cd-led commands on beta-19086 — same channel family, one beta earlier).
  • Secondary observation: on beta-19151, shell resources arrive pre-segmented — one resource per ;-segment (echo a; echo b yields n:2; a 4-statement command yielded n:4). The deny canary confirms a deny on the whole event still blocks the full command. Plugin authors matching whole-command patterns against resources should be aware the unit changed from whole-command (19086) to per-segment (19151).
  • Service log note: per-command evaluated permission=… INFO lines present on older betas no longer appear at all on 19151 (only spawning process lines), consistent with an evaluation-pipeline change.
  • Workaround used by the affected plugin: enforce ask-tier verdicts for shell commands as hard blocks inside tool.execute.before (which still throws reliably), at the cost of losing the approve-and-continue workflow for legitimate ambiguous operations.
  • Evidence method: tap log lines plus observed command outcomes; the tap plugin was removed and the service restarted afterwards (only the production plugin remains; doctor --live healthy).

Activity

  1. github-actions commented on Sep 5, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If your issue is distinct from these (the regression appears specific to beta-19151 and the permission.evaluate hook path), a maintainer may want to link them as related.

  2. whepper commented on Sep 5, 2026

    @whepper
    Author

    Thanks for the triage — I checked both, and this looks distinct but related rather than a duplicate. Suggest linking as related instead of closing:

    vs #45932 — different version line, trigger path, and reproducibility:

    • Opencode ran command explicitly set to ask without asking #45932 is V1 stable (1.18.25, Fedora, TUI session) going through native config rules (permission.bash), and is intermittent ("usually this does not happen").
    • This issue is V2 beta (0.0.0-beta-19151) going through the plugin permission.evaluate hook, with no config rules involved, and is 100% deterministic via a 10-line tap plugin.

    vs #47177 — different trigger path and a sharper bisection:

    Common thread worth linking: all three are ask-enforcement failures, so a shared root cause in permission-effect handling can't be ruled out. But the trigger paths, versions, and determinism differ enough that a duplicate closure would lose the hook-path minimal repro. Happy to re-test against a newer beta or provide tap logs.

  3. rekram1-node commented on Oct 14, 2026

    @rekram1-node
    Collaborator

    opencode-agent can u reproduce?

  4. rekram1-node commented on Oct 14, 2026

    @rekram1-node
    Collaborator

    I checked this against current dev and couldn't reproduce it. With a permission.evaluate hook setting ask on an otherwise allowed shell command, the request shows up as a prompt and the command waits until it's answered. The engine already handled ask this way on the beta you were using, so something likely answered the prompt automatically before you saw it. That could be the TUI running in auto accept mode (--auto or session.permissions set to autoaccept), the Desktop issue in #54790, or another plugin replying to permission requests. I'm going to close this for now, but please reopen it if you can still reproduce it with the TUI in normal prompt mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions