docs: document filesystem hardening

This commit is contained in:
Peter Steinberger 2026-05-06 20:57:25 +01:00
parent 948a696af6
commit 039e3aa0c8
No known key found for this signature in database
3 changed files with 12 additions and 2 deletions

View File

@ -5,9 +5,11 @@
### Fixes
- 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.
### Tests
- Added regression coverage for the filesystem race and traversal findings fixed in this release.
- 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.

View File

@ -60,6 +60,10 @@ await writeJsonDurableQueueEntry({
const pending = await loadPendingJsonDurableQueueEntries({ queueDir, tempPrefix: "queue" });
```
`id` must be a single safe path segment: non-empty, not dot-prefixed, and made
from letters, numbers, `_`, `-`, and `.`. Slashes, backslashes, NUL bytes, `.`,
and `..` are rejected.
Use `ackJsonDurableQueueEntry()` after durable processing succeeds and
`moveJsonDurableQueueEntryToFailed()` when the caller wants to quarantine an
entry for inspection.

View File

@ -177,7 +177,9 @@ const result = await writeSiblingTempFile<string>({
### `writeViaSiblingTempPath`
A higher-level convenience — write content + rename in one call:
A higher-level convenience for callback-based producers. The callback writes to
a private temp path, then the helper copies the result into `targetPath` through
the root boundary:
```ts
import { writeViaSiblingTempPath } from "@openclaw/fs-safe/advanced";
@ -191,7 +193,9 @@ await writeViaSiblingTempPath({
});
```
If `replaceFileAtomic` does what you need, prefer that — `writeViaSiblingTempPath` is the lower-level building block.
If `replaceFileAtomic` does what you need, prefer that. Use
`writeViaSiblingTempPath` when the producer needs a concrete temp pathname but
the final destination still needs root-boundary checks.
## Secure temp root