Skip to content

repair leaves a pre-#1541 root <uuid>/.gitattributes as * -text, so the repaired Bun tarball goes back into Git LFS on the next commit #1581

Closed

Description

[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).

Summary

#1559 fixed #1541 for new vendored runs. A project vendored by 5.0.1 or earlier in a repo that LFS-tracks *.tgz still has its tarball committed as an LFS pointer, plus the legacy .socket/vendor/npm/<uuid>/.gitattributes (* -text). In a checkout that doesn't smudge LFS (CI with actions/checkout defaults, GIT_LFS_SKIP_SMUDGE=1), vendor --check reports vendor_artifact_unreadable and says to run socket-patch repair. repair downloads the real tarball again, exits 0, and vendor --check turns green. But repair doesn't upgrade the root uuid .gitattributes. It stays * -text, so the repo's *.tgz filter=lfs rule still applies, and committing the repair stores the tarball as an LFS pointer again. Every fresh checkout without LFS still fails bun install --frozen-lockfile.

On bun.lockb workspaces, repair does rewrite the member mirrors' .gitattributes to the new * -text -filter -ident -working-tree-encoding (through repair_workspace_copies → bun_binary::restore_mirror_metadata), and those mirrors leave LFS. Only the root artifact's uuid dir is missed.

#1541's impact section named this exact path: "the repaired file goes back into LFS on the next commit".

Impact

The recovery that vendor --check prescribes doesn't recover. CI on an LFS-less checkout stays red after the user runs repair and commits, while vendor --check reports green locally. A vendored run (scan --mode vendored) does heal the tree, because npm_common.rs:295 calls restore_uuid_metadata. But nothing points users to it instead of repair, and docs/ecosystems.md only says "after the next vendored run".

Repro (Linux, main 15ead12)

# 1. vendored by the previous release (5.0.1) in a repo that LFS-tracks *.tgz
git init app && cd app && git lfs install --local
printf '*.tgz filter=lfs diff=lfs merge=lfs -text\n' > .gitattributes
printf 'node_modules/\n' > .gitignore
echo '{"name":"app","dependencies":{"left-pad":"1.3.0"}}' > package.json
bun install && git add -A && git commit -qm init
socket-patch@5.0.1 scan --mode vendored -y && git add -A && git commit -qm vendored
# 2. CI-style checkout without LFS, with current main
GIT_LFS_SKIP_SMUDGE=1 git clone -q "$PWD" ../c && cd ../c && git lfs install --local
socket-patch vendor --check          # vendor_artifact_unreadable … run `socket-patch repair`
socket-patch repair -y               # Redownloaded 1 vendored artifact. Repair complete. (exit 0)
socket-patch vendor --check          # exit 0
cat .socket/vendor/npm/*/.gitattributes   # still "* -text"
git check-attr filter -- .socket/vendor/npm/*/*.tgz   # filter: lfs
git add -A && git commit -qm repaired
git lfs ls-files                     # .socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz
GIT_LFS_SKIP_SMUDGE=1 git clone -q "$PWD" ../d && cd ../d
bun install --frozen-lockfile        # ZlibError (1.2/1.3) or "Integrity check failed" (1.4)

The patch API was a local mock serving a granted tarball for left-pad@1.3.0.

Expected vs actual

Matrix (Linux; 5.0.1 vendored → no-LFS clone → main repair → commit → no-LFS clone → cold frozen install)

Bun lock shape repair root .gitattributes after member mirror frozen install
1.2.23 text single exit 0 * -text n/a fail (ZlibError)
1.3.9 bun.lockb single exit 0 * -text n/a fail (ZlibError)
1.4.3 bun.lockb workspace exit 0 * -text upgraded, leaves LFS fail (integrity)
1.4.3 bun.lockb workspace, scan --mode vendored instead of repair (control) exit 0 upgraded upgraded pass, patched

The 1.4.3 workspace cell was run twice. Plain npm (package-lock.json) behaves the same for the root tarball (root .gitattributes stays * -text, and the tarball stays in LFS after the commit), so this isn't Bun-specific apart from the member-mirror half, which works.

First bad version

This isn't a regression. It's the part of #1541 that #1559 left open (the legacy-tree upgrade only runs on vendored scans).

Suspect code

  • crates/socket-patch-cli/src/commands/vendored_backend/repair.rs:495-528 rewrites the uuid metadata for vlt (restore_vlt_uuid_metadata) and JVM entries, but not for the npm tarball flavors (npm / bun text / bun.lockb / pnpm / yarn). The redownload path (repair.rs:696, vendor::redownload::restore) writes only the artifact.
  • A call to npm_dir::restore_uuid_metadata on the root uuid dir for tarball-flavor entries, as npm_common.rs:295 does on a vendored run, should cover it. It might also make sense for vendor --check to flag a legacy * -text file (or git check-attr filter ≠ unset) so the green check doesn't hide it.

No probe branches: this is git behaviour and doesn't depend on the OS.

Activity

  1. mikolalysenko commented on Oct 15, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged as priority:p1 (Bun/npm vendored). Confirmed on main 4cc50f4 by reading the code: repair (crates/socket-patch-cli/src/commands/vendored_backend/repair.rs ~495-528) rewrites the uuid-dir metadata only for vlt (restore_vlt_uuid_metadata) and JVM entries; the npm tarball flavors (npm, bun text, bun.lockb, pnpm, yarn) never reach npm_dir::restore_uuid_metadata on the root uuid dir, which only the vendored-scan path (npm_common.rs:295) calls. Not a duplicate: #1559 covered new vendored runs only. No open PR addresses it.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 18, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] npm bug-hunt routine (ledger #302): a second symptom of the same root cause, in plain npm with no LFS involved. repair never calls npm_dir::restore_uuid_metadata for the npm tarball flavors. So when the whole <uuid>/ directory is lost, it restores only the .tgz. The <uuid>/.gitignore (!*), .gitattributes and socket-patch.vendor.json stay missing. With Node.gitignore's stock *.tgz rule, git then ignores the redownloaded tarball. repair exits 0 and prints "Redownloaded 1 vendored artifact". vendor --check reports "committed artifact and wiring verified". The "then commit it" step that vendor --check prescribes commits nothing. On every fresh clone, npm ci with a cold cache exits 254 and vendor --check reports vendor_artifact_missing again. The vendor_artifact_gitignored guard that vendor runs (#831) is never reached on this path.

    Repro (main 7d3086f, npm 10.9.4 and 12.2.1 / Node 24.22.0, reproduced twice; the patch API was a local mock):

    git init app && cd app && printf 'node_modules/\n*.tgz\n' > .gitignore
    echo '{"name":"app","version":"1.0.0","dependencies":{"ms":"2.0.0"}}' > package.json
    npm i && socket-patch scan --mode vendored && git add -A && git commit -qm vendored
    git rm -rq .socket/vendor/npm/<uuid> && git commit -qm lost   # dir lost: bad merge, manual delete, …
    socket-patch repair                  # Redownloaded 1 vendored artifact. (exit 0)
    ls -A .socket/vendor/npm/<uuid>      # ms-2.0.0.tgz only
    git check-ignore -v .socket/vendor/npm/<uuid>/ms-2.0.0.tgz   # .gitignore:2:*.tgz
    socket-patch vendor --check          # exit 0
    git add -A && git status --porcelain # nothing to commit
    git clone -q . ../c && cd ../c && npm ci --cache "$(mktemp -d)"   # exit 254 (ENOENT on the file: tarball)

    A warm npm cache hides the failure, because npm serves the tarball by its integrity. The npm_dir::restore_uuid_metadata call proposed above writes both .gitignore and .gitattributes, so it would cover this case as long as it also runs when the files are missing, not only when they are legacy. A git check-ignore probe on the repaired path (as vendor does) would catch a remaining ignore rule.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 21, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: repair never rewrites the root <uuid>/ metadata (.gitattributes/.gitignore/socket-patch.vendor.json) for npm-family tarball flavors). Branch: agent/fix-repair-npm-uuid-metadata. Claim-ID: 2026-10-21T08:21:07Z-507a19


    Generated by Claude Code

  4. mikolalysenko commented on Oct 21, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1656


    Generated by Claude Code

  5. added a commit that references this issue on Oct 21, 2026
    f9bffaa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions