Files
wehub-resource-sync f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:36 +08:00

106 lines
2.5 KiB
Go

package main
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSanitizeTerminal(t *testing.T) {
tests := []struct {
name string
in string
want string
}{
{
name: "plain text",
in: "hello world",
want: "hello world",
},
{
name: "newline and tab preserved; CR stripped",
in: "line1\nline2\ttab\rcr",
want: "line1\nline2\ttabcr",
},
{
// Bare \r on a TTY returns the cursor to column 0
// and lets later text overwrite earlier output —
// a spoofing vector even without ANSI escapes.
name: "strips bare CR to block overwrite attacks",
in: "safe output\rEVIL",
want: "safe outputEVIL",
},
{
// CRLF from Windows-style sources collapses to LF;
// terminals treat \n alone as a newline so display
// still looks right.
name: "CRLF collapses to LF",
in: "line1\r\nline2",
want: "line1\nline2",
},
{
name: "strips ESC (C0)",
in: "safe\x1bdangerous",
want: "safedangerous",
},
{
name: "strips ANSI CSI (cursor up)",
in: "before\x1b[1Aoverwritten",
want: "before[1Aoverwritten",
},
{
// ESC (0x1b) is dropped, so the OSC introducer is
// broken. The literal "]8;;…" bytes remain but are
// no longer interpreted as an escape sequence.
name: "strips OSC 8 hyperlink escape",
in: "click \x1b]8;;https://evil.example\x1b\\me\x1b]8;;\x1b\\",
want: "click ]8;;https://evil.example\\me]8;;\\",
},
{
// BEL (0x07) is a C0 control and also dropped.
name: "strips OSC 52 clipboard escape",
in: "benign \x1b]52;c;ZXZpbA==\x07 end",
want: "benign ]52;c;ZXZpbA== end",
},
{
name: "strips title-set OSC 2",
in: "\x1b]2;rm -rf /\x07after",
want: "]2;rm -rf /after",
},
{
name: "strips NUL and DEL",
in: "a\x00b\x7fc",
want: "abc",
},
{
name: "strips raw C1 bytes",
in: "x\x80y\x9fz",
want: "xyz",
},
{
name: "preserves multibyte UTF-8",
in: "héllo 日本語 😀",
want: "héllo 日本語 😀",
},
{
name: "empty string",
in: "",
want: "",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := sanitizeTerminal(tc.in)
assert.Equal(t, tc.want, got,
"sanitizeTerminal(%q)", tc.in)
// Post-condition: no ESC byte or NUL in output.
assert.False(t, strings.ContainsRune(got, 0x1b),
"output still contains ESC: %q", got)
assert.False(t, strings.ContainsRune(got, 0),
"output still contains NUL: %q", got)
})
}
}