89 lines
3.8 KiB
Go
89 lines
3.8 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"knowledge-governance/internal/qaopsorg"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type orgSpy struct {
|
|
calls int
|
|
actor string
|
|
err error
|
|
}
|
|
|
|
func (s *orgSpy) GetView(context.Context) (qaopsorg.State, error) {
|
|
s.calls++
|
|
return qaopsorg.State{State: "empty"}, s.err
|
|
}
|
|
func (s *orgSpy) PreviewRules(context.Context, qaopsorg.SaveRequest) (qaopsorg.State, error) {
|
|
s.calls++
|
|
return qaopsorg.State{}, s.err
|
|
}
|
|
func (s *orgSpy) SaveRules(_ context.Context, _ qaopsorg.SaveRequest, actor string) (qaopsorg.State, error) {
|
|
s.calls++
|
|
s.actor = actor
|
|
return qaopsorg.State{}, s.err
|
|
}
|
|
func TestQAOrganizationGuardsIdentityIntentAndErrors(t *testing.T) {
|
|
spy := &orgSpy{}
|
|
auth := newFakeAuthStore()
|
|
auth.sessions["org-admin"] = "usr-boss"
|
|
auth.sessions["org-viewer"] = "usr-eye"
|
|
handler, err := NewHandler(Config{Store: &fakeJobStore{}, QAOrg: spy, Auth: &AuthConfig{Store: auth}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
base := "/api/v1/qa-ops/organization"
|
|
for _, tc := range []struct {
|
|
method, path, token, action, origin, body string
|
|
status int
|
|
}{
|
|
{"GET", base, "", "", "", "", 401},
|
|
{"GET", base, "org-viewer", "", "", "", 403},
|
|
{"GET", base, "org-admin", "", "", "", 200},
|
|
{"GET", base + "?tenant=another", "org-admin", "", "", "", 400},
|
|
{"PUT", base + "/regions", "org-admin", "", "", "{}", 403},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "https://untrusted.invalid", "{}", 403},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"updated_by":"forged"}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{} {}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","rules":null}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","rules":[]}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","regions":null,"rules":[]}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","regions":[null],"rules":[]}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","regions":[{"id":"edu","name":null}],"rules":[]}`, 400},
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","rules":[],"rules":[]}`, 400},
|
|
|
|
{"PUT", base + "/regions", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","rules":[]}`, 200},
|
|
{"POST", base + "/preview", "org-admin", "qa-organization", "", `{"directory_id":"d","base_revision":"","rules":[]}`, 200},
|
|
} {
|
|
req := httptest.NewRequest(tc.method, tc.path, strings.NewReader(tc.body))
|
|
if tc.token != "" {
|
|
req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tc.token})
|
|
}
|
|
req.Header.Set("X-Governance-Action", tc.action)
|
|
req.Header.Set("Origin", tc.origin)
|
|
res := httptest.NewRecorder()
|
|
handler.ServeHTTP(res, req)
|
|
if res.Code != tc.status {
|
|
t.Fatalf("%s %s got %d want %d: %s", tc.method, tc.path, res.Code, tc.status, res.Body.String())
|
|
}
|
|
}
|
|
if spy.calls != 3 || spy.actor == "" || spy.actor == "forged" {
|
|
t.Fatalf("invalid requests reached store or actor not stamped: %+v", spy)
|
|
}
|
|
spy.err = qaopsorg.ErrConflict
|
|
req := httptest.NewRequest("PUT", base+"/regions", strings.NewReader(`{"directory_id":"d","base_revision":"","rules":[]}`))
|
|
req.AddCookie(&http.Cookie{Name: sessionCookieName, Value: "org-admin"})
|
|
req.Header.Set("X-Governance-Action", "qa-organization")
|
|
res := httptest.NewRecorder()
|
|
handler.ServeHTTP(res, req)
|
|
if res.Code != 409 {
|
|
t.Fatal("stale configuration not reported as conflict")
|
|
}
|
|
}
|