Skip to content

fix(ext/node): fs.cp across allowed dirs with ignored read permissions#32927

Merged
bartlomieju merged 2 commits intodenoland:mainfrom
bartlomieju:fix/fs-cp-parent-path-permissions
Mar 24, 2026
Merged

fix(ext/node): fs.cp across allowed dirs with ignored read permissions#32927
bartlomieju merged 2 commits intodenoland:mainfrom
bartlomieju:fix/fs-cp-parent-path-permissions

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

Summary

  • Fix node:fs.cp failing with ENOENT when copying between allowed
    directories while read permissions outside those directories are ignored
    ("ignore": true in deno.json permissions config)
  • The check_parent_paths walk-up now handles NotFound from permission
    checks (ignored denials) the same way it handles NotFound from stat
    by stopping the ancestor traversal

Root cause: When fs.cp was moved from JS to Rust (#32580, #32687), the
parent path validation started propagating ignored-permission ENOENT as a
hard error instead of treating it as a stop signal. The old JS code's
safeStatFn caught NotFound and returned undefined, gracefully stopping
the walk. The Rust code's check_cp_path()? propagated it before reaching
the stat call's own NotFound handler.

Closes #32923

Test plan

  • New spec test fs_cp_ignored_permissions — copies a file using
    fs.cp (callback), fs.promises.cp, and fs.cpSync across directories
    with limited read permissions and ignore: true
  • All existing fs_cp spec tests pass

🤖 Generated with Claude Code

When `fs.cp` was moved from JS to Rust, the `check_parent_paths` function
walks up the destination's parent directory chain calling `check_cp_path()`
at each level. With `"ignore": true` permissions, denied reads become
`ENOENT` errors. The old JS code handled this gracefully (safeStatFn caught
NotFound and stopped walking), but the Rust code propagated the error via
`?` before reaching the stat call's own NotFound handler.

Fix: catch NotFound from the permission check and treat it the same as a
non-existent directory — stop walking and return Ok(()).

Closes denoland#32923

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a regression in the Rust-backed node:fs.cp implementation where ancestor-path validation could incorrectly treat ignored permission denials as fatal ENOENT, breaking copies between otherwise-allowed directories when permissions.default.read.ignore: true is set.

Changes:

  • Update check_parent_paths ancestor traversal to treat ignored-permission NotFound from permission checks as a stop signal (like stat’s NotFound).
  • Add a new node spec regression test covering fs.cp (callback), fs.promises.cp, and fs.cpSync under ignored read permissions.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ext/node/ops/fs.rs Stops parent traversal when permission checks return NotFound due to ignored read permissions, preventing erroneous hard failures.
tests/specs/node/fs_cp_ignored_permissions/main.ts New regression script exercising fs.cp variants under a permissions config using ignore: true.
tests/specs/node/fs_cp_ignored_permissions/main.out Expected output for the new regression test.
tests/specs/node/fs_cp_ignored_permissions/__test__.jsonc Spec test definition running the new script with -P permissions config.
tests/specs/node/fs_cp_ignored_permissions/deno.json Permissions configuration reproducing the ignored-read-permissions scenario.
tests/specs/node/fs_cp_ignored_permissions/dir1/data.txt Source fixture file for the copy.
tests/specs/node/fs_cp_ignored_permissions/dir2/data_cb.txt Destination fixture file used by callback copy variant.
tests/specs/node/fs_cp_ignored_permissions/dir2/data_promise.txt Destination fixture file used by promise copy variant.
tests/specs/node/fs_cp_ignored_permissions/dir2/data_sync.txt Destination fixture file used by sync copy variant.
tests/specs/node/fs_cp_ignored_permissions/dir2/.gitkeep Keeps the destination directory tracked.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju merged commit 637b758 into denoland:main Mar 24, 2026
112 checks passed
@bartlomieju bartlomieju deleted the fix/fs-cp-parent-path-permissions branch March 24, 2026 13:47
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.

Using node:fs.cp across allowed directories is broken

2 participants