Skip to content

Commit 5356bb6

Browse files
feat: socket-patch vendor — committable vendoring of patched dependencies (#109)
* refactor(cargo): patch crates in place; drop the [patch]-redirect backend + build guard Simplify the cargo apply path to patch crates in place (vendored or registry cache) like npm/pypi/gem, removing the project-local `[patch]`-redirect backend and the build-time `socket-patch-guard` setup wiring. Cargo now rolls back in place from before-blobs rather than dropping a redirect. Removed: - core: `cargo_setup` (discover/update), `patch/cargo_config`, `patch/cargo_redirect`, and `go_setup` (the build-time Go guard package + templates). - cli: cargo/go redirect dispatch in `apply`/`rollback`, cargo + Go guard wiring in `setup`, and the now-dead setup/redirect tests. Kept: - Go `replace`-redirect (`go_redirect`/`go_mod_edit`/`copy_tree`): the module cache is checksum-verified, so in-place patching fails `go.sum` at build time — Go still needs the project-local copy. - The `socket-patch-guard` crate and its build-integration test. `copy_tree` is now gated on `golang` only. Docs (README, CLI_CONTRACT, module headers) updated to drop the removed backends. Builds clean across feature combos (default / none / all / cargo-only) and the full suite passes (--no-fail-fast). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: drop removed cargo-coexist suite + go-guard-template lint step The simplification deleted `tests/e2e_cargo_coexist.rs` and the `go_setup/templates/*.tmpl` files, but ci.yml still referenced them: the e2e matrix listed `e2e_cargo_coexist` (no such target → fail) and the lint-ecosystems job `cp`'d the now-absent Go guard templates for gofmt/vet (cp → fail). Remove both; keep `guard_build_integration`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor: remove the now-orphaned socket-patch-guard crate + stale references With cargo patching in place (no `[patch]`-redirect) and `setup` no longer wiring a build-time guard, the `socket-patch-guard` crate had no consumer: nothing in cli/core references it, `setup` never writes it, and its `.socket/cargo-patches/` + `SOCKET_PATCH_ROOT` machinery no longer exists. Remove it and every dangling reference. - Delete `crates/socket-patch-guard/` (crate, build.rs, README, SAME_TICK_HEAL_RND.md, same_tick_heal_experiment.rs) and drop it from the workspace members + Cargo.lock. - Delete `guard_build_integration.rs`; drop the `guard_build_integration` e2e matrix entry and the guard-template gofmt/vet step from ci.yml; drop the `cargo publish -p socket-patch-guard` step from release.yml. - CHANGELOG: rewrite the `[Unreleased]` cargo/guard entries to describe what actually ships — cargo in-place patching (default feature) and the Go `replace`-redirect backend — and drop the now-false "cargo apply now redirects" Changed bullet. - Drop the dead `SOCKET_PATCH_ROOT`/`SOCKET_PATCH_GUARD` env vars from test scrub lists (no longer read in src; `SOCKET_PATCH_BIN` kept — the gem Bundler plugin still uses it); repoint stale `setup_matrix_cargo` doc-comments to surviving sibling suites; refresh CLI_CONTRACT prose. Builds clean across feature combos; full suite passes (--no-fail-fast). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(go): parameterize replace-redirect engine by owner/base for the vendor backend - go_mod_edit: ReplaceOwner enum (GoPatches|Vendor), GO_VENDOR_DIR, detect_owner over both prefixes; ensure_replace_entry takes the copy base (cross-owner upsert = vendor takeover), drop_replace_entry is owner-filtered - go_redirect: thread base_rel through apply/remove/in_sync/copy_dir_for; reconcile + verify are GoPatches-scoped and skip vendor-owned modules - new patch/path_safety.rs: shared multi/single-segment + canonical-uuid guards - utils/fs.rs: crate-wide atomic_write_bytes (stage+fsync+rename); go editors delegate - ungate copy_tree (vendor backends for unconditional ecosystems need it) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(vendor): record phase-0 spike findings + uv lock-shape fixtures All 7 package managers verified GO with real tools. Load-bearing facts: - npm: lock-only file: tarball rewrite passes npm ci; integrity MUST be recomputed (stale integrity + warm cache silently installs unpatched) - cargo: source+checksum lock surgery is byte-stable; --locked --offline fresh-checkout proof passed; path deps build without --cap-lints - golang: uuid path level fine; ./ prefix mandatory - uv: surgical pyproject+uv.lock edits byte-match uv's own output; tool.uv.sources applies to override-dependencies (transitive channel) - pip/uv pip: bare paths resolve against CWD (root-only constraint); markers on path lines evaluate correctly (carry over, don't refuse) - composer: lock-only dist=path surgery confirmed incl. --network none - bundler: Gemfile+lock pair edit regenerates byte-identically Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): core module — path convention, state ledger, marker, backend contract - vendor/path.rs: .socket/vendor/<eco>/<uuid>/<leaf> layout, lockfile-string recovery parser (the documented external-tool rule), leaf<->purl round-trip, fail-closed uuid-dir sweep - vendor/state.rs: committed state.json ledger (verbatim original lockfile fragments for revert), atomic sorted deterministic writes, empty-state pruning, socket-patch.vendor.json marker writer - vendor/mod.rs: VendorOutcome/RevertOutcome backend contract, is_vendorable, is_purl_vendored; per-backend submodule stubs - deps: zip 8.6 (no-default+deflate) + base64 into core Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(cli): extract patch-source staging into commands/fetch_stage.rs apply's offline-guard + overlay-tempdir + download block becomes stage_patch_sources(), shared with the upcoming vendor command. Behavior preserved verbatim; apply_network + apply_invariants suites green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): vendored-patch verification + Command::Vendor envelope tag verify_vendored_patch_record: positive file-level evidence against the committed artifact (dirs hashed in place; npm tgz / pypi whl decoded in memory, bomb-capped). Fail-closed: no_files -> vendor_path_unsafe -> vendor_uuid_mismatch (path-level uuid IS the staleness signal) -> vendor_artifact_missing -> unreadable/hash_mismatch. Poisoned state.json paths never stat outside the project tree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(apply): yield to vendor ownership (golang skip, --check exclusion, vendored event reason) - try_local_go_apply: a purl recorded in .socket/vendor/state.json is never taken back over; synthesized success routes to Skipped/'vendored' - result_to_event: vendored package_path marker -> reason 'vendored' - run_check: vendored purls excluded from the go-patches drift audit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(cli): vendor command pipeline + vendor telemetry events (not yet wired) commands/vendor.rs: full vendor + --revert pipelines (lock, manifest gate, fetch staging, reconcile-dropped, crawl, variant probe, per-eco dispatch, per-package state persistence, orphan sweep, VEX embed, envelope). Stays undeclared in commands/mod.rs until the ecosystem backends land so concurrent builds stay green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: vendor command contract section + CHANGELOG entries Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: single Added section in CHANGELOG Unreleased Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: place VEX golang fix under Unreleased, not 3.2.0 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): all six ecosystem backends + CLI wiring + VEX integration Backends (each spike-validated against the real package manager): - npm: deterministic patched tarball + package-lock.json resolved/integrity rewrite (npm ci-verified; nested instances; v2 legacy mirror) - cargo: resurrected [patch.crates-io] config engine + new Cargo.lock source/checksum surgery (cargo build --locked --offline proven) - golang: ReplaceOwner::Vendor wrapper over the redirect engine with go-patches takeover - composer: lock-only dist->path surgery (content-hash unaffected) - gem: Gemfile + Gemfile.lock pair edit in bundler's byte-exact canonical form - pypi (uv-first): RECORD-driven wheel rebuild; uv pyproject+uv.lock pair surgery byte-matching uv's own serializer (override-dependencies for transitive deps); requirements.txt wiring for pip/uv pip VEX: applied_patches_with_vendor verifies vendored artifacts file-level (no installed-tree fallback either direction), '(vendored)' impact phrasing, Property-7 exemption, and fixes the latent golang go-patches attestation hole. CLI: vendor + --revert pipelines wired (lock, staging, reconcile, variant probe, per-package state persistence, orphan sweep, --vex embed). 285 new backend/VEX tests; full sweep green: core 1239 (composer)/983 (no-default), CLI lib 272, all 90 integration binaries pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vendor): prune empty ecosystem dirs on full revert A fully-reverted project carried an empty .socket/vendor/<eco>/ level; save_state's empty branch now removes empty eco dirs (non-recursive) before pruning .socket/vendor itself. Smoke-tested end-to-end: vendor -> npm ci installs patched bytes -> revert restores the lock byte-exactly with zero residue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(vendor): parser-contract + in-process suites; fix SOCKET_FORCE boolish parsing - cli_parse_vendor.rs: 31 tests (EnvScrub + serial + full-surface snapshot); 2 remaining ignored pins document the known empty-env-var crash class shared with GlobalArgs - in_process_vendor.rs: 13 lifecycle tests (end-to-end vendor, idempotent rerun, dry-run, revert round-trips incl. manifest-less, reconcile, golang vendored-skip handshake, lock contention, envelope shape) - fix: --force on apply+vendor now uses BoolishValueParser, so SOCKET_FORCE=1/yes/on work like every other SOCKET_* bool (was: clap's strict true/false parser aborted the whole command) - docs: compiled-out-ecosystem visibility + missing-ledger revert wording aligned with actual (by-design) behavior Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vendor): correct event classification + capstone e2e proofs - result_to_event: apply's yield-to-vendor marker is now an exact sentinel (VENDOR_OWNED_MARKER) instead of a .socket/vendor/ substring match, which misrouted every successful cargo/golang/composer/gem vendor to skipped/'vendored' (summary.applied == 0) - vendor rerun in-sync skips now report the contract's 'already_vendored' - golang takeover prunes empty .socket/go-patches parent husks - capstone e2e suites (npm ci, cargo --locked --offline w/ empty CARGO_HOME, go GOPROXY=off w/ empty GOMODCACHE + file:// proxy fixture, uv sync --frozen --offline + lock --check + byte-stable plain sync, pip/uv pip --no-index): 8 tests, all passing against the real toolchains, each with fresh-checkout committability proof + revert byte-restoration + the apply<->vendor takeover/yield interplay Full sweep: 96/96 CLI test binaries green; core 1239 (composer) / 983 (no-default) green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vendor): security + scoping fixes from adversarial review - SECURITY (blocker): pypi requirements revert joined the tamper-able state.json wiring 'file' path unvalidated -> a poisoned ledger could make 'vendor --revert' splice attacker lines into an arbitrary file (../, abs). Each recorded path now re-passes the in-root constraint vendor-time planning enforced; unsafe records skip fail-closed with a warning. RED-verified regression test (out-of-tree target stays byte-untouched). - reconcile_dropped now respects this run's --ecosystems scope (a scoped 'vendor --ecosystems npm' no longer silently reverts cargo/go entries) - revert orphan sweep keys on (ecosystem, uuid), not uuid alone Reviewer verified all other deletion paths, lockfile writes, the apply sentinel, and VEX attestation fail-closed under tampered manifest/state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): v2 phase 1 — boolish env parsing, composer reference uuid, checksum pins - --force (apply+vendor) and --revert use parse_bool_flag: empty env => false (the GlobalArgs contract); the 2 ignored parse pins are now passing tests - composer lock dist.reference carries the patch uuid (preserved verbatim into installed.json: in-tree traceability surviving .socket-stripped deploys); entry_is_wired deliberately NOT tightened (ledger-clobber hazard) - cargo revert pin: a lock that gained [[patch.unused]] post-vendor still restores cleanly - CLI_CONTRACT: per-ecosystem checksum-coverage table Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): v2 phases 2-3+5 — gem CHECKSUMS, flavor probes, refactors, composer/gem capstones - gem.rs: bundler >=2.6 CHECKSUMS section handled (spike-pinned bare-entry emitter, byte-identical to bundler's own re-lock; separate gemfile_lock_checksum wiring record; fail-closed on platform siblings / unparseable entries; v1-stale-token state refuses with vendor_stale_lock_checksum + revert guidance) - npm_flavor.rs: content-sniffing lock probe (PnP/bun.lockb/berry/lock-version refusals, multiple-lockfile warnings) + vendor_npm_any/revert_npm_any routers; CLI's npm_manager_refusal gate deleted - npm_common.rs: shared stage->patch->pack pipeline for all npm flavors; PackedTarball gains sha1_hex (yarn-classic resolved fragments) - toml_surgery.rs: pypi_uv's text-surgery helpers extracted for the poetry/pdm lock backends - state.rs: PnpmMeta/PoetryMeta/PdmMeta/PipenvMeta (additive, schema v1); forward-compat posture documented - pypi.rs: v2 flavor routing (uv > poetry > pdm > pipenv locks; lock-less markers refuse <tool>_no_lockfile with requirements fallthrough; pypi_multiple_lockfiles warning) with behavior-neutral Refused arms until the backends land - docker_vendor_common + composer/gem build-proof capstones (--network none fresh-checkout installs, red-probe-verified); Dockerfile.gem -> ruby 3.3 + bundler 2.7 pin; Dockerfile.pypi + pipenv; CI matrix runs the new suites - spikes/PHASE0-V2-FINDINGS.txt + 8 fixture-oracle dirs (all eight PMs GO) Suites: core 1273 / cli 272 / all integration binaries green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(vendor): declare v2 backend module stubs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): v2 backend implementations (yarn classic/berry, pnpm, bun, poetry/pdm/pipenv) All six spike-fixture-oracle backends, not yet wired into the routers: - yarn_classic_lock: lock-only block surgery (file:./...#sha1 + SRI double checksum; merged-key + npm-alias blocks; CRLF-preserving splice) - berry_zip + yarn_berry_lock: byte-exact tgz->cache-zip checksum port (10c0/<sha512>, verified identical to yarn 4.12's own cache zip) + resolutions pair-edit; cacheKey/compressionLevel guards - pnpm_lock: pnpm.overrides pair edit + 4-part lock surgery (byte-identical to pnpm 9 & 10 emission) - bun_lock: lock-only 3-tuple rewrite, integrity recomputed - pypi_poetry/pypi_pdm/pypi_pipenv: lock-only [[package]]/JSON splices mirroring pypi_uv; pipenv emits vendor_integrity_unverified (no hash enforcement on file entries) Each: fixture-oracle byte-exact transforms, in-sync hot path, revert round-trips with per-flavor file allowlists, drift gates. Core lib 1371 green (2x at default parallelism). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vendor): wire v2 backends into the npm/pypi routers - npm_flavor: NpmLockFlavor::YarnBerry variant; the __metadata sniff now routes berry (node-modules linker) to the backend instead of refusing (PnP still refused — different artifact pipeline); vendor_npm_any dispatches package-lock/yarn-classic/yarn-berry/pnpm/bun; revert_npm_any routes all five (unknown flavor still fails closed) - pypi: WiringPlan + MetaSlot gain Poetry/Pdm/Pipenv; vendor_pypi loads each project, runs check_target_guards (InSync -> synthesized AlreadyPatched via in_sync_outcome, entry None), wires LAST, routes the meta into the matching VendorEntry field; revert_pypi routes poetry/pdm/pipenv - updated the 3 npm_flavor tests that pinned the placeholder behavior (berry-refusal, native-pointer gate, yarn-classic-fails-closed-revert) to assert the new routing All six v2 backends now reachable end-to-end through the CLI. Suites: core 1371 / cli 272 / in_process_vendor 13 / cli_parse_vendor 31 green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(vendor): v2 contract — flavor matrix, checksum table, reason codes, CHANGELOG CLI_CONTRACT: five npm + six pypi flavor rows with strictest-install proofs; checksum-coverage rows for yarn classic/berry, pnpm, bun, poetry, pdm, pipenv, gem CHECKSUMS; new stable reason codes (vendor_yarn_berry_*, vendor_bun_lockb_*, vendor_override_conflict, vendor_integrity_unverified, *_no_lockfile, *_multiple_lockfiles, vendor_stale_lock_checksum). CHANGELOG v2 entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(vendor): npm-family build-proof capstones (yarn classic/berry, pnpm, bun) Real-package-manager fresh-checkout proofs (skip-guarded local capstones): - yarn classic: yarn install --frozen-lockfile --offline, cold cache - yarn berry (node-modules): yarn install --immutable --check-cache, cold cache, 10c0 cache-zip checksum reproduced + verified - pnpm: pnpm install --frozen-lockfile --offline on BOTH pnpm 9 and 10 - bun: bun install --frozen-lockfile, cold cache Each: vendor -> assert lock rewiring + tarball -> fresh copy of committed files -> strictest cold-cache install -> patched bytes -> revert byte-identical -> re-vendor. All green on this machine with real assertions (no skips). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(vendor): docker build-proof capstones for poetry/pdm/pipenv Two-stage harness (networked fixture+vendor+revert; --network none strictest install): poetry check --lock && poetry sync; pdm install --check && pdm sync; pipenv install --deploy && pipenv verify. Each asserts the lock-only wiring (poetry [package.source] type=file + files[] our-sha256; pdm path + files[]; pipenv default.<pkg> file+hashes), the wheel artifact, byte-identical revert, and re-vendor; pipenv also asserts the vendor_integrity_unverified warning. Red-probe verified (deleting .socket/vendor fails the cold-cache install). All 3 green against the rebuilt socket-patch-test-pypi image. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style: cargo fmt --all Tree-wide formatter pass (a hook reflowed files this session's work left non-fmt). AST-preserving — core lib 1371 (composer)/1114 (no-default), cli lib 272, vendor capstones + in_process_vendor + cli_parse_vendor all green post-fmt; cargo fmt --all --check clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(vendor): drop spikes/ scratch from the branch The phase-0 fixture-oracle dirs (365 files incl. 16 binary wheels, ~34k lines) were development scratch — the backends embed the captured fixture content as inline test constants with provenance comments, so nothing reads spikes/ at build or test time. The spike methodology + results live in the commit history, the CLI_CONTRACT checksum/flavor tables, and those constants. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(clippy): clear the CI clippy gate Two lints promoted to errors under `cargo clippy --workspace --all-features -- -D warnings` (the failing CI job): - `large_enum_variant` on `VendorOutcome`: `Done` dwarfs `Refused` because it carries an `ApplyResult` + `Option<VendorEntry>`. The asymmetry is harmless — it's a one-shot return value, never stored in a collection or hot loop — so `#[allow]` with a justifying comment beats spraying `Box`/deref churn across every backend and router. - `unnecessary_unwrap` in vendor's embedded-VEX path: `is_some()` + `unwrap()` replaced with `if let Some(vex_path)`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style(clippy): clear remaining --all-targets lints surfaced by rust 1.93 CI's clippy job only lints `--workspace --all-features` (lib + bins), but the 1.93 toolchain bump surfaces warn-level lints under `--all-targets` in this PR's files. Cleared so the whole workspace passes `cargo clippy --workspace --all-features --all-targets -- -D warnings`. Machine-applicable (via `cargo clippy --fix`): `map_or(false,..)`→`is_some_and`, `map_or(true,..)`→`is_none_or`, `% n == 0`→`is_multiple_of`, needless borrow/closure removals, struct-field shorthand, `iter().any(==)`→`contains`, `&[x.clone()]`→`std::slice::from_ref(&x)`. Hand fixes where the mechanical suggestion was wrong or lossy: snake_case test fn names; doc paragraphs split from a preceding list with a blank `///` line (indenting would render as a code block); a doc line starting with `+` reworded so markdown doesn't parse it as a nested bullet; `type_complexity` allowed file-wide in the fn-pointer case-table test; and `default_constructed_unit_structs` allowed on the two `*_default_and_new_construct_cleanly` tests whose whole point is to exercise `::default()`. Also clears the two pre-existing `deno_crawler`/`crawler_go_e2e` sites opportunistically (same toolchain-surfaced lints). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(vendor): make unsupported-ecosystem test feature-aware `unsupported_ecosystem_purl_is_currently_dropped_silently` hard-coded a default-features assumption — that a `pkg:nuget/...` purl is dropped silently because nuget is compiled out. But CI runs `cargo test --workspace --all-features` (nuget compiled in), where vendor correctly recognizes the purl, finds it unvendorable, and emits a `vendor_unsupported_ecosystem` skip event. The test wasn't feature-gated, so it failed under --all-features — taking down the test (×3 OS), test-release, and coverage jobs. Production behavior is correct; only the test was wrong. Rewrote it (`..._is_a_benign_skip`) to assert the invariant that holds on every feature set — the nuget purl is never `applied`, npm still vendors, exit 0 — and to branch on `cfg!(feature = "nuget")` for how the purl surfaces (explicit skip when compiled in, silent drop when compiled out). Verified green under both `--all-features` and default features. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 84aaf87 commit 5356bb6

206 files changed

Lines changed: 42448 additions & 2351 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,17 @@ jobs:
326326
327327
- name: Run ${{ matrix.ecosystem }} Docker e2e test with coverage
328328
run: |
329+
# Vendor build-proof capstones ride the same image as their
330+
# ecosystem's main suite (extend the case as new vendor suites land).
331+
EXTRA=""
332+
case "${{ matrix.ecosystem }}" in
333+
composer) EXTRA="--test docker_e2e_vendor_composer" ;;
334+
gem) EXTRA="--test docker_e2e_vendor_gem" ;;
335+
esac
329336
cargo llvm-cov \
330337
--features docker-e2e,cargo,golang,maven,composer,nuget,deno \
331338
--no-report \
332-
--test docker_e2e_${{ matrix.ecosystem }}
339+
--test docker_e2e_${{ matrix.ecosystem }} $EXTRA
333340
334341
- name: Generate per-ecosystem lcov
335342
run: |

CHANGELOG.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,50 @@ in this file — see `.github/workflows/release.yml` (`version` job).
1616

1717
### Added
1818

19+
- **`vendor` now supports every major npm and pypi package manager.** The npm
20+
ecosystem gained four lockfile flavors beyond `package-lock.json` — yarn
21+
classic (`yarn.lock` v1), yarn berry with the node-modules linker
22+
(`resolutions` + a cache-zip `10c0` checksum reproduced offline from the
23+
vendored tarball), pnpm (`pnpm.overrides` + `pnpm-lock.yaml` surgery, pnpm 9
24+
& 10), and bun (`bun.lock`) — all sharing the one vendored tarball and
25+
selected by a content-sniffing probe (yarn-berry PnP and bun's binary
26+
`bun.lockb` are refused with pointers to the native flow). The pypi
27+
ecosystem gained poetry, pdm, and pipenv (lock-only `[[package]]` / entry
28+
splices, like the existing uv/requirements flavors). Every lockfile
29+
checksum/reference field for a vendored package is now recomputed
30+
coherently (the v2 "update checksums and references" directive); the gem
31+
backend handles bundler ≥ 2.6's optional `CHECKSUMS` section; composer's
32+
`dist.reference` carries the patch UUID into `installed.json`. Each flavor
33+
has a real-package-manager build-proof capstone (fresh-checkout, cold-cache,
34+
strictest-install — `--frozen`/`--immutable`/`--deploy`/`--locked` — with
35+
byte-identical revert). `vendor --force`/`--revert` accept empty env vars
36+
(`SOCKET_FORCE=`) as false, matching the global-flag contract.
37+
38+
- **New `vendor` subcommand: committable vendoring of patched dependencies.**
39+
Where `apply` patches installed packages in place (machine-local state),
40+
`socket-patch vendor` ejects each patched package into a committed
41+
`.socket/vendor/<ecosystem>/<patch-uuid>/<artifact>` and rewires the
42+
ecosystem's lockfile so the project consumes the vendored copy — after
43+
committing, a fresh checkout builds with the patched dependency on machines
44+
with no socket-patch installed and no Socket API access. Per ecosystem
45+
(each mechanism validated against the real package manager): npm rewrites
46+
`package-lock.json` only (deterministic patched tarball, recomputed
47+
integrity, `npm ci`-verified); cargo writes a `[patch.crates-io]` entry in
48+
`.cargo/config.toml` plus surgical Cargo.lock edits so `cargo build
49+
--locked --offline` works; golang reuses the `replace`-directive engine
50+
pointed at the vendor tree; composer rewrites the lock entry to a
51+
`dist: path` copy; gem edits the Gemfile + Gemfile.lock pair in bundler's
52+
canonical form; pypi rebuilds a valid wheel (regenerated RECORD) wired
53+
through uv's `pyproject.toml`/`uv.lock` pair (uv-first) or
54+
requirements.txt (`pip` / `uv pip`). The patch UUID is recoverable from the
55+
lockfile path string alone (a documented convention for external tools), a
56+
committed `.socket/vendor/state.json` ledger records the verbatim original
57+
lockfile fragments, and `vendor --revert` restores them byte-exactly.
58+
`vendor --vex` mirrors `apply --vex`; VEX generation attests vendored
59+
patches by hashing the committed artifacts, and `apply` yields ownership of
60+
vendored packages (`vendored` skip reason).
61+
62+
1963
- **Cargo support (`cargo` is now a default feature).** `apply` patches a Rust
2064
dependency **in place** wherever the crawler finds it — the project `vendor/`
2165
directory or the shared `$CARGO_HOME` registry cache — rewriting the crate's
@@ -59,6 +103,15 @@ in this file — see `.github/workflows/release.yml` (`version` job).
59103
individually, so one exotic package can't fail a whole scan). Rate limits
60104
and over-capacity 503s still surface instead of silently degrading. (MINOR)
61105

106+
### Fixed
107+
108+
- **VEX now attests Go `replace`-redirect patches.** `socket-patch vex`
109+
previously verified golang patches against the pristine module cache
110+
instead of the patched `.socket/go-patches/` copy, so redirect-applied
111+
patches were silently omitted from the document (reported `not_applied`,
112+
or `package_not_found` on cache-less CI). Verification now follows the
113+
managed `replace` directive to the committed copy.
114+
62115
## [3.2.0] — 2026-05-29
63116

64117
A repo-wide correctness, security, and filesystem-safety hardening pass: every

Cargo.lock

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ clap = { version = "=4.5.60", features = ["derive", "env"] }
1717
serde = { version = "=1.0.228", features = ["derive"] }
1818
serde_json = { version = "=1.0.149", features = ["preserve_order"] }
1919
sha2 = "=0.10.9"
20+
sha1 = "=0.10.6"
2021
hex = "=0.4.3"
2122
reqwest = { version = "=0.12.28", features = ["rustls-tls", "json"], default-features = false }
2223
tokio = { version = "=1.50.0", features = ["full"] }
@@ -32,6 +33,7 @@ once_cell = "=1.21.3"
3233
qbsdiff = "=1.4.4"
3334
tar = "=0.4.46"
3435
flate2 = "=1.1.9"
36+
zip = { version = "=8.6.0", default-features = false, features = ["deflate"] }
3537
fs2 = "=0.4.3"
3638
wiremock = "=0.6.5"
3739
portable-pty = "=0.9.0"

0 commit comments

Comments
 (0)