Skip to content

node:fs: preserve special POSIX mode bits in file modes - #33042

Closed
FuPeiJiang wants to merge 1 commit into
oven-sh:mainfrom
FuPeiJiang:fix-fs-mode-special-bits
Closed

node:fs: preserve special POSIX mode bits in file modes#33042
FuPeiJiang wants to merge 1 commit into
oven-sh:mainfrom
FuPeiJiang:fix-fs-mode-special-bits

Conversation

@FuPeiJiang

@FuPeiJiang FuPeiJiang commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What

Change node:fs mode normalization from mode & 0o777 to mode & 0o7777.

Why

Bun currently masks file modes to 0o777. That preserves the common rwx permission bits and strips file-type bits from values like stat.mode, e.g. 0o100644 -> 0o644.

However, 0o777 also drops POSIX special mode bits:

  • setuid: 0o4000
  • setgid: 0o2000
  • sticky: 0o1000

Node preserves these bits for chmod/fchmod and creation modes. Masking to 0o7777 keeps all POSIX permission bits while still stripping file-type bits such as S_IFREG (0o100000).

This keeps the existing stat-mode compatibility behavior while avoiding accidental loss of special mode bits.

Note

Node appears to validate file modes as uint32 values and pass them through without applying this permission mask. This PR keeps Bun's existing behavior of stripping higher file-type bits from values like stat.mode, but changes the mask from 0o777 to 0o7777 so POSIX special mode bits are preserved.

If exact Node compatibility is preferred, removing the mask entirely is another option.

Tests

Added Bun-owned coverage for:

  • fs.chmod
  • fs.chmodSync
  • fs.fchmod
  • fs.fchmodSync
  • numeric and octal-string mode inputs
  • fs.writeFileSync({ mode })

Local verification:

git diff --check
PATH=/root/.cargo/bin:$PATH bun run build:debug:noasan
./build/debug/bun-debug test test/js/node/fs/fs.test.ts -t 'preserves special POSIX mode bits'
./build/debug/bun-debug test/js/node/test/parallel/test-fs-chmod-mask.js

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 59ede85e-2d67-4348-878e-f82610d44356

📥 Commits

Reviewing files that changed from the base of the PR and between 9489175 and ef751c6.

📒 Files selected for processing (2)
  • src/runtime/node/types.rs
  • test/js/node/fs/fs.test.ts

Walkthrough

mode_from_js now preserves special POSIX mode bits by masking with 0o7777. The filesystem tests add POSIX-only coverage for writeFileSync, chmod, and fchmod to verify those bits remain intact.

Changes

Special mode bits fix and tests

Layer / File(s) Summary
Mode mask update
src/runtime/node/types.rs
mode_from_js masks mode_int with 0o7777 instead of 0o777, retaining special POSIX bits in the resulting Mode.
Filesystem mode-bit tests
test/js/node/fs/fs.test.ts
POSIX-only tests cover writeFileSync, chmodSync/chmod, and fchmodSync/fchmod, asserting preserved special bits via statSync and fstatSync masked by 0o7777.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: preserving special POSIX mode bits in node:fs.
Description check ✅ Passed The description covers what changed and how it was verified, though its headings differ from the template.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/js/node/test/parallel/test-fs-chmod-mask.js`:
- Around line 91-141: This change adds Bun-specific special-bit assertions into
a vendored Node compatibility test, which should remain an upstream-matching
port. Remove the `testSpecialMode` block from the `fs.chmod`/`fs.fchmod` test in
`test-fs-chmod-mask` and keep that file unchanged as the Node reference. Move
the special-mode coverage into the Bun-owned `fs.test.ts` suite instead, using
the existing `fs`/`fchmod` behavior tests there to host the extra assertions.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 03f5e2d0-cf8c-4a20-8c6e-a3bd1af37402

📥 Commits

Reviewing files that changed from the base of the PR and between f789198 and 8d86391.

📒 Files selected for processing (3)
  • src/runtime/node/types.rs
  • test/js/node/fs/fs.test.ts
  • test/js/node/test/parallel/test-fs-chmod-mask.js

Comment thread test/js/node/test/parallel/test-fs-chmod-mask.js Outdated
@FuPeiJiang
FuPeiJiang force-pushed the fix-fs-mode-special-bits branch from 8d86391 to 9489175 Compare June 29, 2026 05:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/js/node/fs/fs.test.ts`:
- Around line 1736-1745: Add a `writeFileSync({ mode })` test case for the
octal-string input alongside the existing `writeFileSyncSyncWithSpecialMode`
coverage in `fs.test.ts`. The current `it.skipIf(isWindows)` test only verifies
the numeric mode branch, so extend that same test area to call `writeFileSync`
with a string mode value and assert the preserved POSIX bits via
`fs.statSync(...).mode & 0o7777`. Keep the test near the existing special-mode
case so the `writeFileSync` parser behavior is covered by the same suite.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a4b758e9-ad6f-498f-9a2e-7704bdec3731

📥 Commits

Reviewing files that changed from the base of the PR and between 8d86391 and 9489175.

📒 Files selected for processing (2)
  • src/runtime/node/types.rs
  • test/js/node/fs/fs.test.ts

Comment thread test/js/node/fs/fs.test.ts
@FuPeiJiang
FuPeiJiang force-pushed the fix-fs-mode-special-bits branch from 9489175 to ef751c6 Compare June 29, 2026 05:42
@robobun

robobun commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Thank you for catching this and sending a fix!

The & 0o777 mask that was stripping special POSIX mode bits was removed in #33072 (commit a8d0692) as part of a broader input-validation hardening pass. On current main, src/runtime/node/types.rs now returns Ok(Some(mode_int as Mode)) without masking, so setuid/setgid/sticky bits are preserved.

Closing as already fixed on main. Thanks again for the careful report and patch, and we hope to see more contributions from you!

@robobun robobun closed this Jul 31, 2026
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.

2 participants