1package subagents
2
3import (
4 "encoding/json"
5 "strings"
6 "testing"
7
8 "github.com/bnema/zut/packages/core"
9 "github.com/bnema/zut/packages/provider"
10)
11
12func TestResidentHandoffOmitsRawToolSecrets(t *testing.T) {
13 journal, err := OpenResidentJournal(t.TempDir(), "handoff-secrets")
14 if err != nil {
15 t.Fatal(err)
16 }
17 t.Cleanup(func() { _ = journal.Close() })
18 spec := ResidentChildSpec{ID: "handoff-secrets", SessionID: "session", InitialTurnID: "turn", Provider: "openai", Model: "test"}
19 if err := journal.Accept(spec, "check service"); err != nil {
20 t.Fatal(err)
21 }
22 if err := journal.RecordTurnStarted(spec, spec.InitialTurnID); err != nil {
23 t.Fatal(err)
24 }
25 args := json.RawMessage(`{"command":"curl -H 'Authorization: Bearer synthetic-argument-secret' localhost"}`)
26 for _, event := range []core.AgentEvent{
27 core.EvAssistantMessage{Message: provider.Message{Role: provider.RoleAssistant, Content: []provider.Content{provider.TextBlock{Text: "Service verification is incomplete."}, provider.ToolCallBlock{ID: "call", Name: "bash", Arguments: args}}}},
28 core.EvToolCall{ID: "call", Name: "bash", Args: args},
29 core.EvToolResult{ID: "call", Result: core.ToolResult{IsError: true, Content: []provider.Content{provider.TextBlock{Text: "response token=synthetic-output-secret"}}}},
30 } {
31 if err := journal.RecordAgentEvent(event); err != nil {
32 t.Fatal(err)
33 }
34 }
35 if err := journal.RecordTurnFinished(spec, spec.InitialTurnID, ErrBudgetExceeded); err != nil {
36 t.Fatal(err)
37 }
38 result, err := journal.Result()
39 if err != nil {
40 t.Fatal(err)
41 }
42 update := FormatCompletionUpdate([]Completion{(ResidentCompletion{ChildID: spec.ID, TurnID: spec.InitialTurnID, Err: ErrBudgetExceeded, Summary: result.Handoff}).Completion()}, "")
43 for _, text := range []string{result.Handoff, update} {
44 for _, secret := range []string{"synthetic-argument-secret", "synthetic-output-secret", "Authorization", "curl"} {
45 if strings.Contains(text, secret) {
46 t.Fatalf("handoff disclosed raw tool payload %q", secret)
47 }
48 }
49 for _, want := range []string{"Service verification is incomplete.", "tool bash (call)", "is_error=true", HistoryRef(spec.ID)} {
50 if !strings.Contains(text, want) {
51 t.Fatalf("handoff missing safe metadata %q: %s", want, text)
52 }
53 }
54 }
55 items, err := ReadResidentHistory(journal.Dir(), 16)
56 if err != nil {
57 t.Fatal(err)
58 }
59 raw, err := json.Marshal(items)
60 if err != nil || !strings.Contains(string(raw), "synthetic-argument-secret") || !strings.Contains(string(raw), "synthetic-output-secret") {
61 t.Fatal("omitting automatic payloads must not destroy durable recovery history")
62 }
63}