Repository navigation
fix(guardrails): resolve only the existing ancestor through cygpath for an allowed-roots link - #10280
Conversation
…tion On Windows, spd_under_allowed_root passed the resolver's answer for a target's nearest existing ancestor, with the not-yet-created components joined on, to cygpath -l -m. When that answer comes back in a mount spelling (a junction into the temp folder, read as /tmp/...), the long drive spelling can be produced only for a path that exists, so the target never matched the long-spelled root and the "through a link outside D that lands under D" case scanned (exit 2) in test-windows-secrets. Map only the existing ancestor to its compare spelling, then join the remaining components. A path resolving outside every root and an unresolvable ancestor still scan. A Linux seam test forces the msys arm with a stub resolver and cygpath, and fails without the fix. Refs: #10019 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-review reviewed No findings. I read the full diff (3 files), the PR context, and The fix (
Test (
It is skipped when no symlink can be made or on a Windows host. The stubs match the code path: the resolver answers in the mount spelling, and Unverified Windows behaviour: the PR says the real Windows result, including Closing issue: the PR refs #10019 and closes no issue, so there are no acceptance criteria to check. Manifests: none changed. The changelog fragment ( Cost: nothing here can cause a charge. |
|
claude-security-review reviewed No security issues found in this pull request. critical-findings: 0 What I checked. The change is in Why it does not widen the exemption.
Residual notes, not findings.
The Cost: the review spends no billed resources. |
|
test-windows-secrets passed on this head (5d92c9a): job 121609000889. That is the job #10276 reports failing on main with |
…sue-7681-40232573194-1 Brings in #10280's guardrails fix for the inherited test-windows-secrets failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs: #10019
Summary
test-windows-secretshas been red since #10019 on one case: "allowed roots: through a link outside D that lands under D → exit 0: expected exit 0, got 2" (for example run 40211741514,PASS=301 FAIL=1). The guard failed safe: it scanned a write it should have exempted. This fixes the Windows path so the case grants as it does on Linux, without granting anything new.Root cause:
The test makes the link with
mklink /J, and its target iscygpath -wof a/tmp/...path (TEST_TMPDIRismktemp -d), so the junction stores a Windows temp-folder path.On the runner,
/tmpis the user temp folder. The log spells the same mktemp directory both as/tmp/tmp.ZAZQuZvuJK/...and asC:/Users/runneradmin/AppData/Local/Temp/tmp.ZAZQuZvuJK/....Cygwin, and so Git Bash, follows a junction as a symlink. Its user guide says directory junctions are "recognized as symlink but never generated by Cygwin", and describes the
usertempmount that maps the temp folder to/tmp(Cygwin user guide).Before the fix,
spd_under_allowed_rootpassed"<realpath of to-d>/sub/x.md"tocygpath -l -m, andsubdoes not exist yet.GetLongPathNameWfails "if the file does not exist" (Microsoft Learn).The passing case "entry spelled through a link to D → exit 0" sends the same realpath answer for
to-d, with nothing appended, through the samespd_cmp_to, and gets a long spelling that matches the root. The fix's firstspd_cmp_tocall gets exactly that input, so the failing case should now match the same way.UNVERIFIED (inference, not run on Windows):
realpathanswers the junction in the/tmp/...mount spelling;RUNNER~1);cygpath -lusesGetLongPathNameW;cygpath -l -mon a missing tail prints the short spelling or exits non-zero.Either outcome fails the old comparison, and the fix avoids both, so the conclusion does not depend on which one is true.
Fix
plugins/guardrails/hooks/secret-pattern-detection.sh(spd_under_allowed_root):spd_cmp_tonow maps only the existing ancestor's physical path. The components below it, which do not exist, are joined after that. The secondspd_cmp_tocall only folds case and drive, and on Windows it spawns nocygpath, because its input is already drive-spelled.-efidentity check still applies, and either call failing still returns 1. The joined components do not exist, so they can hold no link, and the target was already refused for..,.,//or a line break. On Linux the compared string is the same as before.plugins/guardrails/hooks/secret-pattern-detection.test.sh: a seam test forces the msys arm on any host. A stub resolver answers in a mount spelling, and a stubcygpathexpands long names only for a path that exists. It checks that a junction into the root grants, and that a junction to outside and an unresolvable ancestor do not..changes/guardrails/: a patch fragment.Verification
bash plugins/guardrails/hooks/secret-pattern-detection.test.shon Linux:PASS=312 FAIL=0.PASS=311 FAIL=1. The new "junction outside D into D, mount-spelled answer → granted" case fails, so the test exercises the fix.shellcheckis clean on both files.scripts/check-changelog-fragments.sh --checkpasses.pr-test-windowsrun (test-windows-secrets), where "through a link outside D that lands under D → exit 0" must pass.Related
🤖 Generated with Claude Code