package httpapi import ( "encoding/json" "net/http" "net/http/httptest" "testing" "data-terminal-cloud/internal/alerts" "data-terminal-cloud/internal/identity" "data-terminal-cloud/internal/onboarding" ) func TestCustomerModelReadDoesNotGrantOperatorWrites(t *testing.T) { for _, tc := range []struct { method, path string allowed bool }{ {"GET", "/api/v1/content-models", true}, {"POST", "/api/v1/content-models", false}, {"POST", "/api/v1/content-models/123/activate", false}, {"GET", "/api/v1/content-models/123", false}, {"GET", "/api/v1/ops/content-models", false}, } { if customerCookieRequest(httptest.NewRequest(tc.method, tc.path, nil)) != tc.allowed { t.Fatalf("wrong auth boundary: %s %s", tc.method, tc.path) } } } func TestAlertRoutesSelectOperatorCookieAuthentication(t *testing.T) { router := NewRouter(RouterOptions{ServiceName: "api", TokenVerifier: &identity.OIDCVerifier{}, AlertService: &alerts.Service{}, OnboardingService: &onboarding.Service{}}) for _, path := range []string{"alert-routing-policies", "alerts", "alert-silences", "alert-delivery-tests"} { r := httptest.NewRequest("GET", "https://platform.example/api/v1/ops/"+path, nil) r.AddCookie(&http.Cookie{Name: "__Host-platform-onboarding", Value: "customer-cookie"}) w := httptest.NewRecorder() router.ServeHTTP(w, r) var body struct { Code string `json:"code"` } if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil { t.Fatal(err) } if w.Code != 401 || body.Code != "LOGIN_REQUIRED" { t.Fatalf("%s must require an operator cookie: %s", path, w.Body.String()) } } } func TestCustomerCookieRouteBoundary(t *testing.T) { for _, path := range []string{"/api/v1/memoirs/query", "/api/v1/memoirs/generate", "/api/v1/memoirs/import", "/api/v1/memoirs/illustrations/123"} { if !customerCookiePath(path) { t.Errorf("memoir customer auth unavailable: %s", path) } } for _, path := range []string{"/api/v1/me", "/api/v1/devices", "/api/v1/households/123", "/api/v1/events", "/api/v1/memories/mutations", "/api/v1/stories/123", "/api/v1/conversations/123/turns", "/api/v1/privacy-requests/123", "/api/v1/exports/123", "/api/v1/member-invitations/accept"} { if !customerCookiePath(path) { t.Errorf("customer route not enabled: %s", path) } } for _, path := range []string{"/api/v1/ops/devices", "/api/v1/content-models", "/api/v1/device/calls/prepare", "/api/v1/device/v3/sessions", "/api/v1/memories-admin", "/api/v1/devices-admin", "/internal/v1/tools/memory-search", "/callbacks/v1/vertc/voice-chat"} { if customerCookiePath(path) { t.Errorf("cookie crossed authentication boundary: %s", path) } } } func TestOperatorCookieRouteBoundary(t *testing.T) { for _, path := range []string{"/api/v1/ops/devices", "/api/v1/ops/device-inventory", "/api/v1/content-models", "/api/v1/me", "/api/v1/events"} { r := httptest.NewRequest("GET", path, nil) r.Header.Set("X-Login-Portal", "operator") if !operatorCookieRequest(r) { t.Errorf("operator route unavailable: %s", path) } } for _, path := range []string{"/api/v1/ops-admin", "/api/v1/device/calls/prepare", "/api/v1/web/login/password", "/callbacks/v1/vertc/voice-chat", "/api/v1/households", "/internal/v1/tools/memory-search"} { r := httptest.NewRequest("POST", path, nil) r.Header.Set("X-Login-Portal", "operator") if operatorCookieRequest(r) { t.Errorf("operator cookie crossed boundary: %s", path) } } if operatorCookieRequest(httptest.NewRequest("GET", "/api/v1/me", nil)) { t.Fatal("operator identity selected in customer portal") } }