flex-auth/internal/registry/store_test.go
tegwick 56940727bf
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 57s
Finish FLEX-WP-0019 layer-model v0.7 conformance
Close the remaining PDP obligations: mechanical layer declaration check,
registry-snapshot digest in provenance, explicit allow TTL, per-input-class
freshness deadlines, and the published decision-record contract. Document
the canonical request digest as the §6.4.2 replay test.

Assistant: grok
Assistant-Session: 01a06256-fb71-7102-b3a9-27e6734257d0
2026-09-03 23:48:45 +02:00

122 lines
3.6 KiB
Go

package registry_test
import (
"encoding/json"
"path/filepath"
"strings"
"testing"
"github.com/netkingdom/flex-auth/internal/registry"
"github.com/netkingdom/flex-auth/pkg/api"
)
func TestStoreImportsManifests(t *testing.T) {
store := registry.NewStore()
var subjects api.SubjectManifest
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "subject_manifest.yaml"), &subjects)
if err := store.ImportSubjectManifest(subjects); err != nil {
t.Fatalf("ImportSubjectManifest: %v", err)
}
var relationship api.RelationshipFact
loadYAML(t, filepath.Join("..", "..", "examples", "caring", "relationship_fact.yaml"), &relationship)
if err := store.PutRelationship(relationship); err != nil {
t.Fatalf("PutRelationship: %v", err)
}
subject, ok := store.Subject("user:alice")
if !ok {
t.Fatal("subject user:alice not found")
}
if subject.Tenant != "tenant:alpha" {
t.Errorf("subject.Tenant = %q; want tenant:alpha", subject.Tenant)
}
relations := store.RelationshipsForObject("document:internal-note")
if len(relations) != 1 || relations[0].Subject != "group:platform-architecture" {
t.Fatalf("RelationshipsForObject = %+v; want group reader relation", relations)
}
}
func TestStoreLoadsAndSavesDeterministicSnapshot(t *testing.T) {
snapshotPath := filepath.Join("..", "..", "examples", "caring", "registry_snapshot.json")
store, err := registry.LoadFile(snapshotPath)
if err != nil {
t.Fatalf("LoadFile: %v", err)
}
resource, ok := store.Resource("markitect-tool", "document:internal-note")
if !ok {
t.Fatal("resource document:internal-note not found")
}
if resource.TrustZone != "internal" {
t.Errorf("resource.TrustZone = %q; want internal", resource.TrustZone)
}
outPath := filepath.Join(t.TempDir(), "snapshot.json")
if err := store.SaveFile(outPath); err != nil {
t.Fatalf("SaveFile: %v", err)
}
reloaded, err := registry.LoadFile(outPath)
if err != nil {
t.Fatalf("reload saved snapshot: %v", err)
}
got := mustJSON(t, reloaded.Snapshot())
want := mustJSON(t, store.Snapshot())
if got != want {
t.Fatalf("saved snapshot changed after reload\nwant: %s\ngot: %s", want, got)
}
}
func TestStoreDigestChangesWhenSnapshotChanges(t *testing.T) {
store, err := registry.LoadFile(filepath.Join("..", "..", "examples", "caring", "registry_snapshot.json"))
if err != nil {
t.Fatalf("LoadFile: %v", err)
}
first := store.Digest()
if !strings.HasPrefix(first, "sha256:") || len(first) != len("sha256:")+64 {
t.Fatalf("Digest = %q", first)
}
if store.Digest() != first {
t.Fatal("digest is not stable for an unchanged snapshot")
}
if err := store.ImportResourceManifest(api.ResourceManifest{
ID: "markitect-extra",
System: "markitect-tool",
Resources: []api.Resource{
{ID: "document:other-note", Type: "document"},
},
}); err != nil {
t.Fatalf("ImportResourceManifest: %v", err)
}
if store.Digest() == first {
t.Fatal("digest did not change after snapshot mutation")
}
}
func TestStoreRejectsInvalidRecords(t *testing.T) {
store := registry.NewStore()
if err := store.PutSubject(api.Subject{}); err == nil {
t.Fatal("PutSubject accepted missing id")
}
if err := store.ImportResourceManifest(api.ResourceManifest{ID: "m1"}); err == nil {
t.Fatal("ImportResourceManifest accepted missing system")
}
if err := store.PutRelationship(api.RelationshipFact{ID: "r1"}); err == nil {
t.Fatal("PutRelationship accepted missing subject/relation/object")
}
}
func mustJSON(t *testing.T, value any) string {
t.Helper()
data, err := json.Marshal(value)
if err != nil {
t.Fatalf("marshal json: %v", err)
}
return string(data)
}