Skip to content

Commit f1577c1

Browse files
committed
Fix VEX to check go.work replaces for workspace selection
The VEX gate only walked go.mod replaces from module_roots and never inspected go.work pins. Discovery still emits a hosted go.work replace when selection is Unknown (a zip line still satisfies lockfile basis), so VEX incorrectly attested that pin on a fresh clone or unread module graph instead of withholding go_version_not_selected. The fix loads the workspace and adds its replaces to the entries list, applying the same selection gate logic. Now a go.work-only pin is correctly withheld when the module graph is unavailable. Updated tests to expect the corrected behavior: go.work replaces in a workspace without a cached module graph are now withheld like go.mod replaces.
1 parent 964cd36 commit f1577c1

2 files changed

Lines changed: 21 additions & 5 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,16 @@ async fn generate_vex(
998998
entries.push((root.clone(), entry));
999999
}
10001000
}
1001+
// Also check go.work replaces: discovery emits them when selection is
1002+
// Unknown, but the gate must not attest an unproven workspace selection.
1003+
if let socket_patch_core::vendor::go_workspace::Loaded::Workspace(workspace) =
1004+
socket_patch_core::vendor::go_workspace::load(&common.cwd).await
1005+
{
1006+
let work_root = workspace.work_dir().to_path_buf();
1007+
for entry in workspace.replaces() {
1008+
entries.push((work_root.clone(), entry));
1009+
}
1010+
}
10011011
for (root, entry) in entries {
10021012
let Some(version) = entry.version.as_deref().filter(|_| entry.socket_owned()) else {
10031013
continue;

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -550,13 +550,17 @@ fn redirect_fixture(rel: &str) -> String {
550550
// ══════════════════════════════════════════════════════════════════════
551551

552552
/// a + g(not installed): go.mod (line / block) and go.work flavors attest
553-
/// `(redirected)` for the ORIGINAL module's purl.
553+
/// `(redirected)` for the ORIGINAL module's purl. go.work requires the
554+
/// module graph to be cached (workspace selection check).
554555
#[test]
555556
fn golang_hosted_a_attests_every_flavor_without_manifest_or_ledgers() {
556557
let api = Api::start(vec![(U, go_view(U))]);
557558
for file in GO_FILES {
558559
let fx = Fx::new();
559560
write_go_hosted(&fx, U, file);
561+
if file == GoFile::GoWork {
562+
fx.cache_go_mod(GO_MODULE, GO_VERSION);
563+
}
560564
let run = fx.vex(&["--proxy-url", &api.uri()]);
561565
assert_attested(&fx, &run, GO_PURL, U, "redirected", &format!("{file:?}"));
562566
assert!(
@@ -1046,9 +1050,8 @@ fn golang_workspace_without_its_module_graph_is_not_attested() {
10461050
assert_attested(&fx, &run, GO_PURL, U, "redirected", "graph cached");
10471051
}
10481052

1049-
/// A hand-written go.work replace whose pin lines stayed in the root
1050-
/// go.sum (go reads both sum files in workspace mode): still pinned, still
1051-
/// attested; the vendored twin needs no pin.
1053+
/// A hand-written go.work replace with proper pins: withheld until the
1054+
/// module graph is available (like go.mod replaces), then attested.
10521055
#[test]
10531056
fn golang_go_work_replace_pinned_by_root_go_sum_attests() {
10541057
let api = Api::start(vec![(U, go_view(U))]);
@@ -1058,7 +1061,10 @@ fn golang_go_work_replace_pinned_by_root_go_sum_attests() {
10581061
fx.rm("go.work.sum");
10591062
fx.put("go.sum", sums);
10601063
let run = fx.vex(&["--proxy-url", &api.uri()]);
1061-
assert_attested(&fx, &run, GO_PURL, U, "redirected", "go.work + go.sum pin");
1064+
assert_omitted(&run, GO_PURL, "go_version_not_selected", "empty cache");
1065+
fx.cache_go_mod(GO_MODULE, GO_VERSION);
1066+
let run = fx.vex(&["--proxy-url", &api.uri()]);
1067+
assert_attested(&fx, &run, GO_PURL, U, "redirected", "graph cached");
10621068
}
10631069

10641070
/// LIMITATION (documented, root-only discovery): a Socket replace in a

0 commit comments

Comments
 (0)