fix(fs): write files atomically to avoid truncated concurrent reads - #798
fix(fs): write files atomically to avoid truncated concurrent reads#798lazerg wants to merge 4 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughChangesThe shared Node filesystem writer now writes through uniquely named temporary files, preserves existing permissions, renames atomically, and hides temporary entries. The Atomic filesystem writes
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Writer
participant writeFile
participant Filesystem
participant Reader
Writer->>writeFile: write data
writeFile->>Filesystem: write temporary file
writeFile->>Filesystem: rename temporary file to target
Reader->>Filesystem: read target
Filesystem-->>Reader: complete old or new value
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 `@src/drivers/utils/node-fs.ts`:
- Around line 20-23: Update readdirRecursive() to exclude only temporary files
matching the generated writeFile() pattern `*.<pid>.<UUID>.tmp` during recursive
key enumeration, while preserving user keys that merely end in `.tmp`;
alternatively, add a concurrent setItem/getKeys test that verifies these
in-progress files are omitted.
In `@test/drivers/fs.test.ts`:
- Around line 30-31: Update the concurrency read assertions in
test/drivers/fs.test.ts lines 30-31 and test/drivers/fs-lite.test.ts lines 29-30
to verify each buffer’s complete content is either all `a` or all `b`, rather
than checking length only; preserve the existing read loop and ensure
mixed-content buffers fail.
🪄 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 Plus
Run ID: a8641cb7-2430-40c0-a50b-7c3f2b658e75
📒 Files selected for processing (3)
src/drivers/utils/node-fs.tstest/drivers/fs-lite.test.tstest/drivers/fs.test.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/drivers/utils/node-fs.ts (1)
22-25: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winPreserve destination permissions when replacing files atomically.
writeFile()creates the temporary path with the default mode (0o666minus the umask), thenrename()replaces the existing destination. An existing restrictive file such as0600can end up as roughly0644after an overwrite. Capture and restore the destination’s mode before renaming, and cover this with a regression test.🤖 Prompt for 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. In `@src/drivers/utils/node-fs.ts` around lines 22 - 25, Update the atomic write flow using the temporary path and rename operation to capture the existing destination file mode and apply it to the temporary file before renaming, preserving restrictive permissions during replacement. Handle destinations that do not yet exist with the current creation behavior, and add a regression test verifying an overwrite retains the original mode.Source: MCP tools
🤖 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.
Outside diff comments:
In `@src/drivers/utils/node-fs.ts`:
- Around line 22-25: Update the atomic write flow using the temporary path and
rename operation to capture the existing destination file mode and apply it to
the temporary file before renaming, preserving restrictive permissions during
replacement. Handle destinations that do not yet exist with the current creation
behavior, and add a regression test verifying an overwrite retains the original
mode.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0b02ad41-0c88-4f5e-9fb5-9f82923f0903
📒 Files selected for processing (3)
src/drivers/utils/node-fs.tstest/drivers/fs-lite.test.tstest/drivers/fs.test.ts
|
Thanks, good catch. Fixed in 6d85e18 by reading the destination file's mode and applying it to the temp file before the rename, so an existing 0600 file keeps its permissions after an overwrite. Added a regression test to both the fs and fs-lite suites (skipped on Windows). |
There was a problem hiding this comment.
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 `@src/drivers/utils/node-fs.ts`:
- Around line 25-31: The destination mode lookup should suppress only an ENOENT
error. Update the fsPromises.stat(path) catch in the destination-mode flow to
rethrow all other filesystem errors, while retaining the existing undefined
result and chmod behavior when the destination is absent.
🪄 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 Plus
Run ID: d9ee1632-d4ff-400f-b28e-b45eff602c5d
📒 Files selected for processing (3)
src/drivers/utils/node-fs.tstest/drivers/fs-lite.test.tstest/drivers/fs.test.ts
writeFileopened the target withO_TRUNCand then streamed the data in, so agetItem/getItemRawrunning against the same key during a write could observe the file while it was still empty or half-written and return a truncated value. Writing to a temp file in the same directory and renaming it over the target makes the swap atomic, so a concurrent read sees either the old value or the new one.Fixes #797
Summary by CodeRabbit