Files
Agent-System/internal/archtest/arch_test_test.go
T
weichen 6a3a0dc201 fix(security): harden bypass authz, gate blind spot, command exec, validated_only (review P0/P1)
- 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
2026-09-26 02:00:14 +00:00

202 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}