Skip to content

fix(cache): isolate Windows BSD tar temporary files - #2497

Open
qmuntal wants to merge 6 commits into
actions:mainfrom
qmuntal:fix/cache-windows-bsdtar-isolation
Open

qmuntal wants to merge 6 commits into
actions:mainfrom
qmuntal:fix/cache-windows-bsdtar-isolation

Conversation

@qmuntal

@qmuntal qmuntal commented Sep 17, 2026

Copy link
Copy Markdown

Summary

The Windows BSD-tar/Zstandard fallback decompresses into a fixed cache.tar in the process working directory before listing or extracting it. Concurrent restores can overwrite that intermediate, causing both calls to read the same archive and report success while one cache is missing. Debug listings during cache saves use the same shared-file path.

The shared execReadCommands() helper gives each fallback list/extract operation its own temporary working directory. Cleanup is attempted in finally; cleanup failures are logged at debug level without replacing the read result or the original tool error. Archive and workspace paths are resolved and quoted before changing the child-process working directory, preserving relative paths and paths containing spaces. A fresh directory per operation also isolates archives stored in the same parent directory.

GNU tar, gzip, archive creation, cache keys, and archive formats are unchanged. The existing two-process workaround for Windows BSD tar's external-compressor hang is retained.

Validation

  • All 174 cache unit tests pass on Windows with Node.js 24.
  • New deterministic regressions cover concurrent extraction, concurrent listing, mixed extraction/listing, both Zstandard modes, relative paths containing spaces, preservation of unrelated files, cleanup after failures in either subprocess, and preservation of read results when cleanup itself fails.
  • All six concurrency regressions fail with the intended assertions against the original helper and pass with this fix.
  • Cache package compilation and targeted ESLint/Prettier checks pass.
  • A compiled-helper smoke test passed with real Windows BSD tar and real Zstandard-compressed data, including concurrent reads and cleanup after an actual tar failure. Node's native libzstd stood in for the unavailable Zstandard CLI in that smoke test.

Context

The fallback was introduced in #1237, and #1279 added --force to handle sequential reuse of the intermediate file. Neither isolates concurrent operations. This was discovered while investigating parallel module/build cache operations for actions/setup-go#630.

Run Windows BSD tar/zstd extraction and listing in private temporary
directories. Concurrent operations previously overwrote cache.tar in the
process working directory and could extract the wrong archive without
reporting an error. Debug listings during cache saves have the same race.

Resolve and quote archive and workspace paths before changing the child
working directory, and remove scratch files on success and failure.
Leave GNU tar, gzip, and the cache archive format unchanged.

Add deterministic regression tests for concurrent reads, relative paths
with spaces, and cleanup after failures in either subprocess.
Share the Windows BSD tar/zstd predicate and prepare archive and workspace
arguments once per command. Parameterize duplicate BSD-tar read tests and
use the real temporary-directory utilities in the concurrency fixture.

Retain the existing concurrency, path-handling, and failure coverage.
Restore the existing helper layout and separate test cases rather than
bundling unrelated consolidation with the bug fix. Leave archive creation
unchanged and retain only the read isolation, necessary path handling,
and regression coverage.
@qmuntal
qmuntal marked this pull request as ready for review September 17, 2026 14:31
@qmuntal
qmuntal requested a review from a team as a code owner September 17, 2026 14:31
Copilot AI lite review requested due to automatic review settings September 17, 2026 14:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Cleanup failures should be handled best-effort without masking successful operations or original tool errors.

Review effort: Lite
Findings: None

What changed in this PR

This PR isolates Windows BSD tar/Zstandard fallback operations to prevent concurrent cache restore and listing collisions.

Changes:

  • Creates per-operation temporary directories with cleanup.
  • Resolves and quotes archive and workspace paths.
  • Adds concurrency, path, and failure-cleanup regression tests.
File Description
packages/​cache/​src/​internal/​tar.ts Implements isolated fallback execution.
packages/​cache/​__tests__/​tarConcurrency.test.ts Adds concurrency and cleanup coverage.
packages/​cache/​__tests__/​tar.test.ts Updates temporary-directory and quoting expectations.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@qmuntal
qmuntal marked this pull request as draft September 17, 2026 14:53
@Link-
Link- marked this pull request as ready for review September 17, 2026 14:53
Link-
Link- previously approved these changes Sep 17, 2026
Keep execCommands as a plain executor that honors its cwd argument. Move
scratch-directory allocation and cleanup into a shared list/extract
helper, leaving archive creation on the caller-supplied directory.
Log scratch-directory cleanup failures without replacing a successful
archive read or the original tool error. Keep scratch ownership in
execReadCommands and cover both outcomes for extraction and listing.
@qmuntal
qmuntal requested a review from Link- September 18, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants