Skip to content

fix(core): match read rules written with ./ - #55739

Open
Yun-0000 wants to merge 2 commits into
anomalyco:devfrom
Yun-0000:read-dot-slash
Open

Yun-0000 wants to merge 2 commits into
anomalyco:devfrom
Yun-0000:read-dot-slash

Conversation

@Yun-0000

@Yun-0000 Yun-0000 commented Oct 15, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #55728

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

A read or edit deny rule written as ./Workshop/Checklist.md never matched. File tools authorize the location-relative path Workshop/Checklist.md, and the rule was compared as literal text, so the file was still returned.

read and edit now treat a leading ./ as that same relative path. Shell commands and search patterns stay literal.

How did you verify your code works?

Bun 1.4.2.

Before: FileAccess.resolve("./Workshop/Checklist.md") produced Workshop/Checklist.md. With an allow-all read rule followed by a deny for ./Workshop/Checklist.md, Permission.evaluate returned allow and Permission.Service.assert did not block.

After: the same resolve plus evaluate returns deny, and assert fails with Permission.BlockedError. Workshop/Other.md stays allowed. A shell rule starting with ./ still matches only the literal command.

Passed, from packages/core on 50ed15db4f:

  • bun run test test/permission.test.ts test/file-access.test.ts test/file-access-path.test.ts: 134 pass
  • bun typecheck: pass

Passed on push: bun run check (oxlint, ast-grep, sdk docs, turbo typecheck 36/36).

Passed on this head: check-compliance, check-standards. check-duplicates and add-contributor-label passed on the previous head and did not re-run. test, typecheck, and nix-eval are not in the check list and did not fail. Combined status is pending with 0 statuses. The TUI drive script on the issue and the full packages/core suite were not run.

Screenshots / recordings

Not a UI change.

Checklist

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

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this, and the fix works. I ran the reproduction script from #55728 from source on both branches. On the base, a read deny rule written as ./Workshop/Checklist.md was ignored and the file contents reached the model. With this change, the read is denied and nothing leaks. The permission and file-access tests pass (135), and so does bun typecheck in packages/core.

The public API is unchanged. This only changes how existing read/edit rules match, and rules without ./ work as before.

The code change looks good. Stripping ./ inside Permission.evaluate means it applies to rules from every source, not only config. My one request is about the size of the new tests (inline comment). Heads-up: #53365 changes the same matching code, so whichever lands second may need a rebase.

expect(Permission.evaluate("external_directory", "C:/Users/x/other/*", rules).effect).toBe("ask")
})

test("treats a leading ./ on read and edit rules as the project-relative path", () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This table test has 14 checks for a 16-line fix. Could you cut it down to the core cases? A ./ read rule denying the relative path, an edit case, a ./dir/* glob, and the shell rule staying literal would be enough. Cases like ././, .//, ./ → ., .\ and the rule-ordering checks can go. The new file-access.test.ts test mostly checks existing resolve behaviour, and the Service.assert test in this file already covers the fix end to end, so that one could be dropped too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimmed the table to a ./ read deny, an edit deny, a ./Workshop/* glob, and the shell rule staying literal. Removed the extra ././, .//, .\, and ordering checks, and dropped the file-access resolve test. The Permission.Service.assert case is still the end-to-end check.

Re-ran on Bun 1.4.2 from packages/core: permission, file-access, and file-access-path tests are 134 pass, and bun typecheck passes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is what I meant. I checked 50ed15db. The table now has the core cases: a ./ read deny, an edit deny, a ./Workshop/* glob, and the shell rule staying literal. The extra file-access test is gone, and permission.ts is the same as the version I tested earlier. I have nothing else on the tests.

This branch has not been deployed

No deployments
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.

permissions: deny rule for read tool is ignored, file contents returned anyway

1 participant