feat(intercept): 增加审批记录详情与执行审计

This commit is contained in:
ji ruo committed 2026-09-10 15:10:50 +08:00
1 parent 8dae851b9b
commit 9ad323dc4c
22 files changed
+1687 -535

No files matched your search

+106
View File
@@ -0,0 +1,106 @@
package intercept
import (
"context"
"strings"
"sync"
"testing"
"unicode/utf8"
"github.com/Autumn-27/artex/db"
)
func TestTraceExactCorrelationAndSnapshot(t *testing.T) {
ctx, trace := WithTrace(context.Background(), "save report", []db.InterceptContextEntry{{Kind: "user", Text: "prior message"}})
trace.Start("call-a", "Write", []byte(`{"path":"a","n":12345678901234567890}`))
trace.Append(db.InterceptContextEntry{Kind: "text", Text: "later context"})
callCtx := WithCall(ctx, "Write", []byte(`{ "n":12345678901234567890, "path":"a" }`))
a := auditFor(callCtx, Decision{Action: "allow"}, nil, "allowed")
if a.Correlation != "exact" || a.ToolUseID != "call-a" || len(a.Context) != 1 || a.Context[0].Text != "prior message" {
t.Fatalf("wrong snapshot: %+v", a)
}
var got string
trace.bind("call-a", func(status, output string, cut bool) { got = status + ":" + output })
trace.Complete("different-call", "wrong", false)
if got != "" {
t.Fatal("unrelated result attached")
}
trace.Complete("call-a", "written", false)
trace.Finish()
if got != "succeeded:written" {
t.Fatalf("result %q", got)
}
}
func TestTraceIdenticalParallelCallsAreNeverGuessed(t *testing.T) {
ctx, trace := WithTrace(context.Background(), "test", nil)
input := []byte(`{"command":"pwd"}`)
trace.Start("first", "Bash", input)
trace.Start("second", "Bash", input)
for range 2 {
a := auditFor(WithCall(ctx, "Bash", input), Decision{}, input, "pending")
if a.Correlation != "ambiguous" || a.ToolUseID != "" {
t.Fatalf("guessed identity: %+v", a)
}
}
trace.Complete("first", "first-result", false)
a := auditFor(WithCall(ctx, "Bash", input), Decision{}, input, "pending")
if a.Correlation != "ambiguous" {
t.Fatal("ambiguity must survive the other call completing")
}
}
func TestTraceSequentialIdenticalCallsAndRunIsolation(t *testing.T) {
ctx, trace := WithTrace(context.Background(), "test", nil)
input := []byte(`{}`)
trace.Start("a", "Read", input)
a := auditFor(WithCall(ctx, "Read", input), Decision{}, input, "pending")
trace.Start("b", "Read", input)
b := auditFor(WithCall(ctx, "Read", input), Decision{}, input, "pending")
other, next := WithTrace(context.Background(), "next run", nil)
next.Start("a", "Read", input)
c := auditFor(WithCall(other, "Read", input), Decision{}, input, "pending")
if a.ToolUseID != "a" || b.ToolUseID != "b" || a.RunID == c.RunID {
t.Fatal("run or call identities overlap")
}
}
func TestTraceBoundsAndMissingResult(t *testing.T) {
ctx, trace := WithTrace(context.Background(), strings.Repeat("中文", promptLimit), nil)
for range contextLimit + 5 {
trace.Append(db.InterceptContextEntry{Kind: "text", Text: strings.Repeat("中", entryLimit)})
}
trace.Start("a", "Read", []byte(`{}`))
a := auditFor(WithCall(ctx, "Read", []byte(`{}`)), Decision{}, nil, "pending")
if !a.UserTruncated || !a.ContextTruncated || len(a.Context) != contextLimit || !utf8.ValidString(a.UserMessage) {
t.Fatal("unbounded/invalid snapshot")
}
for _, e := range a.Context {
if len(e.Text) > entryLimit || !utf8.ValidString(e.Text) {
t.Fatal("invalid entry bound")
}
}
got := ""
trace.bind("a", func(status, _ string, _ bool) { got = status })
trace.Finish()
if got != "unknown" {
t.Fatalf("missing result presented as %q", got)
}
}
func TestTraceConcurrentDistinctCalls(t *testing.T) {
ctx, trace := WithTrace(context.Background(), "test", nil)
var wg sync.WaitGroup
for _, id := range []string{"a", "b", "c", "d"} {
wg.Go(func() {
input := []byte(`{"path":"` + id + `"}`)
trace.Start(id, "Read", input)
a := auditFor(WithCall(ctx, "Read", input), Decision{}, input, "allowed")
if a.ToolUseID != id {
t.Errorf("got %s for %s", a.ToolUseID, id)
}
trace.Complete(id, "ok", false)
})
}
wg.Wait()
}