Skip to content

Commit 05906f4

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix/maven-discovery-false-attestation
# Conflicts: # crates/socket-patch-cli/CLI_CONTRACT.md # crates/socket-patch-cli/src/commands/vex_sources.rs # crates/socket-patch-core/src/vex/discover/mod.rs
2 parents de7254b + 7c08fd8 commit 05906f4

51 files changed

Lines changed: 7520 additions & 1994 deletions

Some content is hidden

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

‎crates/socket-patch-cli/CLI_CONTRACT.md‎

Lines changed: 7 additions & 5 deletions
Large diffs are not rendered by default.

‎crates/socket-patch-cli/src/commands/scan/discovery.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ mod tests {
722722
resolved: None,
723723
integrity: LockIntegrity::None,
724724
source_kind: SourceKind::Unspecified,
725+
pnpm_env: false,
725726
}
726727
}
727728

‎crates/socket-patch-cli/src/commands/scan/mod.rs‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,10 @@ fn overlap_from_states(
981981
/// them to right now — the truth source for takeover direction.
982982
///
983983
/// Both directions are proved by lockfile discovery with the same liveness
984-
/// rules `vex` gates attestations on (core `Discovery::redirect_record_live`
985-
/// / `Discovery::vendor_entry_live`). `redirect` holds the overlap PURLs the
984+
/// rules `vex` gates attestations on (core `Discovery::redirect_record_verdict`
985+
/// / `Discovery::vendor_entry_live`); a hosted record on a patch server this
986+
/// run was not given (`RecordLiveness::Undecided`) counts as wired, since the
987+
/// wiring is still there. `redirect` holds the overlap PURLs the
986988
/// lock routes to the hosted patch server (the vendored ledger entry is
987989
/// stale); `vendored` holds those it routes to a committed
988990
/// `.socket/vendor/<eco>/<uuid>` artifact.
@@ -1067,7 +1069,7 @@ pub(super) async fn classify_overlap_takeover_with(
10671069
let mut liveness = LedgerLiveness::new(cwd, discovery, None);
10681070
for purl in overlap {
10691071
let hosted_live = match redirect_uuid_by_purl.get(&PurlKey::new(&purl)) {
1070-
Some(uuid) => liveness.redirect_record(&purl, uuid).await,
1072+
Some(uuid) => liveness.redirect_record_retained(&purl, uuid).await,
10711073
None => discovery.wires_package(&purl, WiringMode::Hosted),
10721074
};
10731075
// `None`: undecided (a JVM pom that cannot be read, or a tree still
@@ -1394,8 +1396,9 @@ async fn gradle_scan(
13941396
/// pin names the purl (`redirect_state`, the lockfiles' hosted state — see
13951397
/// [`crate::commands::hosted_state_from_pins`]) AND lockfile discovery
13961398
/// proves the current lockfile still routes it to that hosted patch — core
1397-
/// `Discovery::redirect_record_live`, the same liveness rule `vex` gates
1398-
/// hosted attestations on.
1399+
/// `Discovery::redirect_record_verdict`, the same liveness rule `vex` gates
1400+
/// hosted attestations on, keeping a record on a patch server this run was
1401+
/// not given (`RecordLiveness::Undecided`): its wiring is still retained.
13991402
///
14001403
/// Deliberately NOT routed through [`classify_overlap_takeover`]: that
14011404
/// classifier keys on purls present in BOTH ledgers, so hosted-only wiring
@@ -1438,7 +1441,7 @@ pub(super) async fn hosted_wiring_retained_purls(
14381441
let mut liveness = LedgerLiveness::new(cwd, &discovery, None);
14391442
let mut out = Vec::new();
14401443
for (purl, uuid) in candidates {
1441-
if liveness.redirect_record(&purl, uuid).await {
1444+
if liveness.redirect_record_retained(&purl, uuid).await {
14421445
out.push(purl);
14431446
}
14441447
}

‎crates/socket-patch-cli/src/commands/vex_sources.rs‎

Lines changed: 147 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444
//! whatever raw text survives. Only for a uuid no read file mentions
4545
//! (formats no extractor reads, patch servers outside the host allowlist)
4646
//! does the ledger's own recorded wiring decide — only files that PIN the
47-
//! resolution, never a leftover registry definition; a vendor entry
47+
//! resolution, never a leftover registry definition — and a hosted
48+
//! record whose lock entry or recorded wiring routes the uuid through a
49+
//! hosted-shaped url on an origin this run was not given is never
50+
//! attested (core `RecordLiveness::Undecided`, fail closed); a vendor entry
4851
//! recording no wiring (repair's reconstruction) probes its ecosystem's
4952
//! root locks; a lock inventory entry resolving the purl elsewhere is
5053
//! dead. A reverted lockfile plus a leftover ledger or artifact must not
@@ -82,7 +85,7 @@ use socket_patch_core::utils::purl::strip_purl_qualifiers;
8285
use socket_patch_core::utils::purl_key::{canonical_base_purl, PurlKey};
8386
use socket_patch_core::vendor::state::{VendorArtifact, VendorEntry, VendorState};
8487
use socket_patch_core::vex::discover::{
85-
vendor_ref, Discovery, LedgerLiveness, PatchedRef, WiringMode,
88+
vendor_ref, Discovery, LedgerLiveness, PatchedRef, RecordLiveness, WiringMode,
8689
};
8790
use socket_patch_core::vex::{FailedPatch, Unattested, UnattestedKind};
8891

@@ -237,6 +240,14 @@ const NOTE_MAVEN_PROFILE_UNPATCHED: &str = "vex_maven_profile_unpatched";
237240
/// Omission tag and note for [`UnattestedKind::MavenConfigOverride`]
238241
/// (`vex::Unattested`).
239242
const NOTE_MAVEN_CONFIG_OVERRIDE: &str = "vex_maven_config_override";
243+
/// Omission tag and note: a hosted Cargo pin beside another declaration of
244+
/// the crate that names no Socket registry, which cargo resolves as a
245+
/// separate, unpatched package (`vex::Unattested`).
246+
const NOTE_CARGO_UNPINNED_DECLARATION: &str = "vex_cargo_unpinned_declaration";
247+
/// Omission tag and note: a vendored Cargo copy beside a copy of the crate
248+
/// from a source its `[patch]` entry does not redirect (another registry,
249+
/// git), which cargo builds unpatched (`vex::Unattested`).
250+
const NOTE_CARGO_PATCH_BYPASSED: &str = "vex_cargo_patch_bypassed";
240251
/// Omission tag and note: a pnpm lock pins the patch, but a
241252
/// `pnpm-lock.<branch>.yaml` exists, which pnpm installs from instead when
242253
/// `gitBranchLockfile` is on; its presence withholds (`vex::Unattested`).
@@ -321,6 +332,15 @@ fn unattested_note(kind: UnattestedKind) -> (&'static str, &'static str) {
321332
through; the wiring itself is intact, so re-running `scan` does not change this \
322333
(drop that -D from .mvn/maven.config, or write the pinned version literally)",
323334
),
335+
UnattestedKind::CargoUnpinnedDeclaration => (
336+
NOTE_CARGO_UNPINNED_DECLARATION,
337+
"not attested while that declaration stands",
338+
),
339+
UnattestedKind::CargoPatchBypassed => (
340+
NOTE_CARGO_PATCH_BYPASSED,
341+
"not attested while that copy can build beside the vendored one; the vendored \
342+
wiring itself is intact (the warning above says how to clear it)",
343+
),
324344
UnattestedKind::PnpmGitBranchLock => (
325345
NOTE_PNPM_GIT_BRANCH_LOCKFILE,
326346
"not attested while any branch lock exists (or the members that could hold one \
@@ -681,9 +701,14 @@ pub(crate) async fn plan(
681701
continue;
682702
}
683703
} else if cand.redirected {
684-
let live = assumed.contains(strip_purl_qualifiers(&cand.key))
685-
|| liveness.redirect_record(&cand.key, &cand.uuid).await;
686-
if live {
704+
let verdict = if assumed.contains(strip_purl_qualifiers(&cand.key)) {
705+
RecordLiveness::Live
706+
} else {
707+
liveness
708+
.redirect_record_verdict(&cand.key, &cand.uuid)
709+
.await
710+
};
711+
if verdict.attests() {
687712
Basis::Hosted {
688713
lockfile_basis: false,
689714
}
@@ -692,6 +717,9 @@ pub(crate) async fn plan(
692717
// purl: verify it as the agent-mode patch it now is.
693718
Basis::Installed
694719
} else {
720+
if verdict == RecordLiveness::Undecided {
721+
notes.push(foreign_origin_note(&cand.key, &cand.uuid));
722+
}
695723
notes.extend(dead_claim_notes(
696724
&discovery,
697725
&cand.key,
@@ -1117,6 +1145,20 @@ fn dead_claim_notes(
11171145
notes
11181146
}
11191147

1148+
/// Why a hosted-ledger record whose wiring resolves from a patch server
1149+
/// this run was not given ([`RecordLiveness::Undecided`]) is not attested:
1150+
/// fail closed, and say how a staging server is admitted.
1151+
fn foreign_origin_note(key: &str, uuid: &str) -> PlanNote {
1152+
PlanNote {
1153+
code: NOTE_CLAIM_UNWIRED,
1154+
detail: format!(
1155+
"{key}: the hosted ledger records patch {uuid}, but its wiring resolves it from a \
1156+
patch server this run was not given; pass --patch-server-url for a non-production \
1157+
patch server; not attested"
1158+
),
1159+
}
1160+
}
1161+
11201162
/// A local record for `uuid` (manifest, then redirect ledger, then vendor
11211163
/// entries) with the key it is filed under.
11221164
fn local_record_by_uuid(
@@ -2111,6 +2153,106 @@ mod tests {
21112153
);
21122154
}
21132155

2156+
/// A hosted Cargo pin beside an unpinned declaration of the crate is
2157+
/// omitted as `vex_cargo_unpinned_declaration`, the note naming the
2158+
/// declaration and the remedy.
2159+
#[tokio::test]
2160+
async fn a_cargo_pin_beside_an_unpinned_declaration_is_gated() {
2161+
const PURL: &str = "pkg:cargo/serde@1.0.1";
2162+
let tmp = tempfile::tempdir().unwrap();
2163+
let mut redirect = RedirectState::new();
2164+
redirect.records.insert(PURL.into(), record(U1));
2165+
let mut found = discovery(vec![hosted_ref(PURL, U1, true)]);
2166+
found.unattested.push(socket_patch_core::vex::Unattested {
2167+
purl: PURL.into(),
2168+
uuid: U1.into(),
2169+
file: "crates/a/Cargo.toml".into(),
2170+
detail: "crates/a/Cargo.toml declares serde \"1\" from crates.io, not registry \
2171+
\"socket-patch-…\"; re-run `socket-patch scan` to pin it too"
2172+
.into(),
2173+
kind: UnattestedKind::CargoUnpinnedDeclaration,
2174+
});
2175+
let gated = plan(
2176+
&common(tmp.path()),
2177+
Sources {
2178+
manifest: PatchManifest::new(),
2179+
vendor: VendorState::new(),
2180+
redirect: Some(redirect),
2181+
discovery: found,
2182+
},
2183+
&[],
2184+
&RunApiClient::new(),
2185+
)
2186+
.await;
2187+
assert!(gated.view.patches.is_empty() && gated.hosted.is_empty());
2188+
assert_eq!(
2189+
gated.gated,
2190+
vec![failed(PURL, NOTE_CARGO_UNPINNED_DECLARATION)]
2191+
);
2192+
assert!(
2193+
gated
2194+
.notes
2195+
.iter()
2196+
.any(|n| n.code == NOTE_CARGO_UNPINNED_DECLARATION
2197+
&& n.detail.contains("crates/a/Cargo.toml declares serde")
2198+
&& n.detail.ends_with(
2199+
"re-run `socket-patch scan` to pin it too; not attested while that \
2200+
declaration stands"
2201+
)),
2202+
"{:?}",
2203+
gated.notes
2204+
);
2205+
}
2206+
2207+
/// A vendored Cargo copy beside a copy of the crate its `[patch]`
2208+
/// entry does not redirect is omitted as `vex_cargo_patch_bypassed`,
2209+
/// the note naming that copy and the remedy.
2210+
#[tokio::test]
2211+
async fn a_vendored_cargo_copy_beside_a_bypassing_source_is_gated() {
2212+
const PURL: &str = "pkg:cargo/serde@1.0.1";
2213+
let tmp = tempfile::tempdir().unwrap();
2214+
let mut manifest = PatchManifest::new();
2215+
manifest.patches.insert(PURL.into(), record(U1));
2216+
let vref = vendor_ref(&format!(".socket/vendor/cargo/{U1}/serde-1.0.1")).unwrap();
2217+
let mut found = discovery(vec![PatchedRef::vendored(
2218+
PURL.into(),
2219+
&vref,
2220+
"Cargo.toml",
2221+
None,
2222+
)]);
2223+
found.unattested.push(socket_patch_core::vex::Unattested {
2224+
purl: PURL.into(),
2225+
uuid: U1.into(),
2226+
file: "crates/a/Cargo.toml".into(),
2227+
detail: "crates/a/Cargo.toml declares serde \"1\" from registry `my-corp`".into(),
2228+
kind: UnattestedKind::CargoPatchBypassed,
2229+
});
2230+
let gated = plan(
2231+
&common(tmp.path()),
2232+
Sources {
2233+
manifest,
2234+
vendor: VendorState::new(),
2235+
redirect: None,
2236+
discovery: found,
2237+
},
2238+
&[],
2239+
&RunApiClient::new(),
2240+
)
2241+
.await;
2242+
assert!(gated.view.patches.is_empty() && gated.hosted.is_empty());
2243+
assert_eq!(gated.gated, vec![failed(PURL, NOTE_CARGO_PATCH_BYPASSED)]);
2244+
assert!(
2245+
gated
2246+
.notes
2247+
.iter()
2248+
.any(|n| n.code == NOTE_CARGO_PATCH_BYPASSED
2249+
&& n.detail.contains("from registry `my-corp`")
2250+
&& n.detail.contains("says how to clear it")),
2251+
"{:?}",
2252+
gated.notes
2253+
);
2254+
}
2255+
21142256
/// Ledger-only records with no wiring anywhere are gated, except the
21152257
/// manifest-owned one, which falls back to agent-mode verification; an
21162258
/// in-run confirmed purl is live by construction.

‎crates/socket-patch-cli/tests/e2e_vex_lockfile/cargo.rs‎

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -913,48 +913,31 @@ fn cargo_hosted_f_spoofed_references_never_attest() {
913913
let run = fx.vex(&["--proxy-url", &api.uri()]);
914914
assert_nothing_discovered(&run, "foreign host");
915915
assert_eq!(api.hits(), 0, "a foreign-host uuid is never even fetched");
916-
// DELIBERATE (the staging fallback): a uuid on a host outside the
917-
// allowlist is not a lockfile reference, but it is not "recognized"
918-
// either, so a redirect-ledger record for it falls back to the ledger's
919-
// own recorded wiring files — which still name it — so that a staging
920-
// `scan --mode hosted` run without `--patch-server-url` keeps
921-
// attesting. Hash verification still judges the copy the build
922-
// consumes (the foreign registry's): nothing is installed here, so the
923-
// default run omits it; only `--no-verify`, which trusts the ledger's
924-
// record by definition, attests.
916+
// Fail closed: a ledger record wired through a hosted-shaped url on an
917+
// unconfigured origin is `redirect_unwired` whatever is installed, even
918+
// under `--no-verify` (CLI_CONTRACT.md, "Patch hosts (manifest-less VEX)").
925919
write_redirect_ledger(&fx, CARGO_PURL, cargo_record(U), CARGO_HOSTED_EDITS);
926-
let run = fx.vex(&["--offline"]);
927-
assert_omitted(
928-
&run,
929-
CARGO_PURL,
930-
"package_not_found",
931-
"foreign host + ledger",
932-
);
933-
fx.install_crate(SOCKET_CARGO_SRC, PATCHED_RS);
934-
let run = fx.vex(&["--offline"]);
935-
assert_omitted(
936-
&run,
937-
CARGO_PURL,
938-
"package_not_found",
939-
"foreign host + ledger: Socket's copy is not what this lock builds",
940-
);
941-
fx.install_crate("evil.example-0123456789abcdef", PRISTINE_RS);
942-
let run = fx.vex(&["--offline"]);
943-
assert_eq!(
944-
run.code,
945-
Some(1),
946-
"foreign registry's pristine copy: {}",
947-
run.env
948-
);
949-
let run = fx.vex(&["--offline", "--no-verify"]);
950-
assert_attested(
951-
&fx,
952-
&run,
953-
CARGO_PURL,
954-
U,
955-
"redirected",
956-
"staging fallback, --no-verify",
957-
);
920+
for (state, install) in [
921+
("not installed", None),
922+
("Socket's patched copy", Some(SOCKET_CARGO_SRC)),
923+
(
924+
"the foreign registry's patched copy",
925+
Some("evil.example-0123456789abcdef"),
926+
),
927+
] {
928+
if let Some(src) = install {
929+
fx.install_crate(src, PATCHED_RS);
930+
}
931+
for extra in [&["--offline"][..], &["--offline", "--no-verify"][..]] {
932+
let run = fx.vex(extra);
933+
assert_omitted(
934+
&run,
935+
CARGO_PURL,
936+
"redirect_unwired",
937+
&format!("foreign host + ledger, {state} {extra:?}"),
938+
);
939+
}
940+
}
958941

959942
// The same foreign origin configured as the operator's patch server.
960943
let fx = Fx::new();

0 commit comments

Comments
 (0)