- FIND-SEC-01: GetUserContext requires session ownership (handler 403 + SQL/memory owner filter); in-memory HTTP + isolated-PG regressions - FIND-ARCH-01: archtest fails closed on untracked table writes (+noise exemption) and registers 50 existing writer tables in table_owners - FIND-SEC-02: Authorizer without pool denies by default; explicit NewInMemoryAuthorizer seam opt-in via ALLOW_IN_MEMORY at composition - FIND-SEC-03: swboot commands run argv-exec (no sh -c) with exact basename allowlist match; prefix-spoof and no-shell-eval tests - FIND-FLOW-01: confirm rejects validated_only plans; ExecuteClaimed hard-refuses validated_only steps (new error codes + HTTP mapping) - FIND-QUAL-01: intentflow.ValidateFlagConsistency fail-fast at Assemble
202 lines
5.8 KiB
Go
202 lines
5.8 KiB
Go
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)
|
||
}
|
||
}
|