@@ -6,16 +6,14 @@ import (
66)
77
88// read_file-style JSON envelope: Go's encoding/json HTML-escapes <, >, & in
9- // the wrapped content, so the raw result exposes < untrusted_content_…
10- // noise. resultPreview must decode the envelope and fold the wrapper.
9+ // the wrapped content, so the raw result exposes \u003c untrusted_content_…
10+ // noise. resultPreview must decode the envelope and fold the wrapper away
11+ // entirely — the body renders bare, with scalar metadata as a footer.
1112func TestResultPreviewJSONEnvelope (t * testing.T ) {
1213 raw := `{"content":"<untrusted_content_dd96e237d3be7447 source=\"/path/to/file.go\">\n217|\n218|\tta := textarea.New()\n</untrusted_content_dd96e237d3be7447>","total_lines":300}`
1314 got := resultPreview (raw )
14- if strings .Contains (got , `<` ) || strings .Contains (got , "untrusted_content_" ) {
15- t .Errorf ("escaped wrapper still visible:\n %s" , got )
16- }
17- if ! strings .Contains (got , "⚠ untrusted: /path/to/file.go" ) {
18- t .Errorf ("missing source badge:\n %s" , got )
15+ if strings .Contains (got , `<` ) || strings .Contains (got , "untrusted_content_" ) || strings .Contains (got , "⚠" ) {
16+ t .Errorf ("wrapper or badge noise still visible:\n %s" , got )
1917 }
2018 if ! strings .Contains (got , "218|\t ta := textarea.New()" ) { // tabs survive sanitize (copy fidelity)
2119 t .Errorf ("body line numbers not intact:\n %s" , got )
@@ -25,16 +23,13 @@ func TestResultPreviewJSONEnvelope(t *testing.T) {
2523 }
2624}
2725
28- // Live (non-JSON) tool results carry the wrapper literally; it folds into a
29- // badge line plus the body.
26+ // Live (non-JSON) tool results carry the wrapper literally; it folds away,
27+ // leaving only the body.
3028func TestResultPreviewLiteralWrapper (t * testing.T ) {
3129 raw := "<untrusted_content_ab12cd34 source=\" /etc/hosts\" >\n 127.0.0.1 localhost\n </untrusted_content_ab12cd34>"
3230 got := resultPreview (raw )
33- if strings .Contains (got , "untrusted_content_" ) {
34- t .Errorf ("wrapper tags still visible:\n %s" , got )
35- }
36- if ! strings .Contains (got , "⚠ untrusted: /etc/hosts" ) {
37- t .Errorf ("missing source badge:\n %s" , got )
31+ if strings .Contains (got , "untrusted_content_" ) || strings .Contains (got , "⚠" ) {
32+ t .Errorf ("wrapper tags or badge still visible:\n %s" , got )
3833 }
3934 if ! strings .Contains (got , "127.0.0.1 localhost" ) {
4035 t .Errorf ("body lost:\n %s" , got )
@@ -64,3 +59,80 @@ func TestResultPreviewMalformedEnvelope(t *testing.T) {
6459 t .Errorf ("malformed envelope rewritten: got %q" , got )
6560 }
6661}
62+
63+ // Parallel tools (parallel_shell) return a top-level results array of per-
64+ // call objects. resultPreview extracts each item's display body — stdout,
65+ // stderr, non-zero exit codes — and drops the JSON noise (command echoes,
66+ // index, duration). Wrappers inside stdout fold away entirely.
67+ func TestResultPreviewParallelResults (t * testing.T ) {
68+ raw := `{"results":[{"index":0,"command":"gofmt -l .","description":"check formatting","stdout":"\u003cuntrusted_content_abc123 source=\"parallel_shell:0:stdout\"\u003e\nREADME.md\n\u003c/untrusted_content_abc123\u003e","stderr":"","exit_code":0,"duration_ms":12},{"index":1,"command":"go vet ./...","description":"vet","stdout":"","stderr":"vets hate this","exit_code":1,"duration_ms":300}]}`
69+ got := resultPreview (raw )
70+ for _ , want := range []string {"[1] README.md" , "[2] exit status 1" , "stderr: vets hate this" } {
71+ if ! strings .Contains (got , want ) {
72+ t .Errorf ("parallel results missing %q in:\n %s" , want , got )
73+ }
74+ }
75+ for _ , banned := range []string {"{" , "}" , "\" command\" " , "gofmt -l" , "go vet ./..." , "index" , "duration_ms" , "description" , "untrusted" , "⚠" } {
76+ if strings .Contains (got , banned ) {
77+ t .Errorf ("parallel results leak %q:\n %s" , banned , got )
78+ }
79+ }
80+ }
81+
82+ // A single-item results array renders the body bare — no index label.
83+ func TestResultPreviewSingleResult (t * testing.T ) {
84+ raw := `{"results":[{"index":0,"command":"ls","stdout":"main.go\nutil.go","stderr":"","exit_code":0,"duration_ms":5}]}`
85+ got := resultPreview (raw )
86+ if ! strings .Contains (got , "main.go" ) || ! strings .Contains (got , "util.go" ) {
87+ t .Errorf ("stdout body lost:\n %s" , got )
88+ }
89+ if strings .Contains (got , "[1]" ) || strings .Contains (got , "ls" ) || strings .Contains (got , "index" ) {
90+ t .Errorf ("single result carries labels or arg echoes:\n %s" , got )
91+ }
92+ }
93+
94+ // Non-stdout result shapes (delegate_tasks headlines) still extract.
95+ func TestResultPreviewResultsHeadline (t * testing.T ) {
96+ raw := `{"results":[{"headline":"built 3 sub-agents","artifacts":[{"id":"a1","path":"x.go","bytes":10}],"cost_usd":0.5}]}`
97+ got := resultPreview (raw )
98+ if ! strings .Contains (got , "built 3 sub-agents" ) {
99+ t .Errorf ("headline body lost:\n %s" , got )
100+ }
101+ if strings .Contains (got , "artifacts" ) || strings .Contains (got , "cost_usd" ) {
102+ t .Errorf ("nested metadata leaked:\n %s" , got )
103+ }
104+ }
105+
106+ // A non-zero exit_code anywhere in a parallel envelope flags the step as
107+ // failed — even when the extracted display text looks innocuous.
108+ func TestHasFailedExit (t * testing.T ) {
109+ for _ , tc := range []struct {
110+ raw string
111+ want bool
112+ }{
113+ {"{\" results\" :[{\" exit_code\" :0}]}" , false },
114+ {"{\" results\" :[{\" stdout\" :\" all good\" }]}" , false },
115+ {"{\" results\" :[{\" exit_code\" :1,\" stdout\" :\" hmm\" }]}" , true },
116+ {"{\" results\" :[{\" exit_code\" :0},{\" exit_code\" :2}]}" , true },
117+ {"plain output" , false },
118+ {"{\" other\" :1}" , false },
119+ } {
120+ if got := hasFailedExit (tc .raw ); got != tc .want {
121+ t .Errorf ("hasFailedExit(%q) = %v, want %v" , tc .raw , got , tc .want )
122+ }
123+ }
124+ }
125+
126+ // Unknown results shapes are never rewritten — the fail-safe holds.
127+ func TestResultPreviewResultsFailSafe (t * testing.T ) {
128+ for _ , s := range []string {
129+ `{"results":[]}` ,
130+ `{"results":["plain string"]}` ,
131+ `{"results":[{"weird":{"a":1}}]}` ,
132+ `{"results":[{"other":"only unknown scalars"}]}` ,
133+ } {
134+ if got := resultPreview (s ); got != s {
135+ t .Errorf ("resultPreview(%q) = %q, want unchanged" , s , got )
136+ }
137+ }
138+ }
0 commit comments