Repository navigation
Withhold a vendored Cargo copy a member's other source bypasses - #2024
Conversation
06d306c to
77a4d2d
Compare
|
Burn-down agent: resolved the merge conflicts with
Generated by Claude Code |
`vendor` wires a crate through the root's `[patch.crates-io]`, which cargo applies only to declarations from crates.io. A workspace member (or the root) that declares the crate from another registry, a `registry-index` or git, at a requirement that may select the patched version, resolves its own unpatched copy. The vendored ref stayed attested beside it because the lock copy claim only reads sourceless entries. The ref now stays (rollback, remove and the ledgers still see the wiring) but is marked unattested with the new `UnattestedKind::CargoPatchBypassed`, naming the declaration. A same-version Cargo.lock entry from any registry or git source beside the copy is marked the same way, naming the lock entry. The check reads the declarations through #2019's classification: live declarations only, a registry dependency counts as covered when a `[patch.<registry>]` table pointing at the same copy redirects it (`Decl::patched_by`), a path declaration (the user's own fork) keeps the existing "ignored" rule, and a `socket-patch-*` registry dependency is hosted wiring. The CLI omits the ref as `vex_cargo_patch_bypassed`; documented in CLI_CONTRACT.md. The workspace member walk ran only when the lock held a Socket-sourced package (or, with no lock, a manifest named a `socket-patch-` registry). A vendored copy's lock entry has no source and it has no such pin, so the walk now also runs whenever the root manifest or the project config wires a Socket copy through `[patch]`, whatever the lock's state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5b08b24 to
64d73a6
Compare
Three Cargo follow-ups to the declaration classification: Lockless pins read declarations like locked ones. A `socket-patch-<uuid>` registry beside `path`, `git` or `registry-index` is no pin (cargo builds that source, and the rewriter's own pinned check agrees), so it no longer adds its requirement to an `UnlockedPin` or makes one on its own. It counts as an unpinned declaration instead, excluding the versions it accepts (every version, without a requirement). A `[workspace.dependencies]` template no manifest inherits is no declaration: a Socket-pinned one makes no lockless pin, and an unpinned one excludes nothing from the root's pin. A non-Socket `[patch]` registry entry no longer counts as an unpinned declaration either (it redirects declarations, it adds none). `DeclSource::Git` keeps its URL, and `Decl::patched_by` matches a `[patch."<repository URL>"]` table against it (a trailing `/` or `.git` ignored). So a git declaration whose repository table points at the same vendored copy no longer withholds that copy, while one from another repository still does. Hosted routing gains the same match for a Socket registry pin in such a table. When no declaration pins the lock's patch, a pin to another patch now makes the conflict pair only when it is live and its requirement may select the locked version (`cargo_req_selects`). One that excludes it is about another version; the stale lock entry is then diagnosed and dropped like any unrouted one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
False attestation: the vendored bypass check counted a declaration as redirected by any root or config `[patch]` entry pointing at the copy, including a manifest entry cargo ignores (the project config redefines its crates.io key, or a crates.io URL table replaces `[patch.crates-io]`). Cargo then builds whatever replaced it for those declarations, while the copy's other, honored entry was attested. Only honored entries count now: the root's `[patch]` entries are collected once with their shadow reason (a `Shadow` built from the root manifest and the config), and the bypass check sees only the unshadowed ones. `vendored` (the member gate) is derived from the same list instead of re-reading every `[patch]` table. One classifier: the bypass check runs each declaration through `route` with the copy's honored `[patch]` tables as the pins, as hosted pins do, passing the lock's other versions of the crate. A path declaration (the user's own fork) is still left alone. `patched_by` now covers a `registry-index` declaration with a `[patch."<index URL>"]` table for the same index (a `registry+` prefix, host case and a trailing `/` ignored; `sparse+` is another source), and treats a `registry-index` naming the crates.io git index as crates.io. The sparse crates.io index stays a separate source. Git URLs compare as cargo's `CanonicalUrl` spells them (one trailing `/` and a `.git` suffix dropped, a GitHub URL lowercased whole, any host lowercased). The bypass detail ends with the remedy for its evidence: a declaration (re-running `vendor` does not help), a crates.io lock entry beside a `[patch.crates-io]` copy (stale: re-lock), or another lock entry (`cargo tree -i` names its declarer). The CLI note no longer claims re-vendoring never helps. Diagnostics: a Socket pin to another patch that the lock does not reflect (its requirement excludes every locked version) used to vanish once any Socket entry of the crate was locked; it is now diagnosed `patched_ref_unattributable`. A well-formed `socket-patch-<uuid>` registry that pins nothing (beside `path` / `git` / `registry-index`, or on a `[workspace.dependencies]` entry no manifest inherits) is diagnosed `patched_ref_invalid`. The committed `workspace-member` redirect golden gains that diagnostic: its `expected/` tree omits the unchanged inheriting member, so the pinned template reads as uninherited there. `Decl::describe` and `same_version_foreign_entry` are shared by the hosted and vendored checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o fix/cargo-vendored-twins-and-split-patches # Conflicts: # crates/socket-patch-core/src/vex/discover/cargo.rs
FALSE ATTESTATION (found reviewing #2019; fixed here, where `Shadow` lives): a root `[patch.crates-io]` Socket registry pin cargo ignores (a `[patch."<crates.io URL>"]` table replaces it, or the config redefines the key) still counted as pinning every crates.io declaration of the crate, so a member's plain declaration was taken as routed to the patch and the hosted ref attested while cargo builds crates.io. Such an entry stays a declaration (Socket's wiring is present, the ref stays) but is not live, and `route` only weighs live `[patch]` pins, as the vendored bypass check already weighs only honored entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Pathless config patch still counts as live
- Changed the shadowing detection logic from '*p != own' to '!(p.is_some() && *p == own)' so that path-less config patches properly shadow path-less manifest patches while preserving the same-path exception.
Or push these changes by commenting:
@cursor push 93a51234a1
Preview (93a51234a1)
diff --git a/crates/socket-patch-core/src/vex/discover/cargo.rs b/crates/socket-patch-core/src/vex/discover/cargo.rs
--- a/crates/socket-patch-core/src/vex/discover/cargo.rs
+++ b/crates/socket-patch-core/src/vex/discover/cargo.rs
@@ -1435,7 +1435,7 @@
let own = path.map(same_path_key);
self.config_keys
.iter()
- .find(|(_, k, p)| k == key && *p != own)
+ .find(|(_, k, p)| k == key && !(p.is_some() && *p == own))
.map(|(file, k, _)| {
format!("{file} redefines `[patch]` key `{k}`, which replaces it in cargo")
})You can send follow-ups to the cloud agent here.
Cargo replaces a manifest [patch] item with a project-config item of the same source and key, whatever the source table and whether either wires a path. Shadow only looked at crates.io tables and treated two path-less items (a registry pin and a git fork) as the same wiring, so a config fork left the manifest's Socket pin live and its stale lock row could be attested. Only an identical path is now the same wiring, and named and URL tables are compared too (URLs as an index key). The ineffective-registry diagnostic also called a shadowed [patch] pin an uninherited [workspace.dependencies] template; it now says cargo ignores the [patch] entry. Addresses Bugbot 4501098254, 4501098256 and 4501098258. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
Shadow compared a config's [patch."<url>"] table with the manifest's through index_key, which keeps a trailing .git and a GitHub path's case. Cargo canonicalizes both, so a config item under a canonical-equivalent git URL replaced the manifest's Socket copy while discovery still counted it. Non-sparse URL tables now compare through git_key; sparse+ ones stay index keys (another source). Addresses Bugbot 4501313607. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
…plit-patches The base picked up #2012's main merge, which added the npm-family, sbt, NuGet and Go UnattestedKind variants and their vex notes. This branch adds CargoPatchBypassed. The two sides only add entries, so the merge keeps both: - vex/discover/mod.rs: CargoPatchBypassed comes after CargoUnpinnedDeclaration, then the base's variants and file_scoped(). Cargo stays non-file-scoped. - vex_sources.rs: keeps both sides' note constants and unattested_note() arms. - CLI_CONTRACT.md: keeps the base's paragraph, appends this branch's vendored-Cargo case, and changes the case count from "Nine" to "Ten". The reasons table keeps both sides' rows. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
…plit-patches Resolve the patched_by conflict: keep this branch's per-source match (registry, registry-index, git) and apply the base's fix that reads an explicit registry = "crates-io" as crates.io in the Registry arm. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
patch_bypassed only withheld the vendored ref for declarations route() finds Unpinned. A member declaring the crate from another socket-patch registry routes to Pin(other) and was skipped. When the lock resolves the crate from that patch, its hosted ref sits beside the vendored one and the CLI's wiring_conflict gate refuses both. When the lock is stale and holds no entry from that patch, only a patched_ref_unattributable diagnostic was left, and patch A was attested even though the member re-resolves to patch B. Mark the vendored copy CargoPatchBypassed in that case instead. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run Generated by Claude Code |
The exemption for a member pinned to another Socket patch trusted any lock line from that patch. hosted_from_lock drops a line whose project registry definition disagrees, and a line at another version is no ref for this package, so wiring_conflicts never fired and the vendored copy stayed attested. Exempt only when the hosted pass emitted a ref for that patch at this very purl that is not itself withheld. Co-Authored-By: Claude <noreply@anthropic.com>
|
bugbot run 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 bc39a27. Configure here.
…plit-patches Brings #2012's fail-closed liveness and #2019's round-3 review fixes. Conflict in beside_the_pin's declaration text: kept this branch's Decl::describe and moved #2019's 'which overrides its registry' clause into it, so every caller says it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review on #2024 (/code-review high), round 4: - The "resolves it only from other Socket patches" diagnostic fired beside a same-version crates.io twin; it now needs a lock with no non-Socket entry of the crate. - Shadow resolves a [patch.<registry>] table through the config's [registries] index, so a config [patch."<index>"] item shadows it. - An identical path-less Socket registry [patch] pin in the manifest and the config is the same wiring, not a shadow. - patched_by (registry-index) and same_patch_source share patch_source_key, with CanonicalUrl rules on both. - patch_bypassed's conflict-gate check matches the CLI's bypassed_ref (file-scoped marks only); it routes each declaration once; its detail also names other-patch declarations; a git lock entry a git [patch] table redirects gets the stale/re-lock remedy. - Reuse patch::redirect::is_crates_io_source for lock sources. - Move the manifests comment back above its vector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f87fc9f
into
fix/cargo-members-liveness-origin
|
Not merged to |
Behavior-preserving cleanup of #2012 after #2019 and #2024 were folded in: - One `distinct<T>` replaces four hand-written order-preserving dedups; `describe_all` and one `other_declared` replace repeated describe/join chains. - `DeclSource::patched_by` is the one redirect rule; the bypass check's stale-entry test maps the lock source to a `DeclSource` instead of re-deriving crates.io and git matching. `index_key` is folded into `patch_source_key`. - `beside_the_pin` collects the lock's Socket uuids once; the manifests are serialized for the rewriter's dry planner once per discovery (`ManifestTexts`), not per crate. `vendored_from_patches` takes the lock from `Bypass`; the two `decls` passes in `extract` are one. - `foreign_hosted_uuid` moves to `origin::hosted_shape_uuid`, so `normalized_hosted_url` is private again; the cheap accepted-origin check runs first in `foreign_hosted_url_in_files`. - Comments and docs no longer narrate review history; the cargo module doc points at `beside_the_pin` / `patch_bypassed` instead of restating them; CLI_CONTRACT.md states the registry-index rule once and the `apply` sentence parses. - Tests share `workspace_root`, `member`, `one_mark` and `shadow` instead of respelling manifests and config parsing; the e2e fail-closed comments point at CLI_CONTRACT.md. Review of the simplify diff (/code-review high): the stale-lock remedy named `[patch.crates-io]` and `socket-patch vendor` for a git entry too; it now names the table that redirects the entry and offers `vendor` only for crates.io. CLI_CONTRACT.md keeps the member-walk and uninherited- template rules the trim had dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Stacked on #2019 (
fix/cargo-mixed-member-pins). It closes the vendored-mode Cargo false-attestation gap the #2019 author found.The second gap, a root pinning a crate to one Socket patch while a member pins it to another, is now handled by #2019 itself (
beside_the_pinemits the other patch'sCargo.tomlref, so the CLI gates it aswiring_conflict). This PR no longer touches it. I ran my earlier split-patch tests against #2019's code alone and they pass, so there was nothing left to keep.Vendored copy bypassed by another source
vendorwires a crate through the root's[patch.crates-io], and cargo applies that only to crates.io declarations. A workspace member (or the root) can declare the crate from another registry, aregistry-indexor a repository URL, at a requirement that may select the patched version. That declaration resolves its own unpatched copy. The vendored ref still attested beside it, because the lock copy claim (vendored_copy_claim) only reads sourceless entries.UnattestedKind::CargoPatchBypassed. The detail names the declaration.Cargo.lockentry at exactly the patched version from any registry or repository source, beside the copy, is marked the same way. The detail names that lock entry.DeclSourceclassification:[workspace.dependencies]template no manifest inherits doesn't.[patch.<registry>]table pointing at the same copy redirects it (Decl::patched_by). A git dependency is covered by a[patch."<repository URL>"]table pointing at the copy (see the follow-ups below).a_same_version_fork_beside_the_tagged_copy_is_ignoredalready specifies.socket-patch-*registry dependency is hosted wiring, handled by Stop attesting a Cargo pin a workspace member resolves from crates.io #2019.vex_cargo_patch_bypassed. It's documented in CLI_CONTRACT.md (Unattested references paragraph and the notes table).I added a new variant rather than reusing
CargoUnpinnedDeclaration. That variant's note tells the user to re-runscan, which is the wrong fix for vendored wiring.Member gate. #2019 reads workspace members only when the lock holds a Socket-sourced package (or, with no lock, a manifest names a
socket-patch-registry). A vendored copy's lock entry has no source, so the members are now also read whenever the root manifest or the project config wires a Socket copy through[patch], whatever the lock's state.Cargo follow-ups (second commit)
unresolved_manifest_pins,UnlockedPin,only_this_patch).socket-patch-<uuid>registry besidepath,gitorregistry-indexis no pin, matching the rewriter's pinned check. It no longer feeds anUnlockedPin; it counts as an unpinned declaration that excludes the versions it accepts (all of them, without a requirement).[workspace.dependencies]template no manifest inherits is no declaration.[patch]registry entry no longer counts as an unpinned declaration (it redirects, it declares nothing).DeclSource::Gitkeeps its URL.Decl::patched_bymatches it against a[patch."<repository URL>"]table (a trailing/or.gitignored). A git declaration whose repository table points at the same vendored copy no longer withholds it, while one from another repository still does. Hosted routing gets the same match for a Socket registry pin in such a table.cargo_req_selectssays it may select the locked version. Otherwise the stale lock entry is diagnosed and dropped like any unrouted one.Tests
a_member_from_another_source_bypasses_the_vendored_copy(another registry, a renamed=1.0.4, a repository URL, aregistry-index)a_same_version_lock_entry_from_any_source_bypasses_the_vendored_copya_member_from_git_bypasses_the_config_wired_copymembers_are_read_for_a_vendored_copy_without_a_socket_lock_entry(with and without a lock)declarations_the_patch_redirects_keep_the_vendored_copy_attested. It covers crates.io members in every spelling, includingregistry = "crates-io"and a rename; an excluding requirement;[patch.my-corp]coverage; a path fork; and an un-inherited workspace template.a_vendored_cargo_copy_beside_a_bypassing_source_is_gated.lockless_path_or_git_beside_a_socket_registry_is_no_pin(path / git / registry-index member beside the root's pin, and alone)lockless_uninherited_template_is_not_a_declaration(Socket-pinned template uninherited vs inherited; an uninherited crates.io template beside the root's pin)a_git_patch_table_for_the_copy_covers_that_repository_only(covered with a.git/spelling and a branch; another repository still bypasses)another_patch_pin_excluding_the_locked_version_is_no_conflictcargo test -p socket-patch-core --lib -- vex::discover:: vendor::cargo patch::redirect:: utils::cargo_workspace(includes the golden corpus test): 1564 passed.-p socket-patch-cli --lib vex_sources: 16 passed.--test in_process_redirect cargo,--test in_process_cargo_apply cargo,--test mode_migration_cargo: 6 / 3 / 30 passed.cargo clippy --locked --workspace --all-features -- -D warningsandcargo fmt --all -- --checkare clean.Review findings (
/code-review high, third commit)Each of findings 1–6 was confirmed first by a test that fails on the previous commit and passes now.
False attestation from a shadowed
[patch]entry: confirmed and fixed. The bypass check counted a manifest entry cargo ignores (the config redefines its crates.io key with a git fork) as redirecting crates.io declarations, so the copy's honored[patch.my-corp]entry was attested beside the fork. Only honored entries count now. Test:a_shadowed_manifest_entry_covers_no_declaration.registry-indexcoverage: confirmed and fixed. A[patch."<index URL>"]table now covers a declaration of the same index (aregistry+prefix, host case and a trailing/ignored). Aregistry-indexnaming the crates.io git index is crates.io. Test:a_registry_index_patch_table_covers_that_index.sparse+https://index.crates.io/) is not treated as crates.io.Cargo.lockrecords it as a distinct source string from the git crates.io index, and the files don't show that[patch.crates-io]reaches it. Treating it as covered could attest a copy cargo doesn't build, so it stays withheld. The cost is a missed attestation on a rare hand-written shape.registry = "<name>"declaration is still matched only by a[patch.<name>]table, not by its index URL (the registry's URL may live in$CARGO_HOME).Remedy per evidence: confirmed and fixed. The detail now ends with the remedy for its evidence:
vendordoesn't help;[patch.crates-io]copy: stale, so re-lock (re-runvendororcargo update -p <crate>);cargo tree -i <crate>@<version>names the dependency that declares it.The CLI note's fixed suffix no longer makes that claim. Test:
the_bypass_remedy_follows_its_evidence.Canonical git URLs: confirmed and fixed. URLs are compared as cargo's
CanonicalUrlspells them: one trailing/and.gitdropped, a GitHub URL lowercased whole, any host lowercased. Test:a_git_patch_table_matches_cargos_canonical_url.Unreflected pin to another patch lost its diagnostic: confirmed and fixed. Once the lock held any Socket entry of the crate,
unresolved_manifest_pinsskipped it, so such a pin got no ref and no diagnostic. It now getspatched_ref_unattributableunless the lock resolves the crate from that patch or a ref already carries it. Test:another_patch_pin_excluding_the_locked_version_is_no_conflict(extended).Ineffective Socket registry gets no diagnostic: confirmed and fixed. A well-formed
socket-patch-<uuid>besidepath/git/registry-index, or on a[workspace.dependencies]entry no manifest inherits, is now diagnosedpatched_ref_invalid("pins nothing there"). Test:an_ineffective_socket_registry_is_diagnosed.redirect/cargo/cargo/workspace-member/expectedtree omits the unchanged inheriting membera/, so its pinned template reads as uninherited there and now carries that diagnostic. I regenerated the golden; no other corpus project changed.socket_copiescomputed twice: fixed. It's computed once, before the root manifest moves;vendored = !wired_all.is_empty().Shared helpers: done.
Decl::describeandsame_version_foreign_entryare used by bothbeside_the_pinandpatch_bypassed.One classifier: done without widening
route.routealready takes(table, uuid)pins, so the vendored check calls it with the copy's honored[patch]tables as the pins and the lock's other versions of the crate. That is the same classifier hosted pins use, with no new parameter. The only vendored-specific rule left is that a path declaration (the user's own fork) is ignored, an existing documented rule.Not done
vendor::cargoalready refuses the lock-twin state:locked_multi_source_conflictcovers a same-version entry from two sources, andvendor_source_unsupportedcovers a non-crates.io entry. A member declaration whose other-source copy isn't locked yet is invisible to the planner without re-resolving.Cloud routine: T1 verified, brought current, one more fix
6592bf2) landed before this run. All 9 findings are addressed (see the section above). I re-ran the full T1 test set on6592bf2: discovery,vendor::cargo,patch::redirect,utils::cargo_workspace, the golden corpus, CLIvex_sources,--test in_process_redirect cargo,--test mode_migration_cargo, clippy and fmt. Everything passes exceptvlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, a chmod test that fails only because the container runs as root.1021784. Three conflicts invex/discover/cargo.rs::read_members/extract. I resolved them by combining Cargo VEX: read member manifests, match liveness by origin, withhold mixed and vendored bypasses #2012's rule (parse members whenever asocket-patch-name appears anywhere) with this PR'svendoredrule (a[patch]-wired copy always reads members).[patch.crates-io]Socket registry pin that cargo ignores is replaced either by a[patch."<crates.io URL>"]table or by a config that redefines the key. That pin still counted for hostedroute, so a member's crates.io declaration was taken as pinned. Such an entry now stays a declaration, so the ref stays, but it isn't live.routeweighs only live[patch]pins, matching what the vendored bypass check already does. Test:a_shadowed_patch_pin_pins_no_declaration. It fails without the fix.Tests after the merge and fix:
cargo test -p socket-patch-core --lib -- vex::discover:: vendor::cargo patch::redirect:: utils::cargo_workspacegives 1570 passed (the 1 failure is the root-only chmod test). CLIvex_sources,in_process_redirect cargoandmode_migration_cargopass. clippy and fmt are clean.Round 4: merged #2019,
/code-review highMerged
fix/cargo-mixed-member-pinsat 0c83105, bringing #2012's fail-closed liveness and #2019's round-3 fixes. The only conflict was inbeside_the_pin's declaration text. I kept this branch'sDecl::describeand moved #2019's "which overrides its registry" clause into it, so every caller now says it. Core and CLI vex tests pass on the merge.Fixed:
beside_the_pinhad returned early over a same-version crates.io twin. It now fires only when the lock has no non-Socket entry of the crate. Test:another_patch_pin_beside_a_foreign_twin_is_not_called_socket_only.[patch.<registry>]table and a[patch."<its index>"]table didn't compare as one source.Shadownow resolves registry names through the config's[registries]index URLs. Without this, a config git fork under the URL table left the manifest's vendored copy counted as honored. Test:config_items_shadow_pathless_and_named_source_entries(extended).gatedclosure didn't match the CLI's conflict gate. It now drops a ref from the gate only for a file-scoped mark on the ref's own file, exactly as the CLI'sbypassed_refdoes.patched_by(registry-index) andsame_patch_sourcenow sharepatch_source_key, withCanonicalUrlrules (.git, GitHub path case) on both.[patch]pin in the manifest and the config was treated as shadowed. That raised a spuriouspatched_ref_invalid. The same registry is now the same wiring, as the same path already was for copies. Test: extended as in 2.is_crates_io_lock_sourceduplicatedpatch::redirect::is_crates_io_source. It's removed, and the redirect helper is nowpub(crate).patch_bypassedranroutetwice per declaration. It's now one pass.[patch."<repo>"]table pointing at the copy redirects now gets the stale/re-lock remedy instead ofcargo tree -i.wired_alldescribedmanifests. Moved.Declined:
patched_ref_invalidforworkspace-memberencodes wrong behavior." By the redirect-fixture convention,expected/holds only the files the rewriter changed, and the golden snapshots discovery over that tree as committed.a/Cargo.toml, the inheriting member, isn't there, so the diagnostic is correct for that tree. Adding the file breaksredirect_golden's changed-file-set check, and overlayinginput/would re-snapshot every redirect family. The live-template behavior is pinned by the unit test on templates (… only for a manifest that inherits it).Tests: core
vex:: origin cargo hosted:: patch::redirect:: vendor::andredirect_golden, plus CLI--lib,e2e_vex_lockfile,e2e_vex_redirect,in_process_redirectandmode_migration_cargo. All pass. clippy and fmt are clean.Note
Medium Risk
Changes Cargo discovery and VEX attestation for vendored patches across workspaces; incorrect routing could false-negative or false-positive attestations, though coverage is heavy in tests.
Overview
Adds
vex_cargo_patch_bypassedso vendored Cargo wiring is not attested when Cargo can still build the same crate/version from a source the[patch]table does not redirect—e.g. a workspace member on another registry, git, orregistry-index, or a foreignCargo.lockentry at the patched version. The ref stays discoverable for rollback/list; onlyvexomits it.Discovery now reads workspace members whenever a Socket copy is wired via
[patch](not only Socket-sourced locks), classifies declarations/[patch]shadowing more like Cargo (honored vs ignored entries, git/index URL canonicalization, ineffectivesocket-patch-*beside path/git), and tightens lockless pin handling.CLI contract documents the new unattested case and lockless Cargo pin rules.
Reviewed by Cursor Bugbot for commit bc39a27. Configure here.
Generated by Claude Code