Freeze the three fact events, intentflow allowlist, and plan table ownership so later units cannot invent producers or write paths outside app/intentflow. Co-authored-by: Cursor <cursoragent@cursor.com>
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package events
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"chat-agent-system/internal/archtest"
|
|
)
|
|
|
|
func TestAssertLiveConsumersRejectsFAV(t *testing.T) {
|
|
if err := AssertLiveConsumers(EventVersionCommitted, []string{ConsumerFAV}); err == nil {
|
|
t.Fatal("fav consumer must fail")
|
|
}
|
|
if err := NewRegistry().Register(ConsumerFAV); err == nil {
|
|
t.Fatal("dynamic fav register must fail")
|
|
}
|
|
}
|
|
|
|
func TestAssertLiveConsumersRejectsUnknown(t *testing.T) {
|
|
if err := AssertLiveConsumers("document.unknown", []string{ConsumerNotify}); err == nil {
|
|
t.Fatal("unknown event must fail")
|
|
}
|
|
if err := NewRegistry().Register("not-a-consumer"); err == nil {
|
|
t.Fatal("unknown consumer must fail")
|
|
}
|
|
}
|
|
|
|
func TestLiveConsumersOmitsFAV(t *testing.T) {
|
|
for _, c := range LiveConsumers(EventVersionCommitted) {
|
|
if c == ConsumerFAV {
|
|
t.Fatal("fav leaked into live consumers")
|
|
}
|
|
}
|
|
if err := NewRegistry().Register(ConsumerNotify); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestManifestJSONIncludesDisabledFAV(t *testing.T) {
|
|
b, err := ManifestJSON()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(b), EventFAVArtifactStaged) || !strings.Contains(string(b), `"enabled":false`) {
|
|
t.Fatalf("%s", b)
|
|
}
|
|
}
|
|
|
|
func TestIntentPlanContractsOmitSensitivePayload(t *testing.T) {
|
|
forbidden := []string{"prompt", "slots", "permissions", "result", "input"}
|
|
for _, c := range StaticContracts() {
|
|
if !strings.HasPrefix(c.EventName, "intent.plan.") {
|
|
continue
|
|
}
|
|
if !c.Enabled {
|
|
t.Fatalf("%s must be enabled for U4 append", c.EventName)
|
|
}
|
|
if !containsName(c.Producers, "app/intentflow") || !containsName(c.Producers, "events") {
|
|
t.Fatalf("%s producers = %v", c.EventName, c.Producers)
|
|
}
|
|
if !containsName(c.Consumers, ConsumerProjection) || !containsName(c.Consumers, ConsumerNotify) {
|
|
t.Fatalf("%s consumers = %v", c.EventName, c.Consumers)
|
|
}
|
|
for _, field := range c.PayloadFields {
|
|
for _, bad := range forbidden {
|
|
if field == bad {
|
|
t.Fatalf("%s payload contains %s", c.EventName, field)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRegistryParityWithYAML(t *testing.T) {
|
|
root := moduleRoot(t)
|
|
b, err := archtest.LoadBoundaries(archtest.DefaultBoundariesPath(root))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := map[string]Contract{}
|
|
for _, c := range StaticContracts() {
|
|
got[c.EventName] = c
|
|
}
|
|
for name, producers := range b.EventProducers {
|
|
if name == "outbox.notify" {
|
|
continue
|
|
}
|
|
c, ok := got[name]
|
|
if !ok {
|
|
t.Fatalf("yaml producer %s missing from StaticContracts", name)
|
|
}
|
|
for _, p := range producers {
|
|
if !containsName(c.Producers, p) {
|
|
t.Fatalf("yaml producer %s/%s not in Go contract", name, p)
|
|
}
|
|
}
|
|
}
|
|
for name, consumers := range b.EventConsumers {
|
|
if name == "outbox.notify" {
|
|
continue
|
|
}
|
|
c, ok := got[name]
|
|
if !ok {
|
|
t.Fatalf("yaml consumer %s missing from StaticContracts", name)
|
|
}
|
|
for _, cons := range consumers {
|
|
if !containsName(c.Consumers, cons) {
|
|
t.Fatalf("yaml consumer %s/%s not in Go contract", name, cons)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func moduleRoot(t *testing.T) string {
|
|
t.Helper()
|
|
_, file, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
t.Fatal("caller")
|
|
}
|
|
dir := filepath.Dir(file)
|
|
for {
|
|
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
|
return dir
|
|
}
|
|
parent := filepath.Dir(dir)
|
|
if parent == dir {
|
|
t.Fatal("go.mod not found")
|
|
}
|
|
dir = parent
|
|
}
|
|
}
|