Skip to content

install: stop leaking the displaced cache folder when a tarball is re-extracted - #38702

Open
robobun wants to merge 4 commits into
mainfrom
farm/b721afae/tarball-cache-staging-leak
Open

install: stop leaking the displaced cache folder when a tarball is re-extracted#38702
robobun wants to merge 4 commits into
mainfrom
farm/b721afae/tarball-cache-staging-leak

Conversation

@robobun

@robobun robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • Every bun install without a lockfile that has a file: or URL tarball dependency already in the cache leaves one fully extracted copy of that tarball behind in the install temp dir (<cache>/.tmp/.<hex>-1.<name>/, or $TMPDIR when that is on the cache's filesystem). N installs leave N-1 copies; the install exits 0.
  • Without a lockfile the tarball is always re-extracted (its package.json is what resolves it). move_to_cache_directory (src/install/extract_tarball.rs) publishes the staging dir with renameat_concurrently: RENAME_NOREPLACE fails because the folder exists, so it falls back to RENAME_EXCHANGE, which swaps the old folder out under the staging name. Nothing deletes it. The step "2b" described in the comment there never had code behind it (the line that was meant to do it in Make duplicate simultaneous bun install work better #9738 ran before the rename, against a variable that was still false).
  • The same happens for https:// tarballs, through both the buffered and the streaming extractor, since both end in move_to_cache_directory.

Fix

  • ExtractTarball::cache_publish() decides, before extraction starts, how the result will be published, and the buffered path (extract) and the streaming path (TarballStream::init) pass that decision to move_to_cache_directory as CachePublish:
    • Supersede: the folder name was already taken when the task started, so this is a re-extraction of the tarball. The fresh copy is swapped in as before, and the folder it displaced is deleted from the temp dir. This is the case in the report, and it keeps the current behaviour that a repacked tarball wins once the lockfile is removed.
    • KeepExisting: the name was free when the task started. If it is taken by the time the rename happens, a concurrent install extracted the same tarball first; its folder may already be copied from, so it is kept and our staging copy is deleted. renameat_concurrently gets a keep_existing_destination option for this, and the Windows arm of move_to_cache_directory does the equivalent on its existing-destination errors. Previously this case replaced the other install's folder (POSIX: swap and leak it; Windows: delete it, which is Windows: parallel bun install --no-cache with shared BUN_INSTALL_CACHE_DIR can fail with ENOENT opening cache/package/version dir #28062).
    • Replace: npm and GitHub folders, unchanged. Their swapped-out folder is still left alone because nothing there can tell a race from a re-extraction; the open PRs listed below deal with those.
  • The decision has to be made before extracting because the only thing distinguishing the two cases is whether the folder predates this extraction. A tarball folder is named after the hash of its path or URL (@T@<hash>@@@1), not its contents, so the contents of an existing folder say nothing (Tag::is_tarball documents this).
  • After the move, anything still under the staging name is deleted whenever it is safe to do so: the superseded folder, or our own copy after a lost race or a failed move. A swapped-out folder in Replace mode is the one thing that is not.
  • Verified with:
    • test/cli/install/bun-install-tarball-integrity.test.ts, two new tests (file: tarball, tarball URL): three installs without a lockfile must leave the temp dir empty and one @T@ folder, and a repacked tarball must be the version installed afterwards. On the current build both fail with two .<hex>-1.pkg dirs left in the temp dir. The URL test serves a 256 KiB tarball in chunks without a Content-Length, and --verbose shows Streamed for all of its installs, so it covers the streaming extractor's half of the plumbing.
    • The reproduction from the report (below) with the debug build: 5 installs, 0 dirs left.
    • New bun_sys unit test for keep_existing_destination (destination kept, source removed; free destination renames normally).
    • bun-install-streaming-extract, bun-add, bun-patch, bun-install-patch, bun-install-git-deps, the tarball/github/cache subset of bun-install.test.ts (one test in it needs network access and fails identically without this change), and the rest of bun-install-tarball-integrity pass with the debug build. cargo check for bun_sys/bun_install passes on Linux and x86_64-pc-windows-msvc; clippy is clean.
  • RenameatConcurrentlyOptions gained a field, so the struct literals in patchPackage.rs and repository.rs now spell out the defaults; their behaviour is unchanged.

Related open PRs

Background

  • Cache publishing: a tarball is extracted into a randomly named staging dir in the install temp dir (chosen to be on the same filesystem as the cache) and then renamed onto its final cache folder, so a cache folder is either absent or complete.
  • renameat_concurrently (src/sys/lib.rs): tries renameat2(RENAME_NOREPLACE), then RENAME_EXCHANGE (atomically swaps source and destination, leaving the old destination under the source name), then delete_tree + rename. Since Make duplicate simultaneous bun install work better #9738 the exchange is what makes two installs sharing a cache not fail each other; the swapped-out folder is left because the other install may still be reading it.
  • @T@ folders: file: and URL tarballs are cached under a hash of the path or URL string (cached_tarball_folder_name_print), so the same folder holds whatever was last extracted from that path. npm folders (name@version) and GitHub folders (resolved commit) are keyed by content identity instead, which is why the race-oriented PRs above can treat an existing folder as equivalent for those but not for tarballs.
  • Streaming extractor (TarballStream.rs): for larger or chunked downloads the tarball is extracted while it downloads; it shares move_to_cache_directory with the buffered path, which is why the publish decision is captured in TarballStream::init (on the main thread, when the download is queued) and in extract for the buffered path.
Reproduction from the report
d=$(mktemp -d); cd "$d"; export BUN_INSTALL_CACHE_DIR="$d/cache"
mkdir -p pkg app
printf '{"name":"tdep","version":"0.0.1","main":"i.js"}' > pkg/package.json; echo 'module.exports=1' > pkg/i.js
head -c 3000000 /dev/urandom > pkg/big.bin
tar czf tdep.tgz --transform 's,^pkg,package,' pkg
printf '{"name":"app","dependencies":{"tdep":"file:../tdep.tgz"}}' > app/package.json
cd app
for i in 1 2 3 4 5; do
  rm -rf node_modules bun.lock; bun install >/dev/null 2>&1
  echo "install #$i: $(ls -A ../cache/.tmp 2>/dev/null | wc -l) staging dirs"
done

Before (1.4.0-canary, b7a043103): 0, 1, 2, 3, 4 staging dirs (in $TMPDIR when it shares a filesystem with the cache, otherwise cache/.tmp). After: 0 every time, and the @T@ folder holds the latest extraction.

The leaked dir holds the previous cache contents, not the new extraction: repack tdep.tgz between two lockfile-less installs and the leaked copy has the old files while the cache folder has the new ones.


[review] gate passed · iteration 3 · 7 files touched

fails on main (without fix)
ASAN without fix: 2 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-install-tarball-integrity.test.ts
bun test v1.4.0 (0613908c0)

test/cli/install/bun-install-tarball-integrity.test.ts:
(pass) tarball integrity > should store integrity hash for local tarball in text lockfile [300.04ms]
(pass) tarball integrity > should store integrity hash for tarball URL in text lockfile [389.67ms]
(pass) tarball integrity > should install successfully from text lockfile without integrity hash (backward compat) [395.62ms]
(pass) tarball integrity > should add integrity hash to lockfile when re-resolving tarball dep [206.05ms]
(pass) tarball integrity > should fail integrity check when tarball URL content changes [554.78ms]
(pass) tarball integrity > should store consistent integrity hash for tarball URL across reinstalls [726.04ms]
(pass) tarball integrity > should install successfully from text lockfile without integrity hash for local tarball (backward compat) [274.54ms]
(pass) tarball integrity mismatch (hoisted) > should fail (not hang) when tarball bytes don't match manifest SHA-512 [414.04m
... (truncated)

release without fix: 2 FAILED
bun test v1.4.0-canary.1 (b7a043103)

test/cli/install/bun-install-tarball-integrity.test.ts:
(pass) tarball integrity > should store integrity hash for local tarball in text lockfile [59.82ms]
(pass) tarball integrity mismatch (hoisted) > should fail (not hang) when tarball bytes don't match manifest SHA-512 [66.65ms]
(pass) tarball integrity metadata forms > verifies the tarball when the integrity entry carries an option suffix [51.72ms]
(pass) tarball integrity metadata forms > verifies the tarball against the strongest entry of a multi-hash integrity string [59.91ms]
(pass) tarball integrity mismatch (isolated) > should fail (not hang) when tarball bytes don't match manifest SHA-512 [63.55ms]
(pass) tarball integrity > should add integrity hash to lockfile when re-resolving tarball dep [74.78ms]
(pass) tarball integrity > should store integrity hash for tarball URL in text lockfile [79.84ms]
(pass) tarball integrity metadata forms > records the strongest entry of a multi-hash integrity string in the lockfile [57.99ms]
(pass) tarball integrity > should install successfully from text lockfile without integrity hash (backward compat) [74.99ms]
(pass) tarball integr
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-install-tarball-integrity.test.ts
bun test v1.4.0 (0613908c0)

test/cli/install/bun-install-tarball-integrity.test.ts:
(pass) tarball integrity > should store integrity hash for local tarball in text lockfile [307.36ms]
(pass) tarball integrity > should store integrity hash for tarball URL in text lockfile [370.21ms]
(pass) tarball integrity > should install successfully from text lockfile without integrity hash (backward compat) [380.74ms]
(pass) tarball integrity > should add integrity hash to lockfile when re-resolving tarball dep [184.72ms]
(pass) tarball integrity > should fail integrity check when tarball URL content changes [517.92ms]
(pass) tarball integrity > should install successfully from text lockfile without integrity hash for local tarball (backward compat) [199.20ms]
(pass) tarball integrity > should store consistent integrity hash for tarball URL across reinstalls [733.56ms]
(pass) tarball integrity > should store consistent integrity hash for local tarball across reinstalls [501.27ms]
(pass) tarba
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped)
  target       linux-x64-gnu
  build type   Release
  build dir    ./build/release
  revision     0613908c0f
  features     baseline

22 deps, 123 codegen, 1176 objects in 1159ms

ninja: Entering directory `/workspace/bun/build/release'
[1/1238] gen ErrorCode+*.h
[2/1238] install /workspace/bun
bun install v1.4.0-canary.1 (b7a043103)

Checked 107 installs across 153 packages (no changes) [13.00ms]
[3/1238] gen bindgenv2
[4/1238] fetch tinycc
[tinycc] up to date
[5/1237] install /workspace/bun/packages/bun-error
bun install v1.4.0-canary.1 (b7a043103)

Checked 1 install across 2 packages (no changes) [1.00ms]
[6/1237] fetch zlib
[zlib] up to date
[7/1237] gen ProcessBindingConstants.lut.h
Generating /workspace/bun/build/release/codegen/ProcessBindingConstants.lut.h from /workspace/bun/src/jsc/bindings/ProcessBindingConstants.cpp
[8/1237] install /workspace/bun/src/node-fallbacks
bun install v1.4.0-canary.1 (b7a043103)

Checked 129 installs across 147 packages (no changes) [20.00ms]
[9/1237] fetch libjpeg-turbo
[libjpeg-turbo] up to date
[10/1237] gen JSBuffer.lut.h
Generating /worksp
... (truncated)
diff hotspot
src/install/PackageManager/patchPackage.rs         |   7 +-
 src/install/TarballStream.rs                       |   6 +
 src/install/extract_tarball.rs                     | 116 +++++++++----
 src/install/repository.rs                          |   4 +-
 src/install/resolution.rs                          |   6 +
 src/sys/lib.rs                                     |  82 +++++++++-
 .../install/bun-install-tarball-integrity.test.ts  | 182 ++++++++++++++-------
 7 files changed, 303 insertions(+), 100 deletions(-)

gate history · 2 passed · 0 rejected · iteration 3

evidence per changed file
file                                                    reads  edits  tests
src/install/PackageManager/patchPackage.rs                  1      0      0
src/install/TarballStream.rs                                4      6      0
src/install/extract_tarball.rs                              5      9      0
src/install/repository.rs                                   2      1      0
src/install/resolution.rs                                   2      3      0
src/sys/lib.rs                                              4      9      0
test/cli/install/bun-install-tarball-integrity.test.ts      6      9      0

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 1 minute

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c5ebffb0-3a42-424b-adb2-df9c3aa2694f

📥 Commits

Reviewing files that changed from the base of the PR and between 9805144 and 0613908.

📒 Files selected for processing (7)
  • src/install/PackageManager/patchPackage.rs
  • src/install/TarballStream.rs
  • src/install/extract_tarball.rs
  • src/install/repository.rs
  • src/install/resolution.rs
  • src/sys/lib.rs
  • test/cli/install/bun-install-tarball-integrity.test.ts

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Status: reproduced and fixed; CI is green on every lane that exercises the change.

  • Reproduced on 1.4.0-canary.1+b7a043103 with the script in the PR description: 5 lockfile-less installs of a file: tarball left 4 extracted copies in the temp dir. The two new tests in test/cli/install/bun-install-tarball-integrity.test.ts fail the same way on that build (2 dirs left after 3 installs) and pass with this branch.
  • https://buildkite.com/bun/bun/builds/96940 (same tree as ab7e2691 plus an empty commit): 177 of 179 jobs passed, including Windows 2019 x64 and Debian x64-asan, the two lanes that did not complete in the first run (https://buildkite.com/bun/bun/builds/96684, where the Windows lane got no agent and x64-asan failed on two vendor/elysia tests this diff does not touch; those did not recur). The remaining two jobs are the macOS 14 aarch64 test lane, which expired waiting for an agent and was re-queued; the same lane passed in 96684. The only other items in 96940 are two install tests on Debian x64 whose local registry failed to start and which passed on retry.
  • Review follow-ups are in (stdout drained in the test helper, docs trimmed); the automated re-review found nothing further.
  • Open item for a maintainer: whether CachePublish (replace a tarball folder that predates the extraction, keep one that appeared during it, npm/GitHub unchanged) is the shape the other open PRs on this publish step should build on. They are listed in the description.

@github-actions

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. install: don't leak package extraction temp directories into $TMPDIR #33979 - Same root cause and same fix shape: it also blames the RENAME_EXCHANGE fallback in move_to_cache_directory for stranding the displaced tree under the staging name, and adds the identical keep_existing_destination field to RenameatConcurrentlyOptions in src/sys/lib.rs — unconditionally for all package kinds, where this PR gates it on CachePublish.
  2. install: fix ENOENT race on shared cache when RENAME_EXCHANGE is unsupported (NFS) #36229 - Rewrites the same POSIX arm of move_to_cache_directory and the same renameat_concurrently fallback chain to first-wins (keep the existing cache folder, delete the staging dir), i.e. the same publish-collision decision this PR encodes as CachePublish::KeepExisting.
  3. install: never delete a concurrently published cache entry on Windows #33884 - Rewrites the Windows arm of move_to_cache_directory to accept an existing destination instead of renaming it aside and deleting it, for the same referenced issue Windows: parallel bun install --no-cache with shared BUN_INSTALL_CACHE_DIR can fail with ENOENT opening cache/package/version dir #28062 as this PR's Windows branch.

🤖 Generated with Claude Code

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Not a duplicate of those three, though they all touch the same publish step (see "Related open PRs" in the description):

The bug fixed here (one extracted copy left behind per lockfile-less install, single process, no race) is not fixed by any of them as written.

Comment thread test/cli/install/bun-install-tarball-integrity.test.ts Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/extract_tarball.rs Outdated
Comment thread src/install/resolution.rs Outdated
Comment thread src/sys/lib.rs Outdated
Comment thread src/sys/lib.rs Outdated
Comment thread src/sys/lib.rs Outdated
Comment thread src/install/extract_tarball.rs
Comment thread src/install/extract_tarball.rs
Comment thread src/install/extract_tarball.rs
Comment thread src/install/extract_tarball.rs
Comment thread src/install/extract_tarball.rs
Comment thread src/install/resolution.rs
Comment thread src/sys/lib.rs
Comment thread src/sys/lib.rs
Comment thread src/sys/lib.rs
@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Review bot follow-ups, in f135318 and ab7e269:

  • installFresh now drains stdout as well and asserts the combined { stdout, stderr, exitCode }.
  • The docs on CachePublish, Tag::is_tarball and the new rename option were cut down to the one fact each of them carries. The remaining flagged comments are those two or three line docs; the reasoning behind the design stays in the description rather than in the code.

No behaviour change in either commit.

@claude claude Bot 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.

I re-reviewed after the follow-up commits and didn't find any bugs — the earlier stdout-drain nit is addressed. Given this touches cache-publish semantics that four open PRs (#33979, #36229, #33884, #31868) are also reworking, a maintainer sign-off on the CachePublish design would be worthwhile.

What was reviewed:

  • cache_publish() computes the same @T@ folder name as move_to_cache_directory (both go through cached_tarball_folder_name_print on self.url), so the pre-check and the rename target agree.
  • Cleanup matrix after the rename: for every (Replace/Supersede/KeepExisting × ok/err × POSIX/Windows) combination the temp name ends up deleted or intentionally kept; Replace+ok is the only case left alone, matching prior npm/GitHub behaviour.
  • RenameatConcurrentlyOptions::default() in repository.rs and the ..Default::default() additions in patchPackage.rs/move_file_z keep the old field values, so those callers are unchanged.
Extended reasoning...

Overview

The PR fixes a temp-dir leak where re-extracting a file:/URL tarball over its existing cache folder swaps the old folder out under the staging name and never deletes it. It introduces a three-way CachePublish enum (Replace/Supersede/KeepExisting), computed before extraction from whether the target cache folder already exists, threads it through both the buffered (extract) and streaming (TarballStream::init) paths into move_to_cache_directory, and adds a keep_existing_destination flag to renameat_concurrently. Struct-literal call sites in patchPackage.rs and repository.rs gain ..Default::default() with no behaviour change. Two integration tests and one bun_sys unit test cover the new paths.

Security risks

None identified. The change deletes the process's own staging directory (a randomly-named child of the install temp dir) or a swapped-out cache folder under names Bun itself generated; no user-controlled path is fed to delete_tree. keep_existing_destination only deletes the from path the caller already owned.

Level of scrutiny

Medium-high. The mechanical change is small, but it encodes a design decision about what happens on cache-folder collisions (replace-and-delete vs keep-existing) that differs by resolution kind and is deliberately positioned relative to four other open PRs touching the same publish step. The Supersede branch newly deletes a folder that was previously left alone, and the Windows arm gains a new early-break on KeepExisting. That is package-manager-cache-correctness territory where a maintainer familiar with the concurrent-install history (#9738, #28062) should confirm the direction.

Other factors

  • My previous inline comment (stdout not drained in installFresh) was addressed in f135318; the comment-cop feedback was addressed in ab7e269.
  • I traced cache_publish() against move_to_cache_directory's folder-name computation for the tarball tags and they agree (same helper, same self.url input, same None patch hash). The thread-local buffer borrow in cache_publish() is released before extract() re-borrows it later, and TarballStream::init runs on a different thread from populate_result, so there is no TL_BUFS aliasing.
  • The post-rename cleanup if moved.is_err() || publish != CachePublish::Replace { delete_tree(tmpname) } was checked against every mode/outcome combination on both the POSIX (renameat_concurrently with the new option) and Windows (retry loop with the new break) arms; each either deletes the intended tree or is a harmless no-op on an already-gone name.
  • move_file_z and repository::CacheStaging::publish keep keep_existing_destination: false via Default, so the new deletion path is not reached by existing callers.
  • The tests look sound (drain both pipes, assert the combined object, hermetic temp dirs, local server on port 0, streaming path forced by chunked incompressible payload).

Deferring rather than approving because the design overlaps with several in-flight PRs on the same function and a human should confirm this is the shape the maintainers want the others to compose with.

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 10:05 PM PT - Aug 14th, 2026

@robobun, your commit 0613908 has some failures in Build #96940 (All Failures)


🧪   To try this PR locally:

bunx bun-pr 38702

That installs a local version of the PR into your bun-38702 executable, so you can run:

bun-38702 --bun

@claude claude Bot 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.

I re-reviewed this PR and found no bugs; the earlier stdout-drain note is addressed. Given the open design question the author flagged (whether CachePublish is the shape #33979 / #36229 / #33884 should build on) and that this changes the cache-publish step those PRs also rewrite, a maintainer should sign off on the direction.

What was reviewed:

  • CachePublish on the POSIX and Windows arms of move_to_cache_directory: the post-move delete_tree(tmpname) was traced for each mode (Supersede after EXCHANGE removes the swapped-out folder; KeepExisting/no-collision and Replace hit an already-gone or intentionally-kept path; the new delete-on-error only removes our own staging).
  • keep_existing_destination in renameat_concurrently: the exists-check-then-delete-source ordering, and that repository.rs/patchPackage.rs callers keep their prior behaviour under ..Default::default().
  • cache_publish() re-using TL_BUFS.folder_name_buf before move_to_cache_directory also does — sequential on the buffered path, different thread on the streaming path, so no conflict.
Extended reasoning...

Overview

The PR fixes a leak where re-extracting a file: or URL tarball over its existing @T@ cache folder leaves the swapped-out copy behind in the install temp dir (one per lockfile-less install). It introduces a CachePublish enum decided before extraction (Supersede when the folder pre-exists, KeepExisting when it does not, Replace unchanged for npm/GitHub), threads it through both the buffered extractor and TarballStream, and adds keep_existing_destination to RenameatConcurrentlyOptions in src/sys/lib.rs. Mechanical ..Default::default() updates in patchPackage.rs/repository.rs keep other callers behaviourally unchanged. Two new integration tests (file: and streamed URL) plus a bun_sys unit test cover the fix.

Security risks

None identified. The new delete_tree targets only the randomly-named staging path inside the install temp dir (or the folder swapped into that name by EXCHANGE); no user-controlled path reaches it. keep_existing_destination only broadens what is kept, and the source it deletes is the caller's own staging.

Level of scrutiny

High. This is core package-manager cache publishing on both POSIX and Windows, with concurrency semantics (racing installs sharing a cache) and file deletion. It also intersects three other open PRs (#33979, #36229, #33884) that rewrite the same step differently, and the author explicitly calls out "Open item for a maintainer: whether CachePublish … is the shape the other open PRs on this publish step should build on." That is a design decision a human should make.

Other factors

The prior automated finding (undrained stdout in installFresh) was fixed in f135318; the comment-cop items were shortened in ab7e269; all inline threads are resolved. CI on build 96684 was green on the lanes that ran, per the status comment. The tests are well-targeted (three lockfile-less installs must leave the temp dir empty and one @T@ folder, then a repacked tarball must win), and the bun_sys unit test covers the new rename option directly. No correctness issue was found in this pass, but the interaction with the sibling PRs and the open design question mean this should not land on automated approval alone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants