Test / test (push) Canceled after 0s
Test / fuzz (./compat, FuzzParseFormat) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatJSON) (push) Canceled after 0s
Test / fuzz (./formatter, FuzzFormatTextPolicy) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSanitize) (push) Canceled after 0s
Test / fuzz (./sanitizer, FuzzSerializerJSON) (push) Canceled after 0s
93 lines
3.0 KiB
Go
93 lines
3.0 KiB
Go
package sanitizer
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
func FuzzSanitize(f *testing.F) {
|
|
for _, s := range []string{"", "plain", "\xff\xfe\n\x80", "<00>\x00", "\u0085\u009b[31m", "世界\u202e", "a'$(id)\\*"} {
|
|
f.Add(s, uint8(0), uint64(FilterControl), uint64(TransformHexEncode))
|
|
}
|
|
f.Fuzz(func(t *testing.T, input string, policy uint8, filter, transform uint64) {
|
|
policies := []PolicyPreset{PolicyRaw, PolicyTxt, PolicyJSON, PolicyShell}
|
|
s := New().Policy(policies[int(policy)%len(policies)]).Rule(filter, transform)
|
|
want := s.Sanitize(input)
|
|
got := s.AppendSanitize([]byte("prefix:"), input)
|
|
if string(got) != "prefix:"+want {
|
|
t.Fatalf("append/string disagreement: %q != %q", got, want)
|
|
}
|
|
if want != s.Sanitize(input) {
|
|
t.Fatal("non-deterministic sanitizer")
|
|
}
|
|
if policy%4 == 3 {
|
|
for _, r := range New().Policy(PolicyShell).Sanitize(input) {
|
|
if unicode.IsControl(r) || unicode.IsSpace(r) || matchesFilter(r, FilterShellSpecial) {
|
|
t.Fatalf("shell filter leaked %U", r)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func FuzzSerializerJSON(f *testing.F) {
|
|
for _, s := range []string{"", "\xff\xfe\x00", "a\"\\\nb", "\u0085", "世界"} {
|
|
f.Add(s, uint8(0))
|
|
}
|
|
f.Fuzz(func(t *testing.T, input string, policy uint8) {
|
|
policies := []PolicyPreset{PolicyRaw, PolicyTxt, PolicyJSON, PolicyShell}
|
|
s := New().Policy(policies[int(policy)%len(policies)])
|
|
out := []byte("prefix:")
|
|
NewSerializer("json", s).WriteString(&out, input)
|
|
if !strings.HasPrefix(string(out), "prefix:") {
|
|
t.Fatal("prefix changed")
|
|
}
|
|
data := out[len("prefix:"):]
|
|
if !utf8.Valid(data) || !json.Valid(data) {
|
|
t.Fatalf("invalid JSON string %q", data)
|
|
}
|
|
var got, want string
|
|
if err := json.Unmarshal(data, &got); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// encoding/json is an independent oracle for malformed UTF-8 replacement.
|
|
oracle, err := json.Marshal(s.Sanitize(input))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := json.Unmarshal(oracle, &want); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != want {
|
|
t.Fatalf("round trip: %q != %q", got, want)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestSanitizerMalformedUTF8AndTransforms(t *testing.T) {
|
|
for _, input := range []string{"\xff", "\xff\n\xfe", "\n\xff"} {
|
|
s := New().Policy(PolicyJSON)
|
|
eq(t, string(s.AppendSanitize(nil, input)), s.Sanitize(input), "malformed UTF-8 consistency")
|
|
}
|
|
eq(t, New().Rule(FilterControl, 0).Sanitize("a\x00b"), "a\x00b", "zero transform preserves")
|
|
eq(t, New().Policy(PolicyJSON).Sanitize("\u0085\u009b"), `\u0085\u009b`, "C1 controls escaped")
|
|
var out []byte
|
|
NewSerializer("unknown", nil).WriteString(&out, "a b")
|
|
eq(t, string(out), `"a b"`, "nil sanitizer and unknown format")
|
|
}
|
|
|
|
func TestSerializerInvalidNumbers(t *testing.T) {
|
|
for _, input := range []string{"", "NaN", "+Inf", "-Inf", "01", "1,2", "null", "1\n", "1 "} {
|
|
var out []byte
|
|
NewSerializer("json", nil).WriteNumber(&out, input)
|
|
var got string
|
|
if err := json.Unmarshal(out, &got); err != nil {
|
|
t.Fatalf("%q must be represented as string: %q (%v)", input, out, err)
|
|
}
|
|
eq(t, got, input, "invalid number round trip")
|
|
}
|
|
}
|