@@ -16,6 +16,7 @@ use tempfile::NamedTempFile;
1616use tokio:: time:: { interval, timeout} ;
1717
1818const INFERENCE_PROVIDER_NAME : & str = "e2e-host-inference" ;
19+ const INFERENCE_PROVIDER_UNREACHABLE_NAME : & str = "e2e-host-inference-unreachable" ;
1920const TEST_SERVER_IMAGE : & str = "python:3.13-alpine" ;
2021static INFERENCE_ROUTE_LOCK : Mutex < ( ) > = Mutex :: new ( ( ) ) ;
2122
@@ -177,6 +178,22 @@ async fn delete_provider(name: &str) {
177178 let _ = cmd. status ( ) . await ;
178179}
179180
181+ async fn create_openai_provider ( name : & str , base_url : & str ) -> Result < String , String > {
182+ run_cli ( & [
183+ "provider" ,
184+ "create" ,
185+ "--name" ,
186+ name,
187+ "--type" ,
188+ "openai" ,
189+ "--credential" ,
190+ "OPENAI_API_KEY=dummy" ,
191+ "--config" ,
192+ & format ! ( "OPENAI_BASE_URL={base_url}" ) ,
193+ ] )
194+ . await
195+ }
196+
180197fn write_policy ( port : u16 ) -> Result < NamedTempFile , String > {
181198 let mut file = NamedTempFile :: new ( ) . map_err ( |e| format ! ( "create temp policy file: {e}" ) ) ?;
182199 let policy = format ! (
@@ -282,36 +299,33 @@ async fn sandbox_inference_local_routes_to_host_openshell_internal() {
282299 delete_provider ( INFERENCE_PROVIDER_NAME ) . await ;
283300 }
284301
285- run_cli ( & [
286- "provider" ,
287- "create" ,
288- "--name" ,
302+ let create_output = create_openai_provider (
289303 INFERENCE_PROVIDER_NAME ,
290- "--type" ,
291- "openai" ,
292- "--credential" ,
293- "OPENAI_API_KEY=dummy" ,
294- "--config" ,
295- & format ! (
296- "OPENAI_BASE_URL=http://host.openshell.internal:{}/v1" ,
297- server. port
298- ) ,
299- ] )
304+ & format ! ( "http://host.openshell.internal:{}/v1" , server. port) ,
305+ )
300306 . await
301307 . expect ( "create host-backed OpenAI provider" ) ;
302308
303- run_cli ( & [
309+ let inference_output = run_cli ( & [
304310 "inference" ,
305311 "set" ,
306312 "--provider" ,
307313 INFERENCE_PROVIDER_NAME ,
308314 "--model" ,
309315 "host-echo-model" ,
310- "--no-verify" ,
311316 ] )
312317 . await
313318 . expect ( "point inference.local at host-backed provider" ) ;
314319
320+ assert ! (
321+ inference_output. contains( "Validated Endpoints:" ) ,
322+ "expected verification details in output:\n {inference_output}"
323+ ) ;
324+ assert ! (
325+ inference_output. contains( "/v1/chat/completions (openai_chat_completions)" ) ,
326+ "expected validated endpoint in output:\n {inference_output}"
327+ ) ;
328+
315329 let guard = SandboxGuard :: create ( & [
316330 "--" ,
317331 "curl" ,
@@ -338,4 +352,69 @@ async fn sandbox_inference_local_routes_to_host_openshell_internal() {
338352 "expected sandbox to receive echoed inference content:\n {}" ,
339353 guard. create_output
340354 ) ;
355+
356+ let _ = create_output;
357+ }
358+
359+ #[ tokio:: test]
360+ async fn inference_set_supports_no_verify_for_unreachable_endpoint ( ) {
361+ let _inference_lock = INFERENCE_ROUTE_LOCK
362+ . lock ( )
363+ . unwrap_or_else ( std:: sync:: PoisonError :: into_inner) ;
364+
365+ let current_inference = run_cli ( & [ "inference" , "get" ] )
366+ . await
367+ . expect ( "read current inference config" ) ;
368+ if !current_inference. contains ( "Not configured" ) {
369+ eprintln ! ( "Skipping test: existing inference config would make shared state unsafe" ) ;
370+ return ;
371+ }
372+
373+ if provider_exists ( INFERENCE_PROVIDER_UNREACHABLE_NAME ) . await {
374+ delete_provider ( INFERENCE_PROVIDER_UNREACHABLE_NAME ) . await ;
375+ }
376+
377+ create_openai_provider (
378+ INFERENCE_PROVIDER_UNREACHABLE_NAME ,
379+ "http://host.openshell.internal:9/v1" ,
380+ )
381+ . await
382+ . expect ( "create unreachable OpenAI provider" ) ;
383+
384+ let verify_err = run_cli ( & [
385+ "inference" ,
386+ "set" ,
387+ "--provider" ,
388+ INFERENCE_PROVIDER_UNREACHABLE_NAME ,
389+ "--model" ,
390+ "host-echo-model" ,
391+ ] )
392+ . await
393+ . expect_err ( "default verification should fail for unreachable endpoint" ) ;
394+
395+ assert ! (
396+ verify_err. contains( "failed to verify inference endpoint" ) ,
397+ "expected verification failure output:\n {verify_err}"
398+ ) ;
399+ assert ! (
400+ verify_err. contains( "--no-verify" ) ,
401+ "expected retry hint in failure output:\n {verify_err}"
402+ ) ;
403+
404+ let no_verify_output = run_cli ( & [
405+ "inference" ,
406+ "set" ,
407+ "--provider" ,
408+ INFERENCE_PROVIDER_UNREACHABLE_NAME ,
409+ "--model" ,
410+ "host-echo-model" ,
411+ "--no-verify" ,
412+ ] )
413+ . await
414+ . expect ( "no-verify should bypass validation" ) ;
415+
416+ assert ! (
417+ !no_verify_output. contains( "Validated Endpoints:" ) ,
418+ "did not expect validation output when bypassing verification:\n {no_verify_output}"
419+ ) ;
341420}
0 commit comments