package topaz_test import ( "context" "errors" "os" "path/filepath" "testing" "github.com/netkingdom/flex-auth/internal/adapters/topaz" "github.com/netkingdom/flex-auth/internal/policy" "github.com/netkingdom/flex-auth/internal/registry" "github.com/netkingdom/flex-auth/pkg/api" ) func TestSnapshotToDirectoryMapsCanonicalRegistry(t *testing.T) { store := loadRegistry(t) got := topaz.SnapshotToDirectory(store.Snapshot()) assertObject(t, got, "user", "user:alice") assertObject(t, got, "identity", "identity:user:alice") assertObject(t, got, "group", "group:platform-architecture") assertObject(t, got, "document", "document:internal-note") assertRelation(t, got, topaz.DirectoryRelation{ ObjectType: "identity", ObjectID: "identity:user:alice", Relation: "identifier", SubjectType: "user", SubjectID: "user:alice", }) assertRelation(t, got, topaz.DirectoryRelation{ ObjectType: "group", ObjectID: "group:platform-architecture", Relation: "member", SubjectType: "user", SubjectID: "user:alice", }) assertRelation(t, got, topaz.DirectoryRelation{ ObjectType: "document", ObjectID: "document:internal-note", Relation: "reader", SubjectType: "group", SubjectID: "group:platform-architecture", SubjectRelation: "member", }) } func TestAdapterCheckWrapsTopazAllowInFlexAuthEnvelope(t *testing.T) { client := &fakeClient{ checkResult: topaz.CheckResult{ Allowed: true, DirectoryETag: "etag:rel-42", Diagnostics: map[string]any{ "topaz_trace": "trace-1", }, }, } adapter := newAdapter(t, client) got, err := adapter.Check(context.Background(), api.CheckRequest{ ID: "check:topaz-allow", Subject: api.SubjectRef{ID: "user:alice", Type: api.SubjectTypeHuman}, Action: "read", Resource: api.ResourceRef{ ID: "document:internal-note", Type: "document", System: "markitect-tool", }, CaringContext: caringDescriptor(), }) if err != nil { t.Fatalf("Check: %v", err) } if got.Effect != api.DecisionEffectAllow || got.Reason != "topaz_directory_allow" { t.Fatalf("decision = %s/%s; want allow/topaz_directory_allow", got.Effect, got.Reason) } if got.Provenance.Evaluator != topaz.EvaluatorName || got.Provenance.Mode != topaz.DelegatedMode { t.Fatalf("provenance = %+v; want delegated Topaz", got.Provenance) } if got.Provenance.DirectoryETag != "etag:rel-42" { t.Fatalf("DirectoryETag = %q", got.Provenance.DirectoryETag) } if got.Diagnostics["topaz_object_type"] != "document" || got.Diagnostics["topaz_subject_type"] != "user" { t.Fatalf("diagnostics = %+v; want Topaz check shape", got.Diagnostics) } if got.Caring == nil || got.Caring.Descriptor == nil { t.Fatal("missing CARING descriptor") } if len(got.Caring.RestrictionsEvaluated) != 1 || got.Caring.RestrictionsEvaluated[0] != api.RestrictionExportBlocked { t.Fatalf("restrictions = %+v; want ExportBlocked", got.Caring.RestrictionsEvaluated) } } func TestAdapterCheckFailsClosedOnUnavailableTopaz(t *testing.T) { client := &fakeClient{ checkErr: topaz.NewBackendError(topaz.FailureUnavailable, "check", errors.New("connection refused")), } adapter := newAdapter(t, client) got, err := adapter.Check(context.Background(), api.CheckRequest{ ID: "check:topaz-down", Subject: api.SubjectRef{ID: "user:alice"}, Action: "read", Resource: api.ResourceRef{ID: "document:internal-note", Type: "document", System: "markitect-tool"}, CaringContext: caringDescriptor(), }) if err != nil { t.Fatalf("Check: %v", err) } if got.Effect != api.DecisionEffectDeny || got.Reason != "topaz_unavailable" { t.Fatalf("decision = %s/%s; want deny/topaz_unavailable", got.Effect, got.Reason) } if got.Diagnostics["topaz_failure"] != "unavailable" { t.Fatalf("diagnostics = %+v; want unavailable failure", got.Diagnostics) } if got.Caring == nil || len(got.Caring.ConformanceFindings) == 0 { t.Fatal("fail-closed decision should carry CARING conformance finding") } if got.Caring.ConformanceFindings[0].Code != "TOPAZ-UNAVAILABLE" { t.Fatalf("finding = %+v", got.Caring.ConformanceFindings[0]) } } func TestImportDirectoryWritesObjectsAndRelations(t *testing.T) { client := &fakeClient{} adapter := newAdapter(t, client) report, err := adapter.ImportDirectory(context.Background(), loadRegistry(t).Snapshot()) if err != nil { t.Fatalf("ImportDirectory: %v", err) } if report.ObjectsWritten != len(client.objects) { t.Fatalf("ObjectsWritten = %d; client wrote %d", report.ObjectsWritten, len(client.objects)) } if report.RelationsWritten != len(client.relations) { t.Fatalf("RelationsWritten = %d; client wrote %d", report.RelationsWritten, len(client.relations)) } assertWrittenRelation(t, client.relations, topaz.DirectoryRelation{ ObjectType: "document", ObjectID: "document:internal-note", Relation: "reader", SubjectType: "group", SubjectID: "group:platform-architecture", SubjectRelation: "member", }) } func TestImportPolicyWritesTopazBundle(t *testing.T) { pkg, err := policy.LoadAndValidateFile(context.Background(), filepath.Join("..", "..", "..", "examples", "caring", "policy_package.md")) if err != nil { t.Fatalf("LoadAndValidateFile: %v", err) } client := &fakeClient{bundleSink: topaz.FileBundleSink{Root: t.TempDir()}} adapter := newAdapter(t, client) report, err := adapter.ImportPolicy(context.Background(), pkg) if err != nil { t.Fatalf("ImportPolicy: %v", err) } if report.BundleID != "markitect.documents.internal-read" || report.Version != "v1" { t.Fatalf("report = %+v", report) } modulePath := filepath.Join(client.bundleSink.Root, "policy", "flexauth", "markitect", "documents.rego") data, err := os.ReadFile(modulePath) if err != nil { t.Fatalf("read module: %v", err) } if string(data) != pkg.RegoModule { t.Fatal("policy module changed during Topaz import") } manifest, err := os.ReadFile(filepath.Join(client.bundleSink.Root, ".manifest")) if err != nil { t.Fatalf("read manifest: %v", err) } if !contains(string(manifest), "flexauth/markitect/documents") { t.Fatalf(".manifest = %s", manifest) } } func loadRegistry(t *testing.T) *registry.Store { t.Helper() store, err := registry.LoadFile(filepath.Join("..", "..", "..", "examples", "caring", "registry_snapshot.json")) if err != nil { t.Fatalf("LoadFile: %v", err) } return store } func newAdapter(t *testing.T, client *fakeClient) *topaz.Adapter { t.Helper() adapter, err := topaz.New(client, topaz.Options{ PolicyPackage: "markitect.documents.internal-read", PolicyVersion: "v1", }) if err != nil { t.Fatalf("New: %v", err) } return adapter } func caringDescriptor() *api.CaringAccessDescriptor { return &api.CaringAccessDescriptor{ ID: "descriptor:tenant-alpha-document-reader", Profile: api.CaringProfileCaring040RC2, SubjectType: api.SubjectTypeGroup, OrganizationRelation: api.OrganizationRelationCustomer, CanonicalRole: api.CanonicalRoleDoer, Scope: api.CaringScope{ Level: api.ScopeLevelResource, ID: "document:internal-note", Tenant: "tenant:alpha", Resource: "document:internal-note", }, Planes: []api.Plane{api.PlaneData}, Capabilities: []api.Capability{api.CapabilityView}, ExposureModes: []api.ExposureMode{api.ExposureModeMasked, api.ExposureModePlaintext}, Restrictions: []api.Restriction{api.RestrictionExportBlocked}, } } func assertObject(t *testing.T, snapshot topaz.DirectorySnapshot, objectType, objectID string) { t.Helper() for _, object := range snapshot.Objects { if object.Type == objectType && object.ID == objectID { return } } t.Fatalf("object %s:%s not found in %+v", objectType, objectID, snapshot.Objects) } func assertRelation(t *testing.T, snapshot topaz.DirectorySnapshot, want topaz.DirectoryRelation) { t.Helper() assertWrittenRelation(t, snapshot.Relations, want) } func assertWrittenRelation(t *testing.T, relations []topaz.DirectoryRelation, want topaz.DirectoryRelation) { t.Helper() for _, relation := range relations { if relation == want { return } } t.Fatalf("relation %+v not found in %+v", want, relations) } func contains(value, needle string) bool { return len(needle) == 0 || (len(value) >= len(needle) && stringsContains(value, needle)) } func stringsContains(value, needle string) bool { for i := 0; i+len(needle) <= len(value); i++ { if value[i:i+len(needle)] == needle { return true } } return false } type fakeClient struct { checkResult topaz.CheckResult checkErr error objects []topaz.DirectoryObject relations []topaz.DirectoryRelation bundleSink topaz.FileBundleSink } func (c *fakeClient) Check(context.Context, topaz.DirectoryCheckRequest) (topaz.CheckResult, error) { return c.checkResult, c.checkErr } func (c *fakeClient) PutObject(_ context.Context, object topaz.DirectoryObject) error { c.objects = append(c.objects, object) return nil } func (c *fakeClient) PutRelation(_ context.Context, relation topaz.DirectoryRelation) (topaz.WriteResult, error) { c.relations = append(c.relations, relation) return topaz.WriteResult{ETag: "etag:last"}, nil } func (c *fakeClient) PutManifest(context.Context, []byte) error { return nil } func (c *fakeClient) PutPolicyBundle(ctx context.Context, bundle topaz.PolicyBundle) error { if c.bundleSink.Root == "" { return nil } return c.bundleSink.PutPolicyBundle(ctx, bundle) } func (c *fakeClient) Health(context.Context) error { return nil }