fix(paths): reject every path anchor in repo-relative guards, not just absolute ones - #65
Open
Hotragn wants to merge 1 commit into
Open
fix(paths): reject every path anchor in repo-relative guards, not just absolute ones#65Hotragn wants to merge 1 commit into
Hotragn wants to merge 1 commit into
Conversation
…t absolute ones
`is_absolute()` is not a containment check on Windows. `PureWindowsPath`
reports "/tmp/wiki" as relative because it carries no drive, and "C:wiki" as
relative because it carries no root. Both still discard the left-hand side when
joined, so a guard built on `is_absolute()` accepts inputs that escape the repo:
PureWindowsPath("C:/repo") / "/tmp/wiki" -> C:/tmp/wiki
PureWindowsPath("D:/repo") / "C:wiki" -> C:wiki
Two guards depended on that check:
- `SourceRuntimeContext.ignored_directories`, which promises
"source runtime ignored directories must be repo-relative"
- `require_default_almanac_root`, which promises
"Almanac root must be a repo-relative path"
`tests/test_filesystem_source_runtime.py` already asserted that "/tmp/wiki" is
rejected, and that assertion failed on Windows. This restores it.
Both guards now share `core.paths.is_rooted`, which rejects any anchor. On POSIX
a root implies an absolute path and `drive` is always empty, so the predicate is
exactly equivalent to the old check and macOS/Linux behaviour is unchanged.
The new tests use explicit `PureWindowsPath`/`PurePosixPath` inputs rather than
the platform-native `Path`, so both platforms' semantics are pinned on any
runner and this stays verifiable on the current Linux-only CI.
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.
Summary
is_absolute()was used as the "must be repo-relative" containment guard in two places. It does not hold on Windows.core.paths.is_rooted, which rejects any path anchor (absolute, rooted-without-drive, or drive-without-root).test_filesystem_source_runtime.pythat fails on Windows today.Why
On Windows,
PureWindowsPathreports two anchored forms as relative:is_absolute()driveroot/tmp/wikiFalse'''\'C:wikiFalse'C:'''Both still discard the left-hand side when joined, which is exactly what a containment guard exists to prevent:
Two guards relied on that check, and both make an explicit promise in their own error message:
SourceRuntimeContext.ignored_directories— "source runtime ignored directories must be repo-relative" (services/sources/requests.py)require_default_almanac_root— "Almanac root must be a repo-relative path" (services/repositories/roots.py)This is not a hypothetical:
tests/test_filesystem_source_runtime.py::test_source_runtime_context_rejects_unsafe_ignored_directories[directory0]already asserts that/tmp/wikiis rejected, and that assertion fails on Windows. The repo already decided this input is unsafe; the guard just does not enforce it off POSIX.It matters most for
ignored_directories, since source runtime context is populated from wiki page frontmatter that agents author, so the value is not necessarily developer-typed.require_default_almanac_rootis hardened for consistency — its later!= almanaccheck already rejected these inputs, so that half is defence in depth rather than a live escape.Verification
Confirmed the tests pin the bug rather than describe it — with the predicate reverted to
is_absolute()only, these fail:The remaining 12 failures are pre-existing and unrelated (macOS
launchdtests plus non-portable fixtures).Docs and wiki
Notes for reviewers
driveis always'', sois_rootedis exactly equivalent tois_absolute()there. The predicate only widens on Windows.core/paths.pybesidenormalize_path, which both services already import. Two call sites with the same subtle rule is how the next one drifts.Pathon purpose.Path("C:wiki")is a legitimate relative filename on POSIX and an anchored path on Windows, so a test written withPathcan only ever check the host it runs on. Using explicitPureWindowsPath/PurePosixPathpins both platforms' semantics, which means this fix is fully verifiable on the current Linux-only CI — no Windows runner needed to review it.resolve_user_path(services/sources/address_path.py) andtranscript_path(integrations/sources/transcripts/paths.py) use the inverse check,if not path.is_absolute(): path = cwd / path. Those have a related Windows wart —/tmp/xtakes the "relative" branch and then resolves drive-relative instead of undercwd— but they are a resolution concern rather than a containment guard, and both are meant to accept absolute input. Happy to send that as its own PR if you want it fixed; I left it out to keep this one reviewable.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.