Commit Graph

71 Commits

Author SHA1 Message Date
Peter Steinberger
393f980ad3
test: stabilize directory guard coverage
Some checks failed
ci / Lint workflows (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (22, macos-latest) (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (22, ubuntu-latest) (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (22, windows-latest) (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (24, macos-latest) (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (24, ubuntu-latest) (push) Has been cancelled
ci / Node ${{ matrix.node }} check (${{ matrix.os }}) (24, windows-latest) (push) Has been cancelled
coverage / Node 22 coverage (push) Has been cancelled
2026-05-08 12:29:15 +01:00
Peter Steinberger
66a4dfba0e
fix: isolate prepack types and secret symlink reads 2026-05-08 08:41:57 +01:00
Peter Steinberger
36dd0888a3
fix(root): align pinned fallback path boundary checks 2026-05-08 02:43:24 +01:00
Sarah Fortune
ecefc5bd53 test: avoid windows 8.3 short-name diff in realpath assertions
On windows fs.realpathSync and fs.realpath (async) can disagree on
8.3 short-name canonicalization. The github actions windows runner
exposes this: fs.realpathSync returns "C:\Users\RUNNER~1\..."
while fs.realpath returns "C:\Users\runneradmin\...". Tests that
compare a sync helper's output against await fs.realpath fail with
the same path printed in two forms.

Compare against fs.realpathSync (imported as realpathSync from
node:fs) on both sides so the test exercises the same canonical
form regardless of which short-name configuration the runner has.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:23:32 -07:00
Sarah Fortune
4a1e5d8b72 fix(root): drop spurious ".." prefix rejection on posix write path
The posix write helper rejected any path whose computed
path.relative(root, resolved) string-began with "..", even when the
resolved path was fully inside the root. That matched literal
filenames whose first segment merely starts with the two characters
".." (e.g. "..%2fpwned.txt", "..%00/pwned.txt") and produced an
"outside-workspace" error for paths that do not actually escape
the root. The real boundary is already enforced upstream by
resolvePathInRoot's path.resolve + isPathInside check, so the
extra startsWith("..") guard added no security value while
introducing platform divergence (windows did not have it). Drop the
guard, keep the path.isAbsolute check.

Recategorize the three former SAFE_REJECTED_SUSPICIOUS_WRITE_PAYLOADS
test inputs so the test reflects what each platform actually does:

- "..%2fpwned.txt" and "..%00/pwned.txt" are literal names that
  resolve fully inside root on both platforms; move them to
  LITERAL_SUSPICIOUS_WRITE_PAYLOADS (accepted everywhere).
- "..\pwned.txt" is a real traversal on windows where "\\" is a
  separator, but a literal filename on posix where "\\" is a regular
  name character; move it to POSIX_LITERAL_SUSPICIOUS_WRITE_PAYLOADS
  (accepted on posix, rejected on windows).

The literal-directory check in the same test uses fsp.stat on
windows since safeRoot.list goes through the pinned helper that is
unavailable on win32, matching the pattern already used a few lines
up. Bump the per-test timeout to 15s for slow windows fs under
parallel test load.

Drop a stale explanatory comment in expandHomePrefix.

After: 254 passed, 0 failed, 66 skipped on windows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 16:16:50 -07:00
Sarah Fortune
3be7ba6ee3 ci+test: run check on windows and guard windows-only test behavior
Run the check job on windows-latest in addition to ubuntu so the
windows code paths (no O_NOFOLLOW, node fallbacks for fd-relative
ops, ACL inspection) are exercised on every PR rather than only
documented.

Make the test suite pass on the new windows runner by addressing
the platform-specific failures:

- Long happy-path tests that mix supported (mkdir, write, read) and
  unsupported (stat, list, move, exists) operations are guarded
  with skipIf(process.platform === "win32") since the pinned
  filesystem helper throws "unsupported-platform" on win32 by
  design (src/pinned-python.ts).
- Short focused tests where the unsupported operation is the whole
  point (pinned-python, pinned-write-fallback-coverage,
  write-boundary-bypass symlink-move) split into runIf(non-win32)
  and runIf(win32) tests, with the windows variant asserting
  unsupported-platform.
- The expectFsSafeCode helper accepts unsupported-platform on
  windows; new expectedFsSafeCode helper substitutes for
  per-rejects.toMatchObject sites where the windows code differs
  from posix (e.g. path-alias / not-found returning
  unsupported-platform via the helper layer).
- secure-file-reads test split into a posix happy-path runIf and a
  windows runIf that asserts permission-unverified, since ACL
  inspection has no portable equivalent on windows
  (src/secure-file.ts:177).
- safeFileURLToPath test uses hardcoded platform-specific input/
  output instead of building the URL via pathToFileURL+fileURLToPath
  so the assertion verifies the function directly.
- Fix expandHomePrefix to normalize path separators by splitting via
  path.normalize + path.sep and rejoining via path.join. Apply the
  same segment-based check to resolveHomeRelativePath and
  resolveOsHomeRelativePath. Drop input.trim() — whitespace is a
  valid filename character on both platforms and env-var inputs are
  already trimmed upstream via normalizeOptionalString.
- coverage-more's "normalizes empty temp names" decomposes the
  result with path.dirname/path.basename instead of regex-matching
  a path-separator literal.
- extracted-helpers' path-helpers test builds its root with
  path.resolve so the drive letter is present on windows.
- additional-boundary-bypass guards its "..\evil.txt" sanitizer
  assertion behind a non-win32 check (windows reserves "\" as a
  path separator and cannot have it in a filename).
- coverage-more's sibling temp test guards just the posix file-mode
  assertion (stat.mode & 0o777 === 0o600), which has no analog on
  windows. The syncing behaviour the test actually targets still
  runs on both platforms.
- Raise test/new-primitives.test.ts size budget to 1500 to
  accommodate the secure-file-reads test split.

After: 253 passed, 1 failed, 66 skipped on windows-11-arm64. The
single remaining failure is a separate library-side gap (a
SAFE_REJECTED_SUSPICIOUS_WRITE_PAYLOADS payload resolves on windows
instead of rejecting) and will be tracked in a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 14:59:24 -07:00
Peter Steinberger
a431bfc3b8
fix: harden absolute directory segment validation 2026-05-07 10:52:57 +01:00
Peter Steinberger
fb06663ac6
test: split absolute directory regressions 2026-05-07 10:36:15 +01:00
Peter Steinberger
f9e3d30d2d
refactor: structure absolute directory failures 2026-05-07 10:32:16 +01:00
jesse-merhi
aa02b4fa42
fix: guard absolute directory races 2026-05-07 10:29:16 +01:00
jesse-merhi
509076b3a2
docs: document absolute directory helper 2026-05-07 10:29:15 +01:00
jesse-merhi
e91134e92f
feat: add absolute directory ensure helper 2026-05-07 10:29:15 +01:00
sallyom
e335490a5b
add non-durable atomic write option
Signed-off-by: sallyom <somalley@redhat.com>
2026-05-07 10:26:06 +01:00
Peter Steinberger
71ec9f4c10
fix: detect stale move fallback sources 2026-05-07 10:17:11 +01:00
Peter Steinberger
354ba8e4c9
fix: preserve concurrent move fallback writes 2026-05-07 08:58:42 +01:00
Peter Steinberger
c382eafdb2
fix: fail closed on stale sidecar locks 2026-05-07 08:02:36 +01:00
Peter Steinberger
02897e6879
fix: harden filesystem read and temp paths 2026-05-07 08:02:25 +01:00
Peter Steinberger
ce4137f028
test: harden external output coverage 2026-05-07 04:34:31 +01:00
Peter Steinberger
b57002a6a1 fix: preserve external output path spelling (#7) (thanks @jesse-merhi)
Some checks are pending
ci / Node 22 check (push) Waiting to run
coverage / Node 22 coverage (push) Waiting to run
pages / Deploy docs (push) Waiting to run
2026-05-07 03:05:05 +01:00
jesse-merhi
cfda97c828 test: cover external output traversal rejection 2026-05-07 03:05:05 +01:00
jesse-merhi
f4a7bb1a65 feat: add safe external output writer 2026-05-07 03:05:05 +01:00
Peter Steinberger
85f5b55050
fix(fs): close fallback mkdir and archive cleanup races 2026-05-07 00:19:59 +01:00
Peter Steinberger
b8f079c999
fix(store): preserve sync read validation failures 2026-05-06 23:53:33 +01:00
Peter Steinberger
261ca3cbc0
fix(fs): preserve prune and trash fallback behavior 2026-05-06 23:05:13 +01:00
Peter Steinberger
d27434b50c
fix(fs): avoid unsafe guarded cleanup paths 2026-05-06 22:32:09 +01:00
Peter Steinberger
70fdf86fde
fix(fs): close guarded fallback handles on post-check failure 2026-05-06 22:22:48 +01:00
Peter Steinberger
5218746972
fix(temp): preserve workspace leaf filename contract 2026-05-06 21:54:15 +01:00
Peter Steinberger
f305c8be2b
fix(fs): preserve public path modes in guard refactor 2026-05-06 21:31:04 +01:00
Peter Steinberger
925dbfa29b
test(fs): cover centralized boundary regressions 2026-05-06 21:21:40 +01:00
Peter Steinberger
948a696af6
test: cover filesystem finding regressions 2026-05-06 20:57:25 +01:00
Peter Steinberger
91f7b74ad6
feat: add root JSON and durable queue helpers 2026-05-06 06:27:23 +01:00
jesse-merhi
9cbee5d1b7 test: rename boundary bypass suites 2026-05-06 14:42:49 +10:00
Peter Steinberger
60e0390332
chore: release 0.1.2 2026-05-06 04:51:16 +01:00
Peter Steinberger
61fadb4365
test: increase filesystem edge coverage 2026-05-06 04:33:06 +01:00
Peter Steinberger
56abb17dc9
test: stabilize coverage corpus 2026-05-06 04:19:51 +01:00
Peter Steinberger
0cfde5c5f4
test: increase edge coverage 2026-05-06 04:17:16 +01:00
Peter Steinberger
a6149c2cee
fix: harden file store writes 2026-05-06 04:12:15 +01:00
Peter Steinberger
cc0757aa82
refactor: split root internals and security test helpers 2026-05-06 03:29:31 +01:00
Peter Steinberger
90ffaf5168
fix: harden root path validation 2026-05-06 03:04:45 +01:00
Peter Steinberger
695710c479
fix: harden archive destination merge 2026-05-06 02:29:42 +01:00
Peter Steinberger
837e37259f
chore: release fs-safe 0.1.0 2026-05-06 01:52:28 +01:00
Peter Steinberger
2e83f7d9b9
refactor: narrow low-level lock and pinned-open surface 2026-05-06 01:43:39 +01:00
Jesse Merhi
c70178e7e1
test: add additional bypass parity coverage (#3) 2026-05-06 01:33:25 +01:00
Peter Steinberger
02b9a9d2ae
refactor: trim temp workspace surface 2026-05-06 01:26:06 +01:00
Peter Steinberger
542657b9d2
refactor: back temp workspaces with file stores 2026-05-06 01:17:03 +01:00
Peter Steinberger
b9434cd363
refactor: bind json state to file stores 2026-05-06 00:53:09 +01:00
Peter Steinberger
32acf97225
refactor: unify private file store 2026-05-06 00:37:14 +01:00
Peter Steinberger
e210a26af2
feat: unify store helpers 2026-05-06 00:07:28 +01:00
Peter Steinberger
ff2e84aaea
feat: add persistent fs-safe python helper 2026-05-05 23:25:07 +01:00
Peter Steinberger
bd2749649a
refactor: align atomic and secret helpers 2026-05-05 22:37:01 +01:00