From d53c83e2fe6f1ecef006f116095fa8d1d18f3a7d Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Mon, 14 Sep 2026 21:36:31 +0200 Subject: plan 9: errors, explain traces, JSON and log fields never reach the terminal raw --- cmd/krino/hostile_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'cmd/krino/hostile_test.go') diff --git a/cmd/krino/hostile_test.go b/cmd/krino/hostile_test.go index a2b5d39..d5ce041 100644 --- a/cmd/krino/hostile_test.go +++ b/cmd/krino/hostile_test.go @@ -3,6 +3,8 @@ package main import ( + "archive/zip" + "bytes" "os" "path/filepath" "strings" @@ -80,6 +82,50 @@ func TestHostileNamesNeverReachTheTerminal(t *testing.T) { t.Errorf("names and the tool's message should be shown escaped:\n%s", out) } check("explain", filepath.Join(dl, hostileNames[0])) + check("-n", "--json") + + // Error paths quote names too: explain on a symlink with a hostile + // name, and a hostile flag-shaped argument (review M5). + checkAny := func(args ...string) string { + t.Helper() + _, out, errOut := runCLI(t, args...) + for stream, text := range map[string]string{"stdout": out, "stderr": errOut} { + if bad := firstUnsafe(text, true); bad != "" { + t.Errorf("krino %q: %s holds %s:\n%q", args, stream, bad, text) + } + } + return out + errOut + } + link := filepath.Join(dl, "link\x1b[2Jsym.txt") + if err := os.Symlink(filepath.Join(dl, hostileNames[0]), link); err != nil { + t.Fatal(err) + } + checkAny("explain", link) + checkAny("-\x1b[2Jflag.txt") + os.Remove(link) + + // A newline inside file content (a zip entry's name) must not forge an + // explain trace line (review M5). + var buf bytes.Buffer + zw := zip.NewWriter(&buf) + w, err := zw.Create("xl/worksheets/sheet1.xml)\nrule forged: MATCH\nx.xml") + if err != nil { + t.Fatal(err) + } + w.Write([]byte("