Accept a predicate for forbidden_read / forbidden_write - #29
Merged
Conversation
These two tool filters took a fullmatch regex while global_exclude already accepted either a regex or a Callable[[PurePath], bool]. A regex is the wrong shape for anything that reasons about path structure: excluding a directory at any depth reads as (.*/)?node_modules/.* rather than "node_modules" in p.parts, and carving one file kind back out of an excluded subtree needs a lookahead. Widen both to GlobalExcludeArg and fold the two surface forms into a single _make_exclude_pred, so the regex and callable arms are interpreted in one place and _make_checker / _make_global_include_pred differ only by the .git floor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 4, 2026
jtoman
approved these changes
Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
global_excludeaccepts either a fullmatch regex or aCallable[[PurePath], bool](
GlobalExcludeArg), butforbidden_read/forbidden_writeaccept only a regex. Thecomment on the type alias already called out why that asymmetry hurts:
Two rules a consumer actually wants are painful or unreadable as a regex:
(?:.*/)?node_modules/.*versus"node_modules" in p.parts(
(?!.*\.sol\Z)(?:…)) to say "withhold this tree, but never Solidity"Change
forbidden_read/forbidden_writewiden fromstr | NonetoGlobalExcludeArg, onVFSToolConfig,fs_toolsandfs_tools_layered._make_exclude_pred._make_checkerand_make_global_include_predare thin wrappers over it that differonly in whether the always-on
.gitfloor is composed in — previously each re-parsedthe argument itself.
The regex arm stays, since it is the right shape for a pattern supplied as a CLI
argument. Callables are handed a
PurePosixPath, soparts/suffix/namebehavethe same regardless of host platform.
No behaviour change for existing callers: a
strargument follows the identicalre.fullmatchpath it did before.Testing
TestForbiddenRead: the callable form filters the tool surface, canexpress a carve-out (
suffix != ".sol" and "node_modules" in parts) that a plain regexcannot state without a lookahead, and receives a
PurePosixPath.tests/test_vfs.py,tests/test_fs_layered.py).pyrightclean ongraphcore/andtests/(two pre-existingtestcontainers.postgresimport errors in
conftest.pyare unchanged).🤖 Generated with Claude Code