package httpapi import ( "context" "encoding/json" "knowledge-governance/internal/qaopsmirror" "net/http" "net/http/httptest" "strings" "testing" ) type mirrorSyncSpy struct { qaOpsSpy syncCalls int key, actor string } func (s *mirrorSyncSpy) GetSyncStatus(context.Context) (qaopsmirror.Status, error) { return qaopsmirror.Status{Mode: "local", IntervalSeconds: 300, WorkerReady: true}, nil } func (s *mirrorSyncSpy) EnqueueSync(_ context.Context, key, actor string) (qaopsmirror.SyncReceipt, bool, error) { s.syncCalls++ s.key = key s.actor = actor return qaopsmirror.SyncReceipt{JobID: "fixture-mirror-job"}, false, nil } func TestQAMirrorSyncRequiresSessionIntentAndIdempotency(t *testing.T) { spy := &mirrorSyncSpy{} auth := newFakeAuthStore() auth.sessions["mirror-admin"] = "usr-boss" auth.sessions["mirror-viewer"] = "usr-eye" h, e := NewHandler(Config{Store: &fakeJobStore{}, QAOps: spy, QAOpsEnabled: true, QAOpsTenantKey: "fixture-tenant", Auth: &AuthConfig{Store: auth}}) if e != nil { t.Fatal(e) } for _, tc := range []struct { method, token, key, intent, origin, body string status int }{ {"GET", "", "", "", "", "", 401}, {"GET", "mirror-viewer", "", "", "", "", 403}, {"GET", "mirror-admin", "", "", "", "", 200}, {"POST", "mirror-admin", "op-one", "", "", "{}", 403}, {"POST", "mirror-admin", "op-one", "qa-records-sync", "https://foreign.invalid", "{}", 403}, {"POST", "mirror-admin", "", "qa-records-sync", "", "{}", 400}, {"POST", "mirror-admin", "op-one", "qa-records-sync", "", "null", 400}, {"POST", "mirror-admin", "op-one", "qa-records-sync", "", `{"tenant":"forged"}`, 400}, {"POST", "mirror-admin", "op-one", "qa-records-sync", "", "{}", 202}, } { req := httptest.NewRequest(tc.method, "/api/v1/qa-ops/sync", strings.NewReader(tc.body)) if tc.token != "" { req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tc.token}) } req.Header.Set("Idempotency-Key", tc.key) req.Header.Set("X-Governance-Action", tc.intent) req.Header.Set("Origin", tc.origin) w := httptest.NewRecorder() h.ServeHTTP(w, req) if w.Code != tc.status { t.Fatalf("%s %s got %d want %d: %s", tc.method, tc.body, w.Code, tc.status, w.Body.String()) } } if spy.syncCalls != 1 || spy.key != "op-one" || spy.actor == "" { t.Fatal("invalid sync reached store or operator was not session-stamped") } req := httptest.NewRequest("GET", "/api/v1/qa-ops/status", nil) req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: "mirror-admin"}) w := httptest.NewRecorder() h.ServeHTTP(w, req) var body struct { Data struct { Cache *qaopsmirror.Status `json:"cache"` } } if json.Unmarshal(w.Body.Bytes(), &body) != nil || body.Data.Cache == nil || body.Data.Cache.Mode != "local" { t.Fatal("local serving mode missing from status") } } func TestQAMirrorSyncNamespaceCannotBypassEntry(t *testing.T) { auth := newFakeAuthStore() auth.sessions["mirror-admin"] = "usr-boss" h, _ := NewHandler(Config{Store: &fakeJobStore{}, Auth: &AuthConfig{Store: auth}}) req := httptest.NewRequest("POST", "/api/v1/jobs", strings.NewReader(`{"type":"qaops.records.sync.fixture","payload":{},"idempotency_key":"bypass"}`)) req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: "mirror-admin"}) w := httptest.NewRecorder() h.ServeHTTP(w, req) if w.Code != 400 { t.Fatal("generic jobs endpoint bypassed mirror sync admission", w.Code) } }