package policy import ( "context" "path/filepath" "strings" "testing" ) // loadRealPolicy compiles the committed policies/sinks/signing_service.rego // so the tests fail if we rename the package or break the file. func loadRealPolicy(t *testing.T) *OPAEvaluator { t.Helper() // From services/signing-service, walk up to repo root (two parents), // then into policies/sinks/signing_service.rego. p := filepath.Join("..", "..", "..", "..", "policies", "sinks", "signing_service.rego") opa, err := NewOPAEvaluator(context.Background(), p) if err != nil { t.Fatalf("load policy: %v", err) } return opa } func makeInput() Input { by := InputRegistryRow{ AgentID: "agent-approval-service", PocketIDClient: "agent-approval-service", K8sNamespace: "agent-trust", K8sServiceAccount: "approval-service", AllowedActions: []string{"expense.submit"}, } return Input{ PocketIDClient: "agent-approval-service", K8s: InputK8s{ Namespace: "agent-trust", ServiceAccount: "approval-service", }, KeyRef: "trust-api/approval-signer-2026-q4", Registry: InputRegistry{ ByPocketID: &by, ByK8s: &by, }, } } func TestOPA_Allows_ApprovalService_HappyPath(t *testing.T) { opa := loadRealPolicy(t) dec, err := opa.Decide(context.Background(), makeInput()) if err != nil { t.Fatalf("Decide: %v", err) } if !dec.Allow { t.Fatalf("expected allow, got deny: %q", dec.Reason) } } func TestOPA_Allows_TestAgentTransform_HappyPath(t *testing.T) { opa := loadRealPolicy(t) by := InputRegistryRow{ AgentID: "agent-testagent-transform", PocketIDClient: "agent-testagent-transform", K8sNamespace: "agent-trust", K8sServiceAccount: "testagent-transform", } in := Input{ PocketIDClient: "agent-testagent-transform", K8s: InputK8s{Namespace: "agent-trust", ServiceAccount: "testagent-transform"}, KeyRef: "trust-api/agent-testagent-transform-2026-q4", Registry: InputRegistry{ByPocketID: &by, ByK8s: &by}, } dec, err := opa.Decide(context.Background(), in) if err != nil { t.Fatalf("Decide: %v", err) } if !dec.Allow { t.Fatalf("expected allow, got deny: %q", dec.Reason) } } func TestOPA_Denies_RegistryMismatch(t *testing.T) { opa := loadRealPolicy(t) in := makeInput() // By-K8s returns a DIFFERENT agent row than By-PocketID — the double // identity check must deny. byK := InputRegistryRow{ AgentID: "agent-testagent-transform", PocketIDClient: "agent-testagent-transform", K8sNamespace: "agent-trust", K8sServiceAccount: "testagent-transform", } in.Registry.ByK8s = &byK dec, err := opa.Decide(context.Background(), in) if err != nil { t.Fatalf("Decide: %v", err) } if dec.Allow { t.Fatalf("expected deny on registry mismatch, got allow") } if !strings.Contains(dec.Reason, "do not resolve to the same registry agent") { t.Errorf("unexpected reason: %q", dec.Reason) } } func TestOPA_Denies_SubjectMismatchFromCaller(t *testing.T) { opa := loadRealPolicy(t) in := makeInput() // Caller presented a different Pocket-ID subject than the one stored // in the registry row — the policy must deny because the row no longer // matches the authenticated identity. in.PocketIDClient = "spoofed-client" dec, err := opa.Decide(context.Background(), in) if err != nil { t.Fatalf("Decide: %v", err) } if dec.Allow { t.Fatalf("expected deny when caller subject mismatches registry, got allow") } } func TestOPA_Denies_WrongKeyRefForRole(t *testing.T) { opa := loadRealPolicy(t) in := makeInput() in.KeyRef = "trust-api/agent-testagent-transform-2026-q4" // belongs to other agent dec, err := opa.Decide(context.Background(), in) if err != nil { t.Fatalf("Decide: %v", err) } if dec.Allow { t.Fatalf("expected deny on wrong key_ref, got allow") } if !strings.Contains(dec.Reason, "not permitted to sign") { t.Errorf("unexpected reason: %q", dec.Reason) } } func TestOPA_Denies_NilRegistryRow(t *testing.T) { opa := loadRealPolicy(t) in := makeInput() in.Registry.ByK8s = nil dec, err := opa.Decide(context.Background(), in) if err != nil { t.Fatalf("Decide: %v", err) } if dec.Allow { t.Fatalf("expected deny on missing registry row, got allow") } }