package decision_test import ( "context" "path/filepath" "testing" "time" "github.com/netkingdom/flex-auth/internal/decision" "github.com/netkingdom/flex-auth/internal/policy" "github.com/netkingdom/flex-auth/internal/registry" "github.com/netkingdom/flex-auth/pkg/api" ) func TestAttributeContextCarriedWithoutViewHash(t *testing.T) { root := filepath.Join("..", "..") pkg, err := policy.LoadAndValidateFile(context.Background(), filepath.Join(root, "examples", "informed-decision-sitting", "policy.md")) if err != nil { t.Fatalf("LoadAndValidateFile: %v", err) } store, err := registry.LoadFile(filepath.Join(root, "examples", "informed-decision-sitting", "registry.json")) if err != nil { t.Fatal(err) } engine, err := decision.NewEngine(store, pkg) if err != nil { t.Fatal(err) } request := api.CheckRequest{ ID: "attribute-context", Tenant: "tenant:platform", Subject: api.SubjectRef{ ID: "synthetic-attribute-reviewer", Type: "human", Tenant: "tenant:platform", Attributes: map[string]any{ "principal_type_source": "authentication-derived", "tenant_source": "registration-supplied", "groups": []any{"net-kingdom-admins"}, "assurance": map[string]any{ "level": "aal2", "mfa": true, "source": "key-cape", "methods": []any{"pwd", "otp"}, "at": time.Now().Unix(), }, }, }, Action: "accept", Resource: api.ResourceRef{ ID: "memo:intake-new-memo", Type: "decision-memo", System: "informed-decision", Tenant: "tenant:platform", }, Context: map[string]any{ "review_group": "net-kingdom-admins", "memo_class": "credential-lane", "intake_submitter": "state-hub", "approval_requester": "informed-decision", "approval_human_control": true, "memo_version": 1, "approval_id": "706f4205-aaa7-44f6-be30-d0f57664d69c", "approval_binding_digest": "sha256:c8a1a9c8fb22616e3aacfb877ba7974feb5eedaed491f856a6c90719c502ebe4", }, PolicyVersion: "v8", } got, err := engine.Check(context.Background(), request) if err != nil { t.Fatal(err) } if got.Effect != api.DecisionEffectDeny || got.Reason != "unknown_class" { t.Fatalf("effect = %s %s; shipped sets must refuse the class", got.Effect, got.Reason) } if got.Binding == nil { t.Fatal("binding missing") } for _, key := range []string{ "review_group", "memo_class", "intake_submitter", "approval_requester", "approval_human_control", "memo_version", "approval_id", "approval_binding_digest", } { if _, ok := got.Binding.Context[key]; !ok { t.Fatalf("binding context missing %s", key) } } if _, ok := got.Binding.Context["view_hash"]; ok { t.Fatal("view_hash entered the decision binding") } if got.Binding.Context["approval_requester"] != "informed-decision" || got.Binding.Context["approval_human_control"] != true { t.Fatalf("binding context = %#v", got.Binding.Context) } }