You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(cache): atomic version-dir publish to close cache TOCTOU (DEVA11Y-482) (#32)
* fix(cache): atomic version-dir publish to close cache TOCTOU (DEVA11Y-482)
Extract the CLI into a unique staging directory and atomically rename it
into place instead of the check-delete-recreate sequence. Concurrent SPM
builds sharing ~/.cache can no longer wipe each other's in-progress
extraction; a build that loses the publish race reuses the winner's
fully-formed binary rather than running a partially-written one.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(review): correct nested-binary publish + harden publish race (DEVA11Y-482)
Review of PR #32 found a regression and residual races in the atomic-publish
change:
- P1: locateExecutable recurses, so a binary with the right name can sit in a
nested subdir; the old lastPathComponent check skipped relocating it, leaving
stagedExecutableURL/expectedExecutableURL pointing at a non-existent top-level
path (ensureExecutablePermissions would throw). Compare full standardized URLs
so any not-already-in-place binary is relocated.
- P2: the publish catch did a non-atomic fileExists->removeItem->moveItem that
could ENOENT-crash or fail a build when a peer republished concurrently. Make
removeItem best-effort and, on retry failure, reuse a peer's valid binary
instead of throwing.
- P3: reword the publishVersionDirectory doc to stop overstating atomicity of the
replace path; use UUID().uuidString for the staging suffix to match the file's
existing convention.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(review): resolve residual cache-publish findings (DEVA11Y-482)
Follow-up to the PR #32 review, closing the report-only findings:
- Staging leak (#4): extraction helpers exit() via forwardExit on failure and
SIGKILL bypasses defer, leaking .tmp.* staging dirs. Add sweepStaleStaging(),
a best-effort mtime-gated sweep (>1h old only, so a concurrent build's in-flight
staging is never deleted) run at the start of prepareArtifact.
- Cross-platform moveItem (#5): stop depending on moveItem's throw-on-existing
semantics (Darwin throws; POSIX rename silently replaces an empty dir). Check
versionDirectory existence explicitly; absent -> atomic rename, present ->
reuse/replace. Removes the untestable platform assumption.
- Windows archive (#6): download the .zip to a sibling temp file outside the
staging dir (with its own defer cleanup) so a failed removal can never bake the
archive into the published version directory; a leftover is swept later.
Not addressed here: binary integrity/signature verification (#7) is pre-existing,
needs a trusted out-of-band digest source, and belongs with APPSEC-415 — not this
TOCTOU fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
0 commit comments