Skip to content

fix(permission): make * not match / in wildcard patterns, add ** globstar support#28689

Open
lexlian wants to merge 2 commits into
anomalyco:devfrom
lexlian:fix/28150-wildcard-path-separator
Open

fix(permission): make * not match / in wildcard patterns, add ** globstar support#28689
lexlian wants to merge 2 commits into
anomalyco:devfrom
lexlian:fix/28150-wildcard-path-separator

Conversation

@lexlian
Copy link
Copy Markdown

@lexlian lexlian commented May 21, 2026

Issue for this PR

Closes #28150

Type of change

  • Bug fix

What does this PR do?

Issue: Granular read permission deny rules don't block file access. When a user configures { read: { "*.env": "deny", "*": "allow" } }, the deny rule is bypassed for paths like src/.env.

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 /.

Fix: Made * match any characters except /, added ** globstar support for cross-directory matching. This aligns with standard glob semantics (gitignore, bash glob).

Files changed:

1. packages/core/src/util/wildcard.ts — core wildcard matching

Changed the regex generation:

  • *[^/]* (matches any chars except /)
  • **.* (matches any chars including /)
  • ?[^/] (single char except /)

Uses placeholder tokens to avoid ** being partially consumed by the * replacement and ? corrupting the (?:...)? optional group in **/.

2. packages/opencode/src/util/wildcard.ts — same changes for the opencode copy

3. packages/opencode/src/agent/agent.ts — updated default permission rules

Patterns that need to match across directories now use **:

  • read: "*""**" (catch-all), "*.env""**/*.env" (deny at any depth)
  • external_directory: "*""**" (catch-all)
  • whitelisted dirs: "*" suffix → "**" suffix

4. packages/opencode/src/permission/index.ts — defensive validation

Added type check in fromConfig() to skip array/null values with a warning.

Examples:

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

Config migration for users:

If your config uses * to match files at any depth, change to **:

// Before (worked because * matched /)
{ "read": { "*": "allow", "*.env": "deny" } }

// After (use ** for cross-directory)
{ "read": { "**": "allow", "**/*.env": "deny" } }

How did you verify your code works?

  • All 15 wildcard tests pass (6 new tests added for path-aware matching)
  • All 85 permission tests pass (5 updated for new wildcard semantics)
  • 31/40 read tool tests pass (8 env file tests now pass correctly, 1 pre-existing scout timeout unrelated to this change)

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

…star support

Wildcard * now matches any characters except /, aligning with standard
glob semantics (gitignore, bash glob). Use ** to match across directory
separators.

- packages/core/src/util/wildcard.ts: * -> [^/]*, ** -> .*, ? -> [^/]
- packages/opencode/src/util/wildcard.ts: same changes
- packages/opencode/src/agent/agent.ts: update defaults to use ** for
  patterns that need cross-directory matching (read, external_directory)
- packages/opencode/src/permission/index.ts: add array/type validation
  in fromConfig()
- tests: update existing tests for new wildcard behavior, add new tests
  for path-aware matching and ** globstar

Fixes anomalyco#28150
@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels May 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.

Granular read permission deny rules don't block file access (patterns never match)

1 participant