Fix allowlist rejecting paths under symlinked directories (#590) - #595
Fix allowlist rejecting paths under symlinked directories (#590)#595rahul188 wants to merge 2 commits into
Conversation
…er#590) validatePath() canonicalizes the requested path with fs.realpath, but isPathAllowed() compared it against the raw configured allowlist entries. When an allowed directory is (or is reached through) a symlink — e.g. the macOS /tmp -> /private/tmp alias — the resolved request never matched its own configured directory, so every access to the allowed directory was rejected. Canonicalize the allowlist entries the same way before comparison, resolving the deepest existing ancestor for entries that don't exist yet. Paths outside the configured directories are still rejected. Adds a portable regression test that reproduces the mismatch with an explicit symlink (skips where directory symlinks aren't permitted).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds canonicalization for configured allowlisted directories, including symlink and unresolved-path handling, and adds regression coverage for allowed symlink paths, children, outside-path rejection, cleanup, and unsupported platforms. ChangesPath canonicalization and validation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/test-allowed-directories-realpath.js`:
- Around line 34-40: Update the symlink setup catch in the test to skip only
recognized platform capability errors, such as the established
unsupported-operation or permission error codes, and rethrow all other failures.
Preserve cleanup and the 'skipped' return for recognized capability errors,
while allowing setup defects to fail the test.
- Around line 68-74: Update the assertion in the not-yet-created child case to
compare the resolved parent directory directly with resolvedTarget, rather than
comparing its parent with path.dirname(resolvedTarget). Keep the existing
validatePath(newChild) flow and success message unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4beede26-ea9a-49d0-90cd-0f368e81e862
📒 Files selected for processing (2)
src/tools/filesystem.tstest/test-allowed-directories-realpath.js
Only skip the test on recognized capability errors (EPERM/EACCES/ENOTSUP/ ENOSYS) so a genuine setup failure surfaces instead of passing as a skip, and assert the not-yet-created child resolves inside the target directory itself rather than only sharing its parent.
|
Hi 👋 Gentle nudge on this PR — it's mergeable and the required checks are passing (one non-required/optional check shows as unstable, which shouldn't block merge). Would appreciate a review whenever you have a moment, and I'm happy to address anything needed. Thanks for your time and for maintaining this project! 🙏 |
Summary
On macOS, configuring a
/tmp/...path inallowedDirectoriesrejected every access to that directory, even for the exact configured path (#590):Root cause
validatePath()canonicalizes the requested path withfs.realpathbefore checking it, so/tmp/dc-fixturebecomes/private/tmp/dc-fixture(macOS symlinks/tmp→/private/tmp).isPathAllowed()however compared that against the configured allowlist entries after onlynormalizePath()— no symlink resolution. The comparison was therefore/private/tmp/dc-fixturevs/tmp/dc-fixture, which never matches, so the allowed directory rejected itself and all of its children.This isn't macOS-only in principle: any allowlist entry that is, or is reached through, a symlink hits the same mismatch.
Fix
Canonicalize the configured allowlist entries the same way the requested path is canonicalized, before comparing. A small
canonicalizePath()helper resolves the path viafs.realpath, falling back to the deepest existing ancestor (re-appending the remaining segments) for entries that don't exist yet — mirroring the existing behavior for requested paths. Paths outside the allowed directories are still rejected.Testing
test/test-allowed-directories-realpath.js— new portable regression test. It reproduces the mismatch with an explicit directory symlink instead of relying on the macOS/tmpalias, and asserts the exact directory, an existing child, and a not-yet-created child all validate, while a path outside is still rejected. Skips gracefully where directory symlinks aren't permitted (e.g. Windows without the privilege). Confirmed the test fails onmainand passes with this change.test-allowed-directories.js,test-home-directory.js, andtest-directory-creation.jsstill pass.Fixes #590
Summary by CodeRabbit