@@ -181,6 +181,18 @@ pub(crate) async fn service_preflight(
181181 . await
182182 . ok ( )
183183 . filter ( |p| !p. copy_was_ok ) ?;
184+ // `vendor_go_module` refuses a version the build doesn't select before
185+ // it asks the service for anything (#392).
186+ if crate :: patch:: redirect:: golang_local:: selection_refusal (
187+ project_root,
188+ & prelude. module ,
189+ & prelude. version ,
190+ )
191+ . await
192+ . is_some ( )
193+ {
194+ return None ;
195+ }
184196 // `go_service_redirect` extracts the module zip (its literal
185197 // `{module}@{version}/` prefix stripped) into the copy dir's stage.
186198 let prefix = format ! ( "{}@{}/" , prelude. module, prelude. version) ;
@@ -817,6 +829,11 @@ mod tests {
817829 } ;
818830 let ( dir, blobs, pristine, record) = fixture ( ) . await ;
819831 let root = dir. path ( ) ;
832+ // A go 1.16 go.mod listing no version of the module: neither
833+ // version is shown unselected, so both ask for a grant.
834+ tokio:: fs:: write ( root. join ( "go.mod" ) , "module example.com/app\n \n go 1.16\n " )
835+ . await
836+ . unwrap ( ) ;
820837 let server = wiremock:: MockServer :: start ( ) . await ;
821838 mount_no_results ( & server) . await ;
822839 let cfg = service_cfg ( & server. uri ( ) , crate :: vendor:: VendorSource :: Service , false ) ;
@@ -911,6 +928,37 @@ mod tests {
911928 }
912929 }
913930
931+ /// #392 (vendored variant): in the go 1.16 graph where go.sum shows the
932+ /// build selects v1.5.0, vendoring a v1.4.2 patch would commit a replace
933+ /// go ignores. Refuse before fetching or writing anything.
934+ #[ tokio:: test]
935+ async fn test_vendor_refuses_a_version_the_build_does_not_select ( ) {
936+ let ( dir, blobs, pristine, record) = fixture ( ) . await ;
937+ let root = dir. path ( ) ;
938+ let go_mod = "module example.com/app\n \n go 1.16\n \n require example.com/mid v1.0.0\n " ;
939+ tokio:: fs:: write ( root. join ( "go.mod" ) , go_mod) . await . unwrap ( ) ;
940+ tokio:: fs:: write (
941+ root. join ( "go.sum" ) ,
942+ "github.com/foo/bar v1.4.2/go.mod h1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\n \
943+ github.com/foo/bar v1.5.0 h1:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=\n ",
944+ )
945+ . await
946+ . unwrap ( ) ;
947+ let outcome = run_vendor ( PURL , root, & blobs, & pristine, & record, false ) . await ;
948+ let detail = expect_refused ( outcome, "vendor_go_version_not_selected" ) ;
949+ assert ! (
950+ detail. contains( "the build selects github.com/foo/bar v1.5.0" ) ,
951+ "{detail}"
952+ ) ;
953+ assert_eq ! (
954+ tokio:: fs:: read_to_string( root. join( "go.mod" ) )
955+ . await
956+ . unwrap( ) ,
957+ go_mod
958+ ) ;
959+ assert ! ( !root. join( ".socket/vendor" ) . exists( ) ) ;
960+ }
961+
914962 #[ tokio:: test]
915963 async fn test_happy_path_wires_copy_replace_and_marker ( ) {
916964 let ( dir, blobs, pristine, record) = fixture ( ) . await ;
0 commit comments