package contracts_test import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "os" "path/filepath" "strings" "testing" "github.com/santhosh-tekuri/jsonschema/v6" "git.ipao.vip/rogee/go-sip/internal/tenant" ) const v1Dir = "upstream/v1" const v1Base = "https://go-sip.local/contracts/v1/" type offlineLoader struct{} func (offlineLoader) Load(url string) (any, error) { return nil, fmt.Errorf("schema is not in the immutable local bundle: %s", url) } func compileV1(t *testing.T, name string) *jsonschema.Schema { t.Helper() compiler := jsonschema.NewCompiler() compiler.AssertFormat() compiler.UseLoader(offlineLoader{}) paths, err := filepath.Glob(filepath.Join(v1Dir, "*.schema.json")) if err != nil || len(paths) == 0 { t.Fatalf("contract bundle missing: %v", err) } for _, path := range paths { var schema any if err := json.Unmarshal(readV1(t, path), &schema); err != nil { t.Fatal(err) } if err := compiler.AddResource(v1Base+filepath.Base(path), schema); err != nil { t.Fatal(err) } } schema, err := compiler.Compile(v1Base + name) if err != nil { t.Fatal(err) } return schema } func readV1(t *testing.T, path string) []byte { t.Helper() raw, err := os.ReadFile(path) if err != nil { t.Fatal(err) } return raw } func objectV1(t *testing.T, path string) map[string]any { t.Helper() var value map[string]any if err := json.Unmarshal(readV1(t, path), &value); err != nil { t.Fatal(err) } return value } func TestV1BundleFixtures(t *testing.T) { for _, name := range []string{"mq.schema.json", "event-payloads.schema.json", "dispatcher-config.schema.json"} { t.Run(name, func(t *testing.T) { compileV1(t, name) }) } var cases []struct { File string `json:"file"` Schema string `json:"schema"` Valid bool `json:"valid"` } if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "fixtures.json")), &cases); err != nil { t.Fatal(err) } if len(cases) < 16 { t.Fatal("missing bounded positive and negative message/config fixtures") } for _, tc := range cases { t.Run(tc.File, func(t *testing.T) { schema := compileV1(t, tc.Schema) value := objectV1(t, filepath.Join(v1Dir, tc.File)) err := schema.Validate(value) if (err == nil) != tc.Valid { t.Fatalf("valid=%v, validation=%v", tc.Valid, err) } }) } } func TestV1ExecuteIdentityAndTenantConstraints(t *testing.T) { schema := compileV1(t, "mq.schema.json") for _, tc := range []struct { name string edit func(map[string]any) }{ {"missing dispatcher", func(m map[string]any) { delete(m, "dispatcher_id") }}, {"non UUID dispatcher", func(m map[string]any) { m["dispatcher_id"] = "dispatcher-a" }}, {"uppercase dispatcher", func(m map[string]any) { m["dispatcher_id"] = strings.ToUpper(m["dispatcher_id"].(string)) }}, {"wildcard tenant", func(m map[string]any) { m["tenant_key"] = "tenant.#" }}, {"old version", func(m map[string]any) { m["schema_version"] = "1.0" }}, {"extra root", func(m map[string]any) { m["metadata"] = map[string]any{} }}, {"extra payload", func(m map[string]any) { m["payload"].(map[string]any)["mode"] = "full_ai" }}, } { t.Run(tc.name, func(t *testing.T) { value := objectV1(t, filepath.Join(v1Dir, "examples/call-execute.json")) tc.edit(value) if err := schema.Validate(value); err == nil { t.Fatal("invalid envelope accepted") } }) } } func TestV1ResponseCorrelationAndResultBranches(t *testing.T) { schema := compileV1(t, "mq.schema.json") for _, tc := range []struct { name string edit func(map[string]any) }{ {"missing correlation", func(m map[string]any) { delete(m, "correlation_id") }}, {"wrong result", func(m map[string]any) { m["status"] = "rejected"; m["reason_code"] = "ok" }}, {"response deadline", func(m map[string]any) { m["not_after"] = "2026-09-21T00:00:30Z" }}, {"missing command ID", func(m map[string]any) { delete(m["payload"].(map[string]any), "command_id") }}, {"extra result", func(m map[string]any) { m["payload"].(map[string]any)["raw"] = map[string]any{} }}, } { t.Run(tc.name, func(t *testing.T) { value := objectV1(t, filepath.Join(v1Dir, "examples/command-query-result.json")) tc.edit(value) if err := schema.Validate(value); err == nil { t.Fatal("invalid query response accepted") } }) } } func TestV1UploadIsAFactNotASaaSHandshake(t *testing.T) { schema := compileV1(t, "mq.schema.json") for _, field := range []string{"oss_id", "verified", "token", "upload_url", "access_key_secret"} { t.Run(field, func(t *testing.T) { value := objectV1(t, filepath.Join(v1Dir, "examples/event-recording-uploaded.json")) value["payload"].(map[string]any)[field] = "not-a-real-value" if err := schema.Validate(value); err == nil { t.Fatal("uploaded fact accepted a credential or SaaS processing claim") } }) } for _, kind := range []string{"recording.upload-session.request", "recording.upload-session.result", "recording.complete", "recording.verified"} { if strings.Contains(string(readV1(t, filepath.Join(v1Dir, "mq.schema.json"))), `"`+kind+`"`) { t.Errorf("removed upload handshake is still in the published schema: %s", kind) } } } func TestV1DispatcherConfigDoesNotAcceptSecretsOrTTLOverride(t *testing.T) { schema := compileV1(t, "dispatcher-config.schema.json") for _, field := range []string{"access_key_id", "access_key_secret", "grant_ttl_seconds", "token"} { t.Run(field, func(t *testing.T) { value := objectV1(t, filepath.Join(v1Dir, "examples/dispatcher-config.json")) value["oss"].(map[string]any)[field] = "not-a-real-value" if err := schema.Validate(value); err == nil { t.Fatal("unexpected secret/override field accepted") } }) } } func TestV1TopologyMatchesDispatcherRoutes(t *testing.T) { var topology struct { Exchanges map[string]struct { Type string `json:"type"` Durable bool `json:"durable"` } `json:"exchanges"` Inbox string `json:"inbox_queue"` Dead string `json:"dead_letter_queue"` Inbound string `json:"inbound_key"` Outbound string `json:"outbound_key"` Durable bool `json:"business_queues_durable"` Persistent bool `json:"message_persistent"` Mandatory bool `json:"publish_mandatory"` Confirm bool `json:"publisher_confirms"` TenantBytes int `json:"tenant_key_max_utf8_bytes"` TokenSeconds int `json:"upload_token_seconds"` } if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "mq-topology.json")), &topology); err != nil { t.Fatal(err) } if !topology.Durable || !topology.Persistent || !topology.Mandatory || !topology.Confirm || topology.TenantBytes != 196 || topology.TokenSeconds != 900 { t.Fatal("topology weakens the approved queue/token boundary") } if len(topology.Exchanges) != 3 { t.Fatal("unexpected exchange topology") } for _, name := range []string{"agent-call.dispatchers.v2", "agent-call.saas.v2", "agent-call.dead-letter.v2"} { x, ok := topology.Exchanges[name] if !ok || x.Type != "topic" || !x.Durable { t.Fatalf("wrong exchange contract: %s", name) } } id := "c046b893-8628-4589-ae50-619d049248a6" for _, key := range []string{"tenant-a", "租户.甲", strings.Repeat("a", 196)} { route, err := tenant.NewDispatcherRoute(id, key) if err != nil { t.Fatal(err) } r := strings.NewReplacer("", id, "", key) if route.InboxQueue != r.Replace(topology.Inbox) || route.DeadLetterQueue != r.Replace(topology.Dead) || route.InboundKey != r.Replace(topology.Inbound) || route.OutboundKey != r.Replace(topology.Outbound) { t.Fatal("implementation differs from the published route templates") } } } func TestV1ManifestPinsEveryBundleFile(t *testing.T) { var manifest struct { Version string `json:"version"` Source string `json:"source"` Files map[string]string `json:"files"` } if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "manifest.json")), &manifest); err != nil { t.Fatal(err) } if manifest.Version != "v1" || manifest.Source != "project-development-v1" || len(manifest.Files) == 0 { t.Fatal("invalid project-local provenance") } err := filepath.WalkDir(v1Dir, func(path string, entry os.DirEntry, err error) error { if err != nil || entry.IsDir() { return err } rel, err := filepath.Rel(v1Dir, path) if err != nil || rel == "manifest.json" { return err } actual := sha256.Sum256(readV1(t, path)) if manifest.Files[filepath.ToSlash(rel)] != hex.EncodeToString(actual[:]) { t.Errorf("missing/incorrect manifest hash: %s", rel) } return nil }) if err != nil { t.Fatal(err) } for rel := range manifest.Files { if !filepath.IsLocal(rel) { t.Errorf("non-local manifest entry: %s", rel) continue } if _, err := os.Stat(filepath.Join(v1Dir, rel)); err != nil { t.Error(err) } } }