Fix vendored npm-family tarballs dropped by .gitignore (#831) - #837
Mikola Lysenko (mikolalysenko) wants to merge 12 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Vendoring into a yarn classic, yarn berry, npm, pnpm or bun project wrote .socket/vendor/npm/<uuid>/<pkg>.tgz without checking whether git would commit it. Under Node.gitignore's `*.tgz`, or a `vendor/` or `.socket/` rule, the scan reported success, the commit dropped the tarball, and every fresh checkout's install failed. The shared tarball staging now refuses with vendor_artifact_gitignored before writing anything when a rule ignores the uuid dir itself. After writing, it adds <uuid>/.gitignore (re-including the tarball against rules like `*.tgz`) and .gitattributes, as vlt already does, and checks the written paths again. Refs #831 Assisted-by: Claude Code:claude-opus-5-5
When the vendor ledger and manifest were ignored or dropped from a commit, `vendor --check` found nothing to compare and exited 0, while the lockfile still pointed at .socket/vendor/<eco>/<uuid>/ and every fresh install failed. The check now reads the lockfile references (the same scan repair uses) and reports each one no ledger entry owns as vendor_ledger_missing. Refs #831 Assisted-by: Claude Code:claude-opus-5-5
002c870 to
617b8e3
Compare
The contract's vendoring table now says every npm-family tarball flavor writes <uuid>/.gitignore and .gitattributes next to the tarball, and refuses vendor_artifact_gitignored when git would still drop it. Refs #831 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
CodeQL flagged the new unledgered-reference message for printing the patch uuid. The human line and error detail now name only the ecosystem; the JSON event still carries the uuid and path as repair's event does. Refs #831 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Ready for review (burn-down agent).
Generated by Claude Code |
|
bugbot run Generated by Claude Code |
main's #605 made the name-keyed npm resolver reach alias and peer copies itself, which broke two vex_consumed tests that assumed an alias-blind resolver. Same change as #851, ported so this PR's CI runs green against the current base; it no-ops once #851 lands. Refs #831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMZyKmgYNAridSR5eqv999
|
Generated by Claude Code |
The tarball gitignore refusal only ran inside stage_patch_pack, which the hosted->vendored takeover reaches after restore_upstream has already removed the hosted pin. In a hosted project that ignores .socket/, vendoring then restored the registry entry and refused, leaving the package patched in neither mode. The npm takeover preflight now runs the same uuid-dir probe before the restore, as vlt's preflight already does. Refs #831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMZyKmgYNAridSR5eqv999
|
BugBot review Generated by Claude Code |
|
[agent] Head Generated by Claude Code |
|
Burn-down agent: labeled Ready for review at
Generated by Claude Code |
Resolved conflict in crates/socket-patch-cli/tests/e2e_vendor_yarn_classic_build.rs: both sides appended new tests at the same spot (this branch's #831 .gitignore tests and git/gitignored_fixture helpers; main's #627 symlinked-yarn.lock refusal test). Kept both in full; rustfmt applied. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
main's #865 added a test that fails when production code computes digests inline; the Gradle cache, JVM jar and Maven sidecar code landed with inline sha1/sha256 calls, so main's coverage and test-release jobs fail production_digests_go_through_the_helpers. Same change as #878, ported so this PR's CI runs green against the current base; it no-ops once #878 lands. Refs #831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMZyKmgYNAridSR5eqv999
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
The Generated by Claude Code |
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ 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 d07dda2. Configure here.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #831
Summary
Vendored mode in a yarn classic, yarn berry, npm, pnpm or bun project wrote
.socket/vendor/npm/<uuid>/<name>-<ver>.tgzwithout checking whether git would commit it. GitHub's stock Node.gitignore ships*.tgz, and polyglot repos often ignorevendor/or.socket/. Under any of these rules the scan exited 0 with no warning. The commit then kept the rewired lockfile and dropped the tarball, so every fresh checkout's frozen install failed. Undervendor/or.socket/,vendor --checkalso passed, because it had no ledger left to check.Root cause
All npm-family tarball backends stage their artifact through
npm_common::stage_patch_pack. The vlt and directory paths already guard this withnpm_dir::gitignore_probe, refusing withvendor_artifact_gitignoredand writing a<uuid>/.gitignorethat re-includes the payload. The shared tarball pipeline had neither, so the gap covered every tarball flavor, not just yarn classic (the yarn berry matrix in the issue comment is the same gap).Changes
stage_patch_pack(crates/socket-patch-core/src/vendor/npm_common.rs)git check-ignore --no-indexon<uuid>/. A rule that ignores the directory itself (vendor/,.socket/,.socket/vendor/) refuses withvendor_artifact_gitignored, naming the rule.<uuid>/.gitignore(!*) and<uuid>/.gitattributes(-text), the same files and content as vlt. This overrides file rules such as*.tgz.vendor_artifact_gitignore_unchecked. Outside a git work tree nothing changes.vendor --check(commands/vendor.rs): reads the lockfile references (repair::scan_vendor_references, the scan repair and the orphan sweeps use). Each.socket/vendor/<eco>/<uuid>/that no ledger entry owns fails withvendor_ledger_missing, using the same artifact-level shape repair emits (uuid+details.{ecosystem,path}). A reference whose manifest key was already reported as unledgered is not reported twice.vendor_artifact_gitignored/_uncheckedrows now cover the tarball flavors. The vendoring table names the uuid.gitignore/.gitattributes. Thevendor --checksection documents the lock-reference check.The npm/PyPI/gem wrappers only dispatch to the binary, so they need no parallel change.
Test evidence (red without the fix, green with it)
*.tgz(shared pipeline)npm_common::tests::a_tgz_ignore_rule_is_overridden_by_the_uuid_gitignorevendor/,.socket/,.socket/vendor/(wet and dry)npm_common::tests::a_directory_ignore_rule_refuses_before_any_writenpm_common::tests::no_work_tree_stages_without_a_refusal*.tgz: real yarn 1.22.22,git committhengit clone,--frozen-lockfile --offlineinstalls the patched bytese2e_vendor_yarn_classic_build::yarn_classic_vendored_tarball_survives_a_tgz_gitignore_rulevendor --checkon a clone without ledger/manifest failsvendor_ledger_missingvendor/and.socket/: refused, yarn.lock untouched, nothing writtene2e_vendor_yarn_classic_build::yarn_classic_vendor_refuses_a_gitignored_vendor_dir*.tgz: real yarn 4.12.0, clone thenyarn install --immutablewith an empty global folder installs the patched bytese2e_vendor_yarn_berry_build::yarn_berry_vendored_tarball_survives_a_tgz_gitignore_rule.socket/: refused, yarn.lock and package.json untouchede2e_vendor_yarn_berry_build::yarn_berry_vendor_refuses_a_gitignored_socket_dirLocal runs (Linux, as root):
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --all-features --lib: 4845 passed, 4 failed. The 4 failures are permission tests that rely onchmodread-only dirs, which root bypasses (copy_tree, vlt_heal, pypi_poetry, pypi_requirements). This PR doesn't touch those modules.cargo test -p socket-patch-cli --all-features --lib: 834 passed.covgap_commands_vendor: 41 passed, 3 failed (*_state_write_failure_*, whichchmod 0o555the vendor dir). The same 3 fail onmainas root.repair: 114 passed, 2 failed (unremovable-file tests, same class).cargo test --workspacedoesn't fit this sandbox's disk allowance, so the CI matrix covers the rest.cargo fmt --all -- --checkisn't clean onmainwith the pinned toolchain's rustfmt, and CI doesn't run it. The new code follows the surrounding style and no unrelated files are reformatted.Notes
002c870) briefly carried an accidental repo-wide rustfmt reformat that touched PDM files, which triggered the path-filtered PDM compatibility workflow. Itsextras agentcell failed on that head. That head is superseded: the current branch touches only the six files above, and PDM compatibility doesn't run on it.*.jar) is the same symptom in a different backend.🤖 Generated with Claude Code
https://claude.ai/code/session_01FMZyKmgYNAridSR5eqv999
Note
Medium Risk
Changes core vendoring and pre-takeover ordering for npm-family lockfiles; mistakes could block vendoring or leave hosted wiring, but the design is fail-closed rather than silently dropping tarballs from commits.
Overview
Vendored npm-family tarball flows (npm, yarn classic/berry, pnpm, bun) now treat git ignore rules like the existing vlt/directory path: refuse before writing when the uuid directory itself would be ignored, write
<uuid>/.gitignoreand.gitattributesto re-include*.tgz(and similar file rules), then re-probe and roll back if the artifact still would not be committed. A newnpm_tarball_gitignore_preflightruns on hosted→vendored takeover before restoring the registry lock entry, so a.socket/ignore does not leave the package wired only to hosted mode.vendor --checkalso scans lockfiles for.socket/vendor/<eco>/<uuid>/references with no matching ledger entry and fails withvendor_ledger_missing(artifact-level event, aligned with repair), including cases the manifest alone cannot see.Docs in
CLI_CONTRACT.mdare updated for tarball flavors and the check behavior. JVM/Gradle code paths switch to sharedsha1_hex_of/sha256_hex_ofhelpers (no behavior change). E2E and in-process tests cover*.tgz,vendor/,.socket/, clone/install, and check-on-missing-ledger.Reviewed by Cursor Bugbot for commit d07dda2. Configure here.