141 lines
5.1 KiB
Go
141 lines
5.1 KiB
Go
package profile
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestRedactTextConservativelyScansMalformedCredentials(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "carriage return in password",
|
|
input: "before http://alice:first\rsecond@proxy.example:8080 after",
|
|
expected: "before http://alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "line feed in password",
|
|
input: "before http://alice:first\nsecond@proxy.example:8080 after",
|
|
expected: "before http://alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "spaces in password",
|
|
input: "before http://alice:two words here@proxy.example:8080 after",
|
|
expected: "before http://alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "slash in password",
|
|
input: "before http://alice:part/other@proxy.example:8080 after",
|
|
expected: "before http://alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "unsupported scheme and CRLF space slash password",
|
|
input: "probe failed [ftp+ssh://alice:line one/line\r\ntwo@proxy.example:8080] retrying",
|
|
expected: "probe failed [ftp+ssh://alice:REDACTED@proxy.example:8080] retrying",
|
|
},
|
|
{
|
|
name: "bare malformed userinfo",
|
|
input: "before alice:bare secret/part@proxy.example:8080 after",
|
|
expected: "before alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "multiple at signs",
|
|
input: "before http://alice:sec@ret@proxy.example:8080 after",
|
|
expected: "before http://alice:REDACTED@proxy.example:8080 after",
|
|
},
|
|
{
|
|
name: "multiple URLs on one line",
|
|
input: "left http://alice:first@one.example:1 middle invalid-scheme://bob:second value@two.example:2 right",
|
|
expected: "left http://alice:REDACTED@one.example:1 middle invalid-scheme://bob:REDACTED@two.example:2 right",
|
|
},
|
|
{
|
|
name: "prose labels before URLs",
|
|
input: "Proxy URL: odd+scheme://alice:first@one.example:1; fallback URL: invalid://bob:second@two.example:2",
|
|
expected: "Proxy URL: odd+scheme://alice:REDACTED@one.example:1; fallback URL: invalid://bob:REDACTED@two.example:2",
|
|
},
|
|
{
|
|
name: "surrounding diagnostics with colons remain",
|
|
input: "error: connect alice:secret@proxy.example:80: refused; code: EHOSTUNREACH",
|
|
expected: "error: connect alice:REDACTED@proxy.example:80: refused; code: EHOSTUNREACH",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := RedactText(test.input); got != test.expected {
|
|
t.Fatalf("RedactText() = %q, want %q", got, test.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRedactTextDoesNotSwallowUnrelatedTextAcrossLines(t *testing.T) {
|
|
input := "diagnostic:\ncontact admin@example.com\nnext diagnostic remains"
|
|
if got := RedactText(input); got != input {
|
|
t.Fatalf("RedactText crossed a diagnostic line boundary: got %q, want %q", got, input)
|
|
}
|
|
|
|
input = "first http://alice:first@one.example:1\nsecond http://bob:second@two.example:2\ntrailing diagnostic"
|
|
want := "first http://alice:REDACTED@one.example:1\nsecond http://bob:REDACTED@two.example:2\ntrailing diagnostic"
|
|
if got := RedactText(input); got != want {
|
|
t.Fatalf("RedactText swallowed across independent URL lines: got %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestRedactUserinfoTextRemovesCompleteMalformedUserinfoAndPreservesContext(t *testing.T) {
|
|
cases := []struct {
|
|
input string
|
|
userinfo string
|
|
expected string
|
|
}{
|
|
{
|
|
input: "BEGIN unsupported://alice:secret words/part@proxy.example:80 END",
|
|
userinfo: "alice:secret words/part",
|
|
expected: "BEGIN unsupported://REDACTED@proxy.example:80 END",
|
|
},
|
|
{
|
|
input: "BEGIN alice:secret\r\nwords@proxy.example:80 END",
|
|
userinfo: "alice:secret\r\nwords",
|
|
expected: "BEGIN REDACTED@proxy.example:80 END",
|
|
},
|
|
{
|
|
input: "BEGIN http://alice:sec@ret@proxy.example:80 END",
|
|
userinfo: "alice:sec@ret",
|
|
expected: "BEGIN http://REDACTED@proxy.example:80 END",
|
|
},
|
|
}
|
|
|
|
for _, test := range cases {
|
|
got := RedactUserinfoText(test.input)
|
|
if strings.Contains(got, test.userinfo) {
|
|
t.Fatalf("RedactUserinfoText retained userinfo %q in %q", test.userinfo, got)
|
|
}
|
|
if got != test.expected {
|
|
t.Fatalf("RedactUserinfoText(%q) = %q, want %q", test.input, got, test.expected)
|
|
}
|
|
if !strings.HasPrefix(got, "BEGIN ") || !strings.HasSuffix(got, " END") {
|
|
t.Fatalf("RedactUserinfoText swallowed surrounding diagnostics: %q", got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRedactionPreservesArbitrarySurroundingDiagnostics(t *testing.T) {
|
|
prefixes := []string{"", "error: ", "[target apt] ", "first URL failed; "}
|
|
suffixes := []string{"", " (retrying)", "; next check continues", "\nstack trace follows"}
|
|
for _, prefix := range prefixes {
|
|
for _, suffix := range suffixes {
|
|
input := prefix + "odd+scheme://user:malformed secret/path@host.example:9" + suffix
|
|
got := RedactText(input)
|
|
if strings.Contains(got, "malformed secret/path") {
|
|
t.Fatalf("secret survived for prefix=%q suffix=%q: %q", prefix, suffix, got)
|
|
}
|
|
if !strings.HasPrefix(got, prefix) || !strings.HasSuffix(got, suffix) {
|
|
t.Fatalf("surrounding diagnostics changed for prefix=%q suffix=%q: %q", prefix, suffix, got)
|
|
}
|
|
}
|
|
}
|
|
}
|