Skip to content

Protect safeWriteText staging entry from replacement through commit #2391

Open

Description

@coderabbitai

Summary

Protect the caller-supplied staging file in src/services/file-safety/safeWriteText.ts against replacement between validation, opening, and publication.

At PR #2385 head b6a8e829b49a8e17d225c6849e9be659ab3a4324, the writer checks that tempPath is a regular file beside the target and does not alias the target. Another process that can modify the staging directory can replace that entry after validation. An early swap can make the writer open or change the mode of a different file. A later swap can make the rename or no-replace link publish a substituted entry instead of the staged content.

Required work

Choose and implement a mechanism that protects the validated staging object through opening and publication. Decide how the mechanism affects the caller-supplied tempPath contract and its cleanup behavior. A handle plus a separate identity check before a pathname-based commit does not, by itself, close the interval between that check and the commit. Consider the supported platforms and both ordinary rename and failIfExist publication.

Acceptance criteria

  • A staging entry replaced after validation cannot cause the writer to modify an unintended file or publish a substituted entry.
  • Cleanup does not remove an entry that the write does not own.
  • Add focused regression tests that exercise replacement before opening and between staging and publication, including the no-replace path.
  • Document any change to the tempPath contract and validate the chosen mechanism on supported platforms.

References

Activity

  1. easonLiangWorldedtech commented on Nov 10, 2026

    @easonLiangWorldedtech
    Contributor

    Reporting a failing row that belongs to this chain rather than opening a competing issue.

    Row: src/services/file-safety/tests/safeWriteText.integration.spec.ts > "publishes the new bytes and leaves no staging or backup residue" fails with DaclRestoreError, thrown from src/services/file-safety/safeWriteText.ts:587, reached through the step-5 restore call _restoreDaclWindows at 578.

    Where it reproduces, all on node v22.23.4 with vitest run from the package directory:

    • at 1913 head 44a862d and at its parent 8289534: same failure, including with this round's safeWriteJson.ts change removed, so it is not caused by that change. The combined nine-spec run at the head is 239 passed, 1 failed, 4 skipped out of 244, and the single failure is this row.
    • at main tip 18861b2: the row does not exist. Both the spec and safeWriteText.ts are absent there (git cat-file -e reports absent for each), and the run exits 1 with 10 log lines whose only substantive line is "No test files found, exiting with code 1". So this is a row inside the file-safety chain this series lands, not a defect that already sits on main.

    Search done before filing anything here, all scoped to open issues in this repository: DaclRestoreError (10 hits, among them #2392 Protect Windows DACLs throughout safeWriteText publication, #2402 safeWriteText reports post-commit failures only through the ..., #2385, #2357), DACL (28 hits, same leaders), direct-entry (127 hits, none about this primitive).

    Posting the row on this issue because it is the staging-entry protection home named by the lane lead, and naming #2392 and #2402 so the DACL restore failure itself is not re-filed a third time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions