package archtest import ( "path/filepath" "runtime" "strings" "testing" "time" ) func miniRoot(t *testing.T) string { t.Helper() _, file, _, ok := runtime.Caller(0) if !ok { t.Fatal("caller") } return filepath.Join(filepath.Dir(file), "testdata", "mini") } func fixtureBoundaries() *Boundaries { return &Boundaries{ Imports: map[string][]string{ "server": {}, "docgov": {}, }, TableOwners: map[string][]string{ "document_records": {"docgov"}, }, PathOwners: map[string][]string{ "output.md": {"squad", "workspace"}, }, EventProducers: map[string][]string{ "outbox.notify": {"docrevision"}, "document.agent_version_committed": {"docrevision"}, }, EventConsumers: map[string][]string{ "outbox.notify": {"notification"}, }, BaselineCounts: map[string]int{}, } } func scanMini(t *testing.T) []Finding { t.Helper() findings, err := Scan(ScanOptions{Root: miniRoot(t)}, fixtureBoundaries()) if err != nil { t.Fatal(err) } return findings } func TestGooseAndTestsAreNotProductionWriters(t *testing.T) { for _, f := range scanMini(t) { if f.Kind == KindSQLWrite && f.Package == "docgov" && f.File == "internal/docgov/owner_write_test.go" { t.Fatalf("test file must not be a production writer: %+v", f) } if f.Kind == KindSQLWrite && filepath.Ext(f.File) == ".sql" { t.Fatalf("goose/sql must not be a production writer: %+v", f) } } } func TestNonOwnerProductionWriteIsBlockedAndNamed(t *testing.T) { var hit *Finding findings := scanMini(t) for i, f := range findings { if f.Kind == KindSQLWrite && f.Symbol == "document_records" && f.Package == "server" { hit = &findings[i] if f.File != "internal/server/rogue_write.go" { t.Fatalf("expected rogue_write.go, got %s", f.File) } } } if hit == nil { t.Fatal("expected UPDATE document_records in internal/server/rogue_write.go to be blocked") } } func TestOwnerProductionWriteIsAllowed(t *testing.T) { for _, f := range scanMini(t) { if f.Kind == KindSQLWrite && f.Package == "docgov" && f.File == "internal/docgov/owner_write.go" { t.Fatalf("owner write should be allowed: %+v", f) } } } // TestUntrackedTableWriteIsBlocked FIND-ARCH-01 回归:未登记表的生产写 // 不再被静默跳过,必须产生 sql_write finding(fail-closed)。 func TestUntrackedTableWriteIsBlocked(t *testing.T) { var hit *Finding findings := scanMini(t) for i, f := range findings { if f.Kind == KindSQLWrite && f.Symbol == "brand_new_table" && f.Package == "server" { hit = &findings[i] if f.File != "internal/server/untracked_write.go" { t.Fatalf("expected untracked_write.go, got %s", f.File) } if !strings.Contains(f.Detail, "untracked table") { t.Fatalf("expected untracked-table detail, got %q", f.Detail) } } } if hit == nil { t.Fatal("expected INSERT INTO brand_new_table in internal/server/untracked_write.go to be blocked as untracked") } } // TestUpsertSetKeywordIsNotFlaggedAsUntracked 证明 ON CONFLICT DO UPDATE SET // 等正则假阳性词汇不会因 fail-closed 改动而误报。 func TestUpsertSetKeywordIsNotFlaggedAsUntracked(t *testing.T) { for _, f := range scanMini(t) { if f.Kind == KindSQLWrite && f.Symbol == "set" { t.Fatalf("upsert SET keyword must stay exempt noise, got finding: %+v", f) } if f.Kind == KindSQLWrite && f.Package == "docgov" && f.File == "internal/docgov/owner_upsert_write.go" { t.Fatalf("owner upsert must stay allowed (incl. SET noise): %+v", f) } } } func TestPathJoinConcatAndConstAreDetected(t *testing.T) { want := map[string]bool{ "internal/server/path_join.go": false, "internal/server/path_concat.go": false, "internal/server/path_const.go": false, } for _, f := range scanMini(t) { if f.Kind != KindPath || f.Symbol != "output.md" { continue } if _, ok := want[f.File]; ok { want[f.File] = true } } for file, seen := range want { if !seen { t.Errorf("path construction not detected in %s", file) } } } func TestUnauthorizedEventProducerIsBlocked(t *testing.T) { found := false for _, f := range scanMini(t) { if f.Kind == KindEvent && f.Package == "server" { found = true } } if !found { t.Fatal("expected unauthorized OnOutbox producer in server to be blocked") } } func TestExceptionRequiresExpiryAndOwner(t *testing.T) { b := fixtureBoundaries() b.Exceptions = []Exception{{ Kind: KindSQLWrite, Package: "server", File: "internal/server/rogue_write.go", Symbol: "document_records", Reason: "no owner or expiry", }} ev := Evaluate(scanMini(t), b, time.Date(2026, 9, 14, 12, 0, 0, 0, time.UTC)) if len(ev.BadExceptions) == 0 { t.Fatal("expected missing owner/expires to block") } if len(ev.Unmatched) == 0 { t.Fatal("invalid exception must not hide the finding") } } func TestExpiredExceptionBlocksImmediately(t *testing.T) { b := fixtureBoundaries() b.Exceptions = []Exception{{ Kind: KindSQLWrite, Package: "server", File: "internal/server/rogue_write.go", Symbol: "document_records", Owner: "server", Reason: "stale", Milestone: "U3", Expires: "2026-09-01", }} ev := Evaluate(scanMini(t), b, time.Date(2026, 9, 14, 12, 0, 0, 0, time.UTC)) if len(ev.BadExceptions) == 0 { t.Fatal("expected expired exception to block") } found := false for _, f := range ev.Unmatched { if f.File == "internal/server/rogue_write.go" { found = true } } if !found { t.Fatal("expired exception must surface the original finding") } } func TestClassifyGooseSQL(t *testing.T) { root := miniRoot(t) got := classifyFile(root, filepath.Join(root, "deploy", "postgres", "goose", "00001_fixture.sql")) if got != classGoose { t.Fatalf("classify goose: got %v want %v", got, classGoose) } got = classifyFile(root, filepath.Join(root, "internal", "docgov", "owner_write_test.go")) if got != classTestOrFixture { t.Fatalf("classify test: got %v want %v", got, classTestOrFixture) } }