Files
llmgw/internal/control/adminapi/guard_test.go
T

85 lines
3.1 KiB
Go

package adminapi
import (
"context"
"slices"
"testing"
"time"
"gitea.mynodes.xyz/ilker/llmgw/internal/guard"
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
)
type memGuard struct{ att []guard.Attachment }
func (m *memGuard) GuardAttachments(context.Context) ([]guard.Attachment, error) { return m.att, nil }
func (m *memGuard) AttachGuard(_ context.Context, a guard.Attachment, _ string) error {
if !slices.Contains(m.att, a) {
m.att = append(m.att, a)
}
return nil
}
func (m *memGuard) DetachGuard(_ context.Context, a guard.Attachment) (bool, error) {
n := len(m.att)
m.att = slices.DeleteFunc(m.att, func(x guard.Attachment) bool { return x == a })
return len(m.att) < n, nil
}
func TestGuardPoliciesAreAttachedByTarget(t *testing.T) {
a, _ := setup(t, testModels())
if code := call(t, a, "GET", "/api/v1/guard", "", nil); code != 501 {
t.Errorf("without policies: %d", code)
}
st := &memGuard{}
invalidated := 0
a.SetGuard(&GuardAdmin{
Library: guard.Config{Default: []string{"base"}, Policies: map[string]guard.Policy{"base": {}, "finance": {}}},
Store: st, Invalidate: func() { invalidated++ },
})
if code := call(t, a, "POST", "/api/v1/guard/attachments", `{"target":"key:k1","policy":"finance"}`, nil); code != 200 {
t.Fatalf("attach: %d", code)
}
if invalidated != 1 || len(st.att) != 1 || st.att[0] != (guard.Attachment{Scope: "key", ScopeID: "k1", Policy: "finance"}) {
t.Errorf("stored %v, invalidated %d", st.att, invalidated)
}
for _, bad := range []string{`{"target":"key:k1","policy":"nope"}`, `{"target":"galaxy:x","policy":"finance"}`, `{"target":"key:","policy":"finance"}`} {
if code := call(t, a, "POST", "/api/v1/guard/attachments", bad, nil); code != 400 {
t.Errorf("%s: %d", bad, code)
}
}
var v GuardView
if code := call(t, a, "GET", "/api/v1/guard", "", &v); code != 200 || len(v.Attachments) != 1 ||
!slices.Equal(v.Policies, []string{"base", "finance"}) || !slices.Equal(v.Default, []string{"base"}) {
t.Errorf("%d %+v", code, v)
}
if code := call(t, a, "DELETE", "/api/v1/guard/attachments", `{"target":"key:k1","policy":"finance"}`, nil); code != 200 || len(st.att) != 0 {
t.Errorf("detach: %d %v", code, st.att)
}
if code := call(t, a, "DELETE", "/api/v1/guard/attachments", `{"target":"key:k1","policy":"finance"}`, nil); code != 404 {
t.Errorf("detach again: %d", code)
}
}
type memAudit struct{ f store.AuditFilter }
func (m *memAudit) AuditEvents(_ context.Context, f store.AuditFilter) ([]store.AuditEvent, error) {
m.f = f
return []store.AuditEvent{{Actor: "ilker", Action: "POST /api/v1/models"}}, nil
}
func TestTheAuditLogIsReadWithFilters(t *testing.T) {
a, _ := setup(t, testModels())
m := &memAudit{}
a.SetAudit(m)
var ev []store.AuditEvent
if code := call(t, a, "GET", "/api/v1/audit?since=2d&actor=ilker&contains=models&limit=5", "", &ev); code != 200 || len(ev) != 1 {
t.Fatalf("%d %v", code, ev)
}
if m.f.Actor != "ilker" || m.f.Contains != "models" || m.f.Limit != 5 || time.Since(m.f.Since) < 47*time.Hour {
t.Errorf("filter %+v", m.f)
}
if code := call(t, a, "GET", "/api/v1/audit?since=soon", "", nil); code != 400 {
t.Errorf("a bad since: %d", code)
}
}