Skip to content

Commit 79ee1f8

Browse files
committed
Fix fail-closed handling for corrupt ledger and discovery errors
Bug 1 (b691b777): Corrupt ledger routes off JVM backend - jvm_shape: Changed from .ok()? to proper match that fail-closes on load_state error, continuing to detect shape even with corrupt ledger - vendor_maven_jvm: Changed from silently skipping inherit_peer_records on error to failing with vendor_ledger_corrupt error message Bug 2 (30f7f45e): VEX misses live JVM wiring - maven_reactor::wired: Changed from .is_ok_and() to match that returns true (fail-closed) when Reactor::discover fails with unsupported layout - entry_wired: Check for escaped paths first and return true (fail-closed) before checking wiring, matching revert's refusal behavior All changes implement fail-closed semantics: errors are treated as 'still wired' rather than 'not wired', preventing silent failures and incorrect GC of live vendored entries.
1 parent e3695a2 commit 79ee1f8

3 files changed

Lines changed: 40 additions & 12 deletions

File tree

‎crates/socket-patch-core/src/vendor/jvm/apply.rs‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -619,13 +619,17 @@ pub fn entry_wired(root: &Path, entry: &VendorEntry) -> bool {
619619
uuid: &entry.uuid,
620620
};
621621
let reader = ProjectReader::new(root);
622+
// Fail-closed: a path escaping the checkout is not proof the entry is
623+
// unwired; treat it as still live (same as revert's refusal).
624+
if reader.escaped().is_some() {
625+
return true;
626+
}
622627
let read = |rel: &str| reader.read(rel);
623-
let wired = if is_gradle(&entry.wiring) {
628+
if is_gradle(&entry.wiring) {
624629
gradle::wired(&read, &c)
625630
} else {
626631
maven_reactor::wired(&read, &c)
627-
};
628-
wired && reader.escaped().is_none()
632+
}
629633
}
630634

631635
/// The vendored jar of the JVM `entry` for `uuid`, project-relative: the

‎crates/socket-patch-core/src/vendor/jvm/maven_reactor.rs‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,17 @@ pub fn unplan(read: ReadFn<'_>, c: &Coords<'_>, records: &[WiringRecord]) -> Jvm
352352
/// (outside comments): the liveness proof `vex` needs for this layout.
353353
pub fn wired(read: ReadFn<'_>, c: &Coords<'_>) -> bool {
354354
let sv = c.suffixed_version();
355-
Reactor::discover(read).is_ok_and(|reactor| {
356-
reactor
355+
match Reactor::discover(read) {
356+
Ok(reactor) => reactor
357357
.scope
358358
.iter()
359-
.any(|rel| reactor.poms[rel].doc.masked.contains(&sv))
360-
})
359+
.any(|rel| reactor.poms[rel].doc.masked.contains(&sv)),
360+
Err(_) => {
361+
// Fail-closed: discovery failure (broken pom, nested .mvn, etc.)
362+
// is not proof the entry is unwired; treat it as still live.
363+
true
364+
}
365+
}
361366
}
362367

363368
/// `<!-- socket-patch <uuid>:` — the start of `c`'s pin comment.

‎crates/socket-patch-core/src/vendor/maven_repo.rs‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -716,9 +716,17 @@ pub async fn revert_maven_opts(
716716
/// flag), and only for a reactor or a Gradle build.
717717
async fn jvm_shape(project_root: &Path) -> Option<super::jvm::Shape> {
718718
if !super::jvm::experimental_enabled() {
719-
let state = super::state::load_state(project_root).await.ok()?;
720-
if !state.entries.values().any(super::jvm::apply::is_jvm_entry) {
721-
return None;
719+
match super::state::load_state(project_root).await {
720+
Ok(state) => {
721+
if !state.entries.values().any(super::jvm::apply::is_jvm_entry) {
722+
return None;
723+
}
724+
}
725+
Err(_) => {
726+
// Fail-closed: unreadable or corrupt ledger is never empty.
727+
// Continue to detect shape so a corrupt ledger with JVM entries
728+
// still routes to the JVM backend.
729+
}
722730
}
723731
}
724732
let reader = super::jvm::apply::ProjectReader::new(project_root);
@@ -914,8 +922,19 @@ async fn vendor_maven_jvm(
914922
};
915923
// Shared fragments another JVM entry wrote, and the pristine originals
916924
// of a patch update, come from the ledger (§7.3).
917-
if let Ok(state) = super::state::load_state(project_root).await {
918-
super::jvm::apply::inherit_peer_records(&mut wiring, state.entries.values());
925+
match super::state::load_state(project_root).await {
926+
Ok(state) => {
927+
super::jvm::apply::inherit_peer_records(&mut wiring, state.entries.values());
928+
}
929+
Err(e) => {
930+
// Fail-closed: unreadable or corrupt ledger is never empty. Without
931+
// peer records, a later revert cannot restore shared fragments.
932+
return done(
933+
failed_result(purl, &jar_path, format!("vendor_ledger_corrupt: {e}")),
934+
None,
935+
warnings,
936+
);
937+
}
919938
}
920939
let entry = maven_entry(
921940
build_maven_purl(&group_id, &artifact_id, &version),

0 commit comments

Comments
 (0)