Skip to content

permission.edit patterns are matched against worktree-relative paths — absolute/~ patterns silently never match (fail-open for deny rules) #40945

Description

@ns-calvinwu

Summary

permission.edit (and by extension write) rules are matched against the worktree-relative path of the file being edited, not the absolute path. Any rule using an absolute path or ~ pattern silently never matches. This is fail-open for deny rules: a rule like "~/.ssh/**": "deny" looks like it protects a directory but does nothing.

Environment

  • opencode 1.18.13 (Homebrew, macOS)
  • Config: ~/.config/opencode/opencode.jsonc

Root cause

The edit/write tools submit a worktree-relative path as the permission pattern:

  • packages/opencode/src/tool/write.ts:56patterns: [path.relative(instance.worktree, filepath)]
  • packages/opencode/src/tool/edit.ts:104 and :147 — same

For a file outside the worktree this yields paths with ../.. segments (e.g. ../../daily-notes/2026-08.md), which absolute/~ patterns can never match.

Repro

  1. Global config:
{
  "agent": {
    "writer": {
      "mode": "all",
      "permission": {
        "bash": "deny",
        "edit": { "*": "deny", "~/daily-notes/**": "allow" }
      }
    }
  }
}
  1. Run: opencode run --agent writer "Create the file ~/daily-notes/test.txt containing ok"

Expected: edit allowed by the ~/daily-notes/**" allow rule.

Actual: denied — the submitted pattern is relative (e.g. ../../daily-notes/test.txt from a repo cwd, Users/<name>/daily-notes/test.txt from /tmp), so the allow rule never matches and "*": "deny" wins.

The fail-open direction (security)

"edit": { "*": "allow", "~/.ssh/**": "deny" }

A user writing this believes ~/.ssh is protected. The deny rule never matches, so the agent can edit ~/.ssh/* freely. Any absolute-path deny rule for edit/write is currently a no-op.

Workaround (what I had to do)

Use relative patterns that anticipate ../ segments, which is undocumented and fragile:

"edit": { "*": "deny", "daily-notes/**": "allow", "*/daily-notes/**": "allow" }

This also over-broadens the rule: any directory named daily-notes anywhere becomes writable.

Suggestion

Resolve the submitted pattern to an absolute path before matching (or match against both absolute and relative forms), so absolute and ~ patterns work as users expect. At minimum, document that edit/write permission patterns are worktree-relative and that absolute/~ patterns do not work.

Happy to provide more detail or test a fix.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions