fix(core): allow reads of permitted skill resources by kitlangton · Pull Request #47554 · anomalyco/opencode · GitHub
Skip to content

fix(core): allow reads of permitted skill resources - #47554

Open
kitlangton wants to merge 1 commit into
v2from
skill-resource-access
Open

fix(core): allow reads of permitted skill resources#47554
kitlangton wants to merge 1 commit into
v2from
skill-resource-access

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

Why

Loading an installed skill succeeds, but reading a supporting file from that skill can immediately stop for an unrelated external-directory approval. This happens with discovered skill directories outside the project, including a symlinked ~/.opencode/skill directory: skill loading checks the skill ID, while the subsequent read checks the filesystem boundary independently.

What Changes

The read tool recognizes supporting paths beneath registered directory-based SKILL.md skills whose skill permission evaluates to allow. It supplies an allowance for that read's external-directory assertion, then applies the ordinary read permission.

Case Result
Allowed directory skill → read references/policy.md Reads without an extra external-directory prompt
Explicit read or external_directory denial Remains blocked
Supporting .env file Still asks under the normal read policy
Skill permission is ask or deny Retains ordinary external-directory authorization
Flat Markdown skill or unrelated sibling path Gets no supporting-directory allowance

Permission flow

The allowance lasts for one Permission.assert call. Configured denials are checked first, and permission evaluation hooks still run. This overrides an external_directory: ask decision for the recognized read, but does not save an approval or grant subsequent edit/shell access to that directory.

Demo

skill-resource-before-after.mp4

Before: cd504dc66a. After: e63c147ac3. The same OpenCode Drive 2.1.0 fixture loads a skill from a symlinked external source, then invokes the real read tool on its supporting policy. Only the provider responses are simulated. The before run records an external_directory request from the reference read; the after run records none. Both runs verify the real tool's returned file content (the before request is approved only after its recording checkpoint).

Matched four-second checkpoints, sequentially presented at native 1000×640 resolution to keep terminal text legible. No acceleration.

Scope

This fixes read access to registered directory-skill resources without adding global directory rules or persisted permissions. It follows the existing lexical path policy; symlink canonicalization and skill-activation history are outside this change.

Verification

From packages/core:

bun run test test/tool-skill-resource.test.ts
bun run test test/tool-skill-resource.test.ts test/tool-read.test.ts test/permission.test.ts test/session-instructions.test.ts
bun run test test/tool-*.test.ts test/skill*.test.ts test/config/skill.test.ts test/agent.test.ts test/location-mutation.test.ts test/permission.test.ts test/session-instructions.test.ts
bun typecheck
  • Regression first: both plain and symlinked external skill fixtures failed on the unexpected external_directory request before the fix.
  • Focused: 138 passing tests, including real skill discovery, skill loading, supporting-file reads, explicit denials, .env read approval, unrelated paths, and non-persistence of the read allowance.
  • Broader: 517 passed, 19 skipped, 0 failed across 24 files.
  • Types: Core typecheck passed. The normal pre-push hook also passed all 33 workspace typecheck tasks with Bun 1.4.2.
  • End to end: matched isolated Drive runs passed, including tool-result verification. Encoded before/after frames were inspected at native size.
  • Prettier and git diff --check passed. Scoped oxlint reported no errors (existing warnings only).

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant