Commit 4868030
committed
feat(vex): manifest-less VEX — attest hosted and vendored patches from lockfiles
`socket-patch vex` and the embedded `apply` / `scan` / `vendor --vex` now
attest hosted and vendored patches with no `.socket/manifest.json` — and
with no `.socket/vendor` ledgers either — by reading the wiring out of the
project's lockfiles (`vex::discover`). This covers a depscan-opened PR, a
clone that never committed its ledgers, and a lock-only CI checkout.
Record view (`commands::vex_sources::plan`): four sources — the manifest,
the redirect ledger's records, the vendor ledger's embedded records and
lockfile discovery — merge into one view. A candidate's record must carry
the uuid the lockfile actually WIRES; it comes from the first source that
has one, else (online only) from the patch API by uuid, 10 fetches at a
time with `get`'s one-shot 401/403 → public-proxy fallback (#247's
uuid-only `ApiClient::fetch_patch`). Nothing is written: vex never takes
the apply lock, never creates `.socket/`, never writes the manifest, and
the `socket-patch.vendor.json` marker is never a record.
Gates, applied before hashing and kept under `--no-verify` (which now
skips only the hashing):
- a vendor-ledger entry attests only while a lockfile still wires its
artifact (`vendor_unwired`); a redirect-ledger record only while a
lockfile wires its hosted patch (`redirect_unwired`); discovery is
authoritative for every uuid a read file mentions, so a rejected
mention keeps nothing alive;
- `record_unavailable` (offline, 404, refused, transport error — the run
continues), `record_mismatch`, `wiring_conflict` (lockfiles wire one
package to several patches);
- a malformed / unreadable `.socket/vendor/state.json` is the hard error
`vendor_ledger_corrupt` (exit 2), mirroring `redirect_ledger_corrupt` —
this supersedes #247's degrade-and-disclose posture for `vex` only;
`setup --check` keeps #247's `vendor_context_from` /
`warn_unreadable_vendor_state` path.
Evidence: vendored refs hash the committed artifact (the ledger entry when
it names the wired artifact, else one synthesized from the ref); hosted
refs hash the installed copies the build CONSUMES
(`vex_consumed::hosted_consumed_copies` → core `VendorContext::hosted` /
`HostedCopies`: the Go replacement module, the Socket-registry cargo src
dir, maven's suffixed version — never a pristine sibling), and with
nothing installed a discovered pinned reference attests from its lockfile
pin, like in-run `scan --mode hosted --vex`. Discovered refs bypass the
Property 7 ecosystem filter.
Commands:
- `apply --vex` / `vendor --vex` with no manifest attest what the
lockfiles and ledgers wire (nothing anywhere keeps the calm exit 0 and
removes a stale document; `apply --check` and `--dry-run` never
generate); #247's no-manifest lines ("No patch manifest found; nothing
to apply.", "No manifest found, nothing to vendor.") are kept;
- failed VEX runs carry the discovery diagnostics into `warnings[]`
(standalone envelope, embedded envelopes, scan JSON — hosted included);
- `manifest_not_found` now means no manifest AND nothing wired;
- human output: `Note:` lines for superseded records / fetch failures,
phrased omission reasons.
Writer hardening: the manifest-driven standalone `vendor` now embeds the
patch `record` in its ledger entries too (vendored mode already does, as
`detached` entries). `detached` stays the "no manifest owner" flag, so
the manifest reconcile, legacy-manifest migration and get/scan
idempotency from #247 are unaffected. Every reader of embedded records
shares one ownership rule (`commands::vendor_record_is_unowned`): a
detached entry's record always stands alone, a standalone `vendor`
entry's fallback copy only when no manifest entry covers it (by ledger
key or base purl). `vex`, `list` and `setup --check`
(`fold_vendor_records`, formerly `fold_detached_records`) all apply it,
so one tree never lists "no patches" while its VEX document attests one.
`repair` stays narrower: it keeps preferring a manifest that moved on to
a newer uuid and falls back to the embedded copy only with no manifest
at all.
One liveness rule for vex and scan: `scan`'s cross-mode takeover
classification (`classify_overlap_takeover`), its
`hosted_wiring_retained` warning and `redirectState.wiringLive` ask the
same core discovery (`commands::discover_wiring`) and liveness rule
(`Discovery::redirect_record_live` / `vendor_entry_live` /
`wires_package`, through one `LedgerLiveness` holder per call site) that
gate attestation, replacing scan's private cargo / hosted / vendored
checks and its looser text scan. The CLI also shares one purl splitter
(`utils::purl::purl_parts`), one vendor-ledger lookup
(`vendor::state::lookup_entry_kv`) and one npm alias-aware identity crawl
(`ecosystem_dispatch::npm_paths_by_identity`) across vex, scan and
vendor, and pairs PEP 723 script locks through
`utils::python_lock::script_of_lock` like the rewriters do.
Output follows the conventions from #248: `ui::plural` counts, a
`ui::StatusLine` progress line for record fetches, and the shared
`format_vex_written` / `format_vex_dry_run_skip` lines on the
manifest-less `apply --vex` / `vendor --vex` paths. Manifest-less `vex`
honours `--dry-run` and `-O -` like the manifest path.
Product auto-detection adds go.mod, composer.json, pom.xml, a single
`*.csproj` and a single `*.gemspec`, after the existing probes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>1 parent 52e71ee commit 4868030
20 files changed
Lines changed: 4089 additions & 693 deletions
File tree
- crates
- socket-patch-cli/src
- commands
- scan
- socket-patch-core/src
- patch/redirect
- vendor
- vex
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
191 | | - | |
192 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
193 | 196 | | |
194 | 197 | | |
195 | 198 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
| |||
791 | 793 | | |
792 | 794 | | |
793 | 795 | | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
794 | 832 | | |
795 | 833 | | |
796 | 834 | | |
797 | 835 | | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
798 | 858 | | |
799 | | - | |
800 | | - | |
801 | | - | |
802 | | - | |
803 | | - | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
804 | 878 | | |
805 | | - | |
| 879 | + | |
806 | 880 | | |
807 | 881 | | |
808 | 882 | | |
| |||
1094 | 1168 | | |
1095 | 1169 | | |
1096 | 1170 | | |
| 1171 | + | |
1097 | 1172 | | |
1098 | 1173 | | |
1099 | 1174 | | |
| |||
1119 | 1194 | | |
1120 | 1195 | | |
1121 | 1196 | | |
1122 | | - | |
1123 | | - | |
1124 | | - | |
1125 | | - | |
1126 | | - | |
1127 | | - | |
| 1197 | + | |
1128 | 1198 | | |
1129 | 1199 | | |
1130 | 1200 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
39 | 41 | | |
40 | 42 | | |
41 | 43 | | |
| |||
62 | 64 | | |
63 | 65 | | |
64 | 66 | | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
69 | 75 | | |
70 | 76 | | |
71 | 77 | | |
| |||
88 | 94 | | |
89 | 95 | | |
90 | 96 | | |
91 | | - | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
92 | 101 | | |
93 | 102 | | |
94 | 103 | | |
| |||
817 | 826 | | |
818 | 827 | | |
819 | 828 | | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
820 | 912 | | |
821 | 913 | | |
822 | 914 | | |
| |||
0 commit comments