docs(fs): document boundary guardrails
This commit is contained in:
parent
925dbfa29b
commit
c2e5849039
@ -6,10 +6,13 @@
|
||||
|
||||
- Reject `fileStore()` and `fileStoreSync()` writes through symlinked parent directories so store commits cannot escape the configured root.
|
||||
- Harden Root fallback mutators, archive merges, private store reads/writes, durable queue ids, JSON fallback writes, sibling temp writes, temp filename sanitization, and trash moves against symlink-swap and path traversal edge cases.
|
||||
- Centralize safe path segment validation, directory identity guards, and guarded mutation wrappers so future filesystem helpers reuse the same race-resistant checks.
|
||||
- Route JSON sync writes, archive ZIP staging, temp workspace sync reads, secret-file commits, and atomic move/replace fallbacks through shared pinned-read or guarded-write primitives.
|
||||
|
||||
### Tests
|
||||
|
||||
- Added regression coverage for the filesystem race and traversal findings fixed in this release.
|
||||
- Added a static filesystem-boundary primitive check that blocks reintroducing known raw copy/read/guard patterns.
|
||||
- Increased filesystem edge coverage around secure temp fallback handling, sibling-temp cleanup, local-root resolution, file locks, and file identity checks.
|
||||
- Prevented POSIX test runs from leaving Windows-style secure-temp fallback paths in the repository root.
|
||||
|
||||
|
||||
@ -68,7 +68,12 @@ If `beforeRename` throws, the rename is skipped and the temp file is removed —
|
||||
|
||||
### `EPERM` and copy fallback
|
||||
|
||||
On systems where `rename` fails with `EPERM`/`EEXIST`, pass `copyFallbackOnPermissionError: true` to fall back to copy + unlink. The fallback refuses symlink destinations before copying so it does not write through a replaced destination link.
|
||||
On systems where `rename` fails with `EPERM`/`EEXIST`, pass
|
||||
`copyFallbackOnPermissionError: true` to fall back to a non-atomic copy
|
||||
replacement. The fallback removes the old destination, opens the replacement
|
||||
with exclusive/no-follow flags where the platform supports them, and refuses
|
||||
known symlink destinations so it does not write through a replaced destination
|
||||
link.
|
||||
|
||||
### Sync variant
|
||||
|
||||
@ -117,9 +122,8 @@ Rename a path. If the rename fails with `EXDEV` (cross-device) or `EPERM`, fall
|
||||
import { movePathWithCopyFallback } from "@openclaw/fs-safe/atomic";
|
||||
|
||||
await movePathWithCopyFallback({
|
||||
source: "/srv/cache/blob.bin",
|
||||
destination: "/srv/persistent/blob.bin",
|
||||
overwrite: true,
|
||||
from: "/srv/cache/blob.bin",
|
||||
to: "/srv/persistent/blob.bin",
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@ -159,6 +159,16 @@ Run only the security boundary corpus while iterating on root/path/archive/temp
|
||||
pnpm test:security
|
||||
```
|
||||
|
||||
Run the static primitive guard after changing low-level filesystem helpers:
|
||||
|
||||
```sh
|
||||
pnpm lint:fs-boundary
|
||||
```
|
||||
|
||||
It catches the specific raw fallback patterns that previously led to
|
||||
check-then-use bugs, such as direct copy-to-destination fallback and sync temp
|
||||
workspace reads that bypass pinned file descriptors.
|
||||
|
||||
`pnpm check` also runs `pnpm lint:file-size`. New source and test files should stay under 500 lines. Existing larger files have explicit budgets in `scripts/check-file-size.mjs`; do not increase those budgets as part of unrelated work.
|
||||
|
||||
## See also
|
||||
|
||||
Loading…
Reference in New Issue
Block a user