@@ -429,6 +429,104 @@ func TestSnapshotBackedRouteReturns503WhenSnapshotMissing(t *testing.T) {
429429 }
430430}
431431
432+ func TestResearchBoundariesEndpointProxiesRuntimeBoundaryRegistry (t * testing.T ) {
433+ upstream := httptest .NewServer (http .HandlerFunc (func (writer http.ResponseWriter , request * http.Request ) {
434+ if request .URL .Path != "/api/v1/research-boundaries" {
435+ t .Fatalf ("unexpected path %s" , request .URL .Path )
436+ }
437+ writeJSON (writer , http .StatusOK , map [string ]any {
438+ "status" : "ok" ,
439+ "source" : "registry" ,
440+ "candidate_policy" : "not-exposed-as-live-jobs" ,
441+ "boundaries" : []map [string ]any {
442+ {
443+ "key" : "h2-output-cloud-geometry-candidate-no-runtime-job" ,
444+ "admission_status" : "watch" ,
445+ },
446+ },
447+ "source_readiness" : map [string ]any {"ready" : true },
448+ })
449+ }))
450+ defer upstream .Close ()
451+
452+ server := NewServer (Config {RuntimeBaseURL : upstream .URL })
453+ request := httptest .NewRequest (http .MethodGet , "/api/v1/research-boundaries" , nil )
454+ recorder := httptest .NewRecorder ()
455+
456+ server .Handler ().ServeHTTP (recorder , request )
457+
458+ if recorder .Code != http .StatusOK {
459+ t .Fatalf ("expected 200, got %d" , recorder .Code )
460+ }
461+ var payload map [string ]any
462+ if err := json .Unmarshal (recorder .Body .Bytes (), & payload ); err != nil {
463+ t .Fatalf ("decode failed: %v" , err )
464+ }
465+ if payload ["source" ] != "registry" {
466+ t .Fatalf ("expected runtime registry payload, got %v" , payload )
467+ }
468+ if payload ["candidate_policy" ] != "not-exposed-as-live-jobs" {
469+ t .Fatalf ("unexpected candidate policy %v" , payload ["candidate_policy" ])
470+ }
471+ if payload ["job_type" ] != nil {
472+ t .Fatalf ("research boundary payload must not expose live job_type: %v" , payload )
473+ }
474+ }
475+
476+ func TestResearchBoundariesEndpointReturnsStableUnavailablePayloadWithoutRuntime (t * testing.T ) {
477+ server := NewServer (Config {})
478+ request := httptest .NewRequest (http .MethodGet , "/api/v1/research-boundaries" , nil )
479+ recorder := httptest .NewRecorder ()
480+
481+ server .Handler ().ServeHTTP (recorder , request )
482+
483+ if recorder .Code != http .StatusOK {
484+ t .Fatalf ("expected 200, got %d" , recorder .Code )
485+ }
486+ var payload map [string ]any
487+ if err := json .Unmarshal (recorder .Body .Bytes (), & payload ); err != nil {
488+ t .Fatalf ("decode failed: %v" , err )
489+ }
490+ if payload ["status" ] != "unavailable" {
491+ t .Fatalf ("expected unavailable status, got %v" , payload ["status" ])
492+ }
493+ if payload ["candidate_policy" ] != "not-exposed-as-live-jobs" {
494+ t .Fatalf ("unexpected candidate policy %v" , payload ["candidate_policy" ])
495+ }
496+ if payload ["runtime_configured" ] != false {
497+ t .Fatalf ("expected runtime_configured=false, got %v" , payload ["runtime_configured" ])
498+ }
499+ }
500+
501+ func TestResearchBoundariesEndpointDoesNotExposeRuntimeErrors (t * testing.T ) {
502+ server := NewServer (Config {
503+ RuntimeBaseURL : "http://192.0.2.10:8765" ,
504+ RuntimeTimeout : 10 * time .Millisecond ,
505+ })
506+ request := httptest .NewRequest (http .MethodGet , "/api/v1/research-boundaries" , nil )
507+ recorder := httptest .NewRecorder ()
508+
509+ server .Handler ().ServeHTTP (recorder , request )
510+
511+ if recorder .Code != http .StatusOK {
512+ t .Fatalf ("expected 200, got %d" , recorder .Code )
513+ }
514+ raw := recorder .Body .String ()
515+ if strings .Contains (raw , "192.0.2.10" ) || strings .Contains (raw , "connection refused" ) || strings .Contains (raw , "deadline" ) {
516+ t .Fatalf ("research boundaries leaked upstream details: %s" , raw )
517+ }
518+ var payload map [string ]any
519+ if err := json .Unmarshal ([]byte (raw ), & payload ); err != nil {
520+ t .Fatalf ("decode failed: %v" , err )
521+ }
522+ if payload ["status" ] != "unavailable" {
523+ t .Fatalf ("expected unavailable status, got %v" , payload ["status" ])
524+ }
525+ if payload ["runtime_configured" ] != true {
526+ t .Fatalf ("expected runtime_configured=true, got %v" , payload ["runtime_configured" ])
527+ }
528+ }
529+
432530func TestJobsListEndpointIsProxied (t * testing.T ) {
433531 upstream := httptest .NewServer (http .HandlerFunc (func (writer http.ResponseWriter , request * http.Request ) {
434532 if request .URL .Path != "/api/v1/audit/jobs" {
0 commit comments