package audit import ( "context" "io" "net/http" "net/http/httptest" "net/url" "strings" "testing" "gitea.mynodes.xyz/ilker/llmgw/internal/store" ) func TestNothingSecretIsRecorded(t *testing.T) { got := Redact(FormFields(url.Values{ "current": {"old-pw"}, "new": {"new-pw"}, "password": {"pw"}, "csrf": {"tok"}, "name": {"ok-name"}, "note": {"sk-proj-abcdefgh"}, })) for _, secret := range []string{"old-pw", "new-pw", `"pw"`, "tok", "sk-proj"} { if strings.Contains(got, secret) { t.Errorf("%s recorded: %s", secret, got) } } if !strings.Contains(got, "ok-name") { t.Errorf("an ordinary field was dropped: %s", got) } nested := Redact(map[string]any{"external": map[string]any{"api_key": "x1", "url": "https://p"}}) if strings.Contains(nested, "x1") || !strings.Contains(nested, "https://p") { t.Errorf("nested: %s", nested) } } type memSink struct{ got []store.AuditEvent } func (m *memSink) WriteAudit(_ context.Context, e store.AuditEvent) error { m.got = append(m.got, e) return nil } func TestEveryChangeToTheAdminAPIIsRecorded(t *testing.T) { sink := &memSink{} h := API(sink, func(*http.Request) string { return "ilker" }, nil, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) })) for _, req := range []*http.Request{ httptest.NewRequest("GET", "/api/v1/models", nil), httptest.NewRequest("POST", "/api/v1/models", strings.NewReader(`{"name":"m1","external":{"api_key":"sk-1"}}`)), httptest.NewRequest("DELETE", "/api/v1/nodes/n1", nil), } { h.ServeHTTP(httptest.NewRecorder(), req) } if len(sink.got) != 2 { t.Fatalf("recorded %d: %+v", len(sink.got), sink.got) } e := sink.got[0] if e.Actor != "ilker" || e.Action != "POST /api/v1/models" || e.Target != "m1" || e.Status != 201 || strings.Contains(e.Detail, "sk-1") || e.Source != "api" { t.Errorf("%+v", e) } } func TestABodyLargerThanWhatIsRecordedReachesTheHandlerWhole(t *testing.T) { big := `{"content":"` + strings.Repeat("x", 200<<10) + `"}` var got int h := API(&memSink{}, func(*http.Request) string { return "ilker" }, nil, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { b, _ := io.ReadAll(r.Body) got = len(b) })) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("POST", "/api/v1/models/m/eval", strings.NewReader(big))) if got != len(big) { t.Errorf("the handler was given %d of %d bytes", got, len(big)) } } func TestAskingAJudgeKeepsNoText(t *testing.T) { sink := &memSink{} h := API(sink, func(*http.Request) string { return "ilker" }, nil, http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) h.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("POST", "/api/v1/guard/judges/ask", strings.NewReader(`{"text":"something a user wrote"}`))) if len(sink.got) != 0 { t.Errorf("a judge's question was recorded: %+v", sink.got) } }