Skip to content

Fix git-ignored bun.lockb workspace mirrors (#1116) - #1442

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-bun-lockb-mirror-gitignore
Oct 12, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-bun-lockb-mirror-gitignore

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1116

Root cause

In a bun.lockb workspace, vendoring writes the patched tarball twice:
the canonical root artifact .socket/vendor/npm/<uuid>/<leaf>, and a
copy (mirror) inside each member at <member>/.socket/vendor/npm/<uuid>/<leaf>.
Bun 0.5.9–1.3 installs from the member copy. The #837 guard covers only
the root artifact's uuid dir. That guard probes git check-ignore before
the write, then writes a !* <uuid>/.gitignore after it. The mirror
loop in bun_binary.rs wrote straight to root.join(rel). So GitHub's
stock *.tgz rule, or a member-local .socket/ rule, kept the mirror out
of the commit while the scan reported success. Fresh clones then failed
bun install --frozen-lockfile (1.1–1.2), hung (1.3.9), or failed
vendor --check / vex (1.4).

Fix

  • Pre-flight, before any write (dry runs too): the backend pre-flight
    probes every member mirror's uuid dir and refuses
    vendor_artifact_gitignored when a directory rule ignores it, naming
    that member. The hosted→vendored takeover pre-flight
    (npm_tarball_gitignore_preflight) probes the same dirs, so a takeover
    never restores the registry entry and then refuses.
  • Wire: each mirror gets the root artifact's <uuid>/.gitignore and
    .gitattributes, including in-sync re-runs, so re-running a scan
    fixes an already-vendored project. All written paths then go through
    one batched git check-ignore. If they are still ignored, the run
    unwinds; if git can't answer, it warns
    vendor_artifact_gitignore_unchecked.
  • Repair: bun_workspace::repair (run by socket-patch repair on healthy
    and broken bun entries alike) restores the metadata.
  • Revert / rollback / undo / cleanup: the metadata is removed with the
    mirror, even when the tarball was already deleted by hand. That keeps
    the member's .socket/ pruned. Deferred removal during a staged
    takeover queues the metadata as well.
  • CLI_CONTRACT.md documents the member mirrors and the refusal.

Tests (red → green)

New unit tests in crates/socket-patch-core/src/vendor/bun_binary.rs:

  • a_tgz_rule_still_commits_every_workspace_mirror: a real git work tree
    with node_modules and *.tgz ignored. Vendoring succeeds and
    git check-ignore reports no mirror as ignored. repair restores a
    deleted mirror .gitignore. Revert, with one mirror tarball deleted by
    hand, restores the lock and prunes the member's .socket/.
    Without the fix: left: Some(".gitignore:2:*.tgz\tpackages/helper/.socket/vendor/npm/…/minimist-1.2.2.tgz").
  • an_ignored_member_vendor_dir_refuses_before_any_write: covers a
    member .socket/ rule and a root */**/.socket/ rule, each as a dry
    run and a real run. Vendoring refuses vendor_artifact_gitignored
    with the lock byte-identical and no .socket/vendor written, and the
    takeover pre-flight refuses too. Without the fix: expected a refusal, got Done { … success: true … }.
  • first_ignored_names_the_path_git_reports: the refusal names the
    ignored member, not the first one probed.
Issue Covered by
#1116 *.tgz (root or member) drops the mirror a_tgz_rule_still_commits_every_workspace_mirror
#1116 member .socket/ rule an_ignored_member_vendor_dir_refuses_before_any_write
#1116 repair can't make the mirror committable a_tgz_rule_still_commits_every_workspace_mirror (repair step)

Local results (Linux, Bun 1.4.2)

  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --lib bun: 355 passed.
  • e2e_vendor_bun_build (37), in_process_vendor_bun_takeover (40),
    mode_migration_bun (33) and vendor_eject_bun_lockb (10), all with
    --include-ignored: all pass. e2e_bun_lockb: 22/23. The one
    failure, binary_shared_bundled_record_hosted_pin_is_managed, is a
    hosted rollback that can't reach patches-api.socket.dev from the
    sandbox (tunnel error).
  • cargo test --workspace --all-features --no-fail-fast: all bun suites
    pass. The only failures are chmod- or unremovable-file write-failure
    tests (covgap_commands_vendor ×3, in_process_redirect ×3,
    repair ×2, core lib ×4: copy_tree, vlt_heal, pypi_poetry,
    pypi_requirements). They can't fail as intended because the sandbox
    runs as uid 0, and none touch the bun code. CI runs them as a normal
    user.

Review notes (/code-review high)

Fixed: one batched git probe instead of two git processes per mirror,
the refusal now names the ignored member, a hand-deleted mirror's
metadata is cleaned on revert, and the uuid dir is now found from path
components so Windows verbatim paths clean up.

Not changed:

  • "repair never restores mirror metadata": repair calls
    repair_workspace_copies for healthy entries too (repair.rs:422), so
    it does.
  • A mirror still ignored after its !* .gitignore is a generic
    failure, not a Refused:
    the wire step returns String errors. That
    case needs a rule a deeper .gitignore can't override, which the
    pre-flight already refuses. The error text still starts with
    vendor_artifact_gitignored, and the run unwinds.
  • The download-plan gate (preflight_packages) doesn't probe git: this
    matches the root artifact's check, which also runs only at staging. The
    backend still refuses before writing anything.
  • Metadata written into an in-sync mirror dir isn't undone if a later
    write fails:
    those files are what a committed vendored dir should
    hold anyway.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Swcnf9zxfEYuSqCy8F3TWy


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
On a bun.lockb workspace, vendoring also writes the patched tarball
under each member's .socket/vendor/npm/<uuid>/, because Bun 0.5.9-1.3
installs from there. Those copies never got the git-ignore check or
the !* .gitignore the root artifact gets, so GitHub's stock *.tgz rule
(or a member's .socket/ rule) kept them out of the commit: the scan
said success, and fresh clones failed or hung on
bun install --frozen-lockfile, or failed vendor --check on Bun 1.4.

Each mirror now gets the same .gitignore and .gitattributes as the
root artifact (on vendor and on repair), and a rule no nested file
can override refuses vendor_artifact_gitignored before anything is
written, dry runs and hosted takeovers included. Reverting removes
that metadata with the mirror so the member's .socket/ is pruned.

Fixes #1116

Assisted-by: Claude Code:claude-opus-5-5
The CLI contract now says that each bun.lockb workspace member's
tarball copy gets the same .gitignore/.gitattributes as the root
artifact, and that a member .socket/ ignore rule refuses vendoring.

Refs #1116

Assisted-by: Claude Code:claude-opus-5-5
- Probe every written member mirror in one git call instead of
  two git processes per mirror.
- Name the member git actually ignores in the refusal, not the
  first one probed.
- A mirror tarball already deleted by hand still takes its
  .gitignore/.gitattributes on revert, so the member's .socket/
  is pruned.
- Find the member uuid dir from path components, so Windows
  verbatim paths clean up too.

Refs #1116

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 12, 2026 20:03
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 79c12b6. Configure here.

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

Labels

None yet

Projects

None yet

3 participants