You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Provider: OpenCode Zen (opencode/big-pickle)
Config: ~/.config/opencode/opencode.json / jsonc
Shell: zsh
I wanted to restrict the agent from reading certain personal folders when using cloud models. The permission system seemed perfect for this, but granular deny rules on read, glob, and grep never block access despite the config loading correctly.
What works:
Global deny ("read": "deny") correctly removes the read tool entirely
opencode debug config confirms rules are loaded into resolved config
Config validates as valid JSON
What doesn't work:
Granular deny rules never match file paths. Tested all following pattern formats in read, glob, and grep permissions — none blocked access:
Removing "*": "allow" entirely (falling through to default allow)
Restarting both opencode and terminal between config changes
Applying same rules to glob and grep permissions
Expected behavior:
Setting "read": { "Documents": "deny" } should prevent the agent from reading files whose path contains "Documents".
Actual behavior:
All file reads succeed regardless of deny rules.
I created a fix in PR #28689, but this might lead to some design discussion. Granular read permission deny rules weren't blocking file access — when configuring { read: { "*.env": "deny", "*": "allow" } }, the deny rule was bypassed for paths like src/.env.
The root cause: wildcard * was converted to regex .*, which matches any character including /. This meant *.env matched src/.env, a/b/.env — making it as broad as *. With "last matching rule wins" semantics, a later wildcard * rule always overrode specific deny rules for any path containing /.
The fix makes * match any characters except /, and adds ** globstar support for cross-directory matching — aligning with standard glob semantics (gitignore, bash glob). Patterns that need to match across directories (like the catch-all "*" → "**" and "*.env" → "**/*.env") have been updated in the default permission rules in agent.ts.
Pattern matching changes:
Pattern
Before (bug)
After (fix)
*.env
matches .env, src/.env, a/b/.env
matches .env only
**/*.env
same as *.env (no ** support)
matches .env, src/.env, a/b/.env
src/*.env
matches src/.env, src/a/.env
matches src/.env only
src/**/*.env
not possible
matches src/.env, src/a/.env
*
matches anything including paths
matches single-segment filenames only
**
same as *
matches anything including paths
Note for reviewers: This changes the semantics of * in permission patterns. Existing configs using * to match files at any depth will need to migrate to **. I've documented the migration path in the PR description.
Activity
github-actions commentedon May 18, 2026
This issue might be a duplicate of existing issues. Please check:
*: askin permission config" — related: deny rules being overriddenIf your issue is distinct from the above, please add a note explaining what makes it different.
lexlian commentedon May 28, 2026
I created a fix in PR #28689, but this might lead to some design discussion. Granular read permission deny rules weren't blocking file access — when configuring
{ read: { "*.env": "deny", "*": "allow" } }, the deny rule was bypassed for paths likesrc/.env.The root cause: wildcard
*was converted to regex.*, which matches any character including/. This meant*.envmatchedsrc/.env,a/b/.env— making it as broad as*. With "last matching rule wins" semantics, a later wildcard*rule always overrode specific deny rules for any path containing/.The fix makes
*match any characters except/, and adds**globstar support for cross-directory matching — aligning with standard glob semantics (gitignore, bash glob). Patterns that need to match across directories (like the catch-all"*"→"**"and"*.env"→"**/*.env") have been updated in the default permission rules inagent.ts.Pattern matching changes:
*.env.env,src/.env,a/b/.env.envonly**/*.env*.env(no**support).env,src/.env,a/b/.envsrc/*.envsrc/.env,src/a/.envsrc/.envonlysrc/**/*.envsrc/.env,src/a/.env****Note for reviewers: This changes the semantics of
*in permission patterns. Existing configs using*to match files at any depth will need to migrate to**. I've documented the migration path in the PR description.github-actions commentedon Aug 16, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.