12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 | package render_test
import (
"net/url"
"path"
"path/filepath"
"strings"
"testing"
"code.bruce-hill.com/repo-renderer/internal/render"
)
// Run one with `make fuzz`; plain `go test` runs only the seeds.
var fuzzLay = render.Layout{GitBase: "/var/git", Htdocs: "/htdocs/h", QueueDir: "/spool", State: "/db"}
// under reports whether p lies strictly inside dir.
func under(p, dir string) bool {
rel, err := filepath.Rel(dir, p)
return err == nil && filepath.IsLocal(rel)
}
// Tree paths come from the pusher. Every one ValidPath admits must land
// inside its repository's output directories and come back out of its URL
// unchanged, with nothing taken for a query or fragment.
func FuzzValidPath(f *testing.F) {
for _, s := range []string{
"a", "src/main.c", "..", "a/../b", "./a", "a//b", "/etc/passwd", "a/",
"a?b#c", "%2e%2e", "a b/ü.txt", "x\x00y", "a\\..\\b", "index.html", "...",
} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, p string) {
if !render.ValidPath(p) {
return
}
if path.Clean(p) != p || !filepath.IsLocal(p) {
t.Fatalf("ValidPath(%q) but it is not clean and local", p)
}
for name, pair := range map[string][2]string{
"page": {fuzzLay.Page("r", p), fuzzLay.RepoDir("r")},
"raw": {fuzzLay.Raw("r", p), fuzzLay.RawDir("r")},
"svg": {fuzzLay.SVG("r", p), fuzzLay.SVGDir("r")},
} {
if !under(pair[0], pair[1]) {
t.Fatalf("%s of %q is %s, outside %s", name, p, pair[0], pair[1])
}
}
for prefix, u := range map[string]string{
"/code/r/": render.CodeURL("r", p),
"/raw/r/": render.RawURL("r", p),
"/svg/r/": render.SVGURL("r", p),
} {
pu, err := url.Parse(u)
if err != nil || pu.Path != prefix+p || pu.RawQuery != "" || pu.Fragment != "" || pu.Host != "" {
t.Fatalf("URL %q of %q parses as %+v (%v)", u, p, pu, err)
}
}
})
}
// Tag names come from the pusher too. A sanitized name must be a single
// harmless file name in the repository's archive directory.
func FuzzSanitizeTag(f *testing.F) {
for _, s := range []string{"v1.0", "release/2", "..", ".hidden", "a/../b", "-x", "v1?x", "", "/", "a\x00"} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, tag string) {
s, ok := render.SanitizeTag(tag)
if !ok {
return
}
if s == "" || strings.ContainsAny(s, "/\\\x00") || s == "." || s == ".." {
t.Fatalf("SanitizeTag(%q) = %q", tag, s)
}
a := fuzzLay.Archive("r", s)
if filepath.Dir(a) != fuzzLay.ArchiveDir("r") || filepath.Base(a) != "r-"+s+".tar.gz" {
t.Fatalf("archive of %q is %s", tag, a)
}
pu, err := url.Parse(render.ArchiveURL("r", s))
if err != nil || pu.Path != "/archive/r/r-"+s+".tar.gz" || pu.RawQuery != "" || pu.Fragment != "" {
t.Fatalf("archive URL of %q parses as %+v (%v)", tag, pu, err)
}
})
}
|