| 1 | package cli |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/json" |
| 6 | "path/filepath" |
| 7 | "strings" |
| 8 | "testing" |
| 9 | "time" |
| 10 | |
| 11 | "reasonix/internal/agent" |
| 12 | "reasonix/internal/recovery" |
| 13 | ) |
| 14 | |
| 15 | func TestSessionMachineRecoveryIsContentFree(t *testing.T) { |
| 16 | identityKey := installMachineTestIdentity(t) |
| 17 | dir := t.TempDir() |
| 18 | saveMachineTestSession(t, dir, "recoverable", time.Date(2026, 7, 23, 14, 0, 0, 0, time.UTC)) |
| 19 | path := filepath.Join(dir, "recoverable.jsonl") |
| 20 | if err := agent.MarkSessionInFlightTurn(path, 1, true); err != nil { |
| 21 | t.Fatalf("mark in-flight: %v", err) |
| 22 | } |
| 23 | if err := recovery.SaveSnapshot(path, recovery.Snapshot{Tasks: map[string]*recovery.TaskState{ |
| 24 | "task": {Phase: recovery.PhaseAwaitingDecision, Pending: &recovery.PendingProposal{Tool: "bash", Subject: "PRIVATE SUBJECT", Args: []byte(`{"secret":"PRIVATE"}`)}}, |
| 25 | }}); err != nil { |
| 26 | t.Fatalf("save recovery: %v", err) |
| 27 | } |
| 28 | |
| 29 | var out bytes.Buffer |
| 30 | if code := runSessionCommand([]string{"recovery", "--json", "--dir", dir}, &out); code != 0 { |
| 31 | t.Fatalf("recovery exit code = %d, output = %s", code, out.String()) |
| 32 | } |
| 33 | var response machineRecoveryList |
| 34 | if err := json.Unmarshal(out.Bytes(), &response); err != nil { |
| 35 | t.Fatalf("decode recovery: %v", err) |
| 36 | } |
| 37 | if len(response.Recoveries) != 1 { |
| 38 | t.Fatalf("recoveries = %+v", response.Recoveries) |
| 39 | } |
| 40 | item := response.Recoveries[0] |
| 41 | if item.SessionID != machineSessionIDWithKey("recoverable", identityKey) || item.State != "awaiting_decision" || item.Tasks != 1 || item.Pending != 1 || !item.InFlight { |
| 42 | t.Fatalf("recovery = %+v", item) |
| 43 | } |
| 44 | if strings.Contains(out.String(), "PRIVATE") || strings.Contains(out.String(), dir) { |
| 45 | t.Fatalf("recovery output leaked private data: %s", out.String()) |
| 46 | } |
| 47 | } |
| 48 |