vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
Fuzz the parsers that read untrusted input
16bf0ebf8054de5044a52f93d156402542f0f71a · Keenan Nemetz · 10d ago · parent 70ba9a69
Fuzz the parsers that read untrusted input The SSH exec line, the Git HTTP route, and the LFS packet stream are all hand-written parsers on bytes a client controls, and each was covered only by a table of examples someone thought to write. Six targets, each asserting a property rather than waiting for a panic: the command parser cannot invent bytes and its output survives being quoted back, a route re-routes from its own parts and never names more than one path segment, a repository argument is a name and not a path, and the packet reader's lines survive being framed again. The seeds are the shapes the clients actually send, so go test ./... keeps guarding them and a fuzz target costs a push nothing. The route fuzzer found one gap on its first run: /git/.git/info/refs gave back an empty repository name with ok set, and only the store refused it. A route that answers ok now means a name the rest of the path applies to. Closes #96.
server/githttp/githttp.go +10−3
| @@ -125,12 +125,19 @@ func Route(path string) (name, rest string, ok bool) { | |||
| 125 | 125 | if i <= 0 { | |
| 126 | 126 | return "", "", false | |
| 127 | 127 | } | |
| 128 | dir := trimmed[:i] | ||
| 128 | name = trimmed[:i] | ||
| 129 | 129 | rest = trimmed[i+1:] | |
| 130 | if !strings.HasSuffix(dir, ".git") { | ||
| 130 | if !strings.HasSuffix(name, ".git") { | ||
| 131 | 131 | return "", "", false | |
| 132 | 132 | } | |
| 133 | return strings.TrimSuffix(dir, ".git"), rest, true | ||
| 133 | name = strings.TrimSuffix(name, ".git") | ||
| 134 | // "/git/.git/info/refs" names no repository. The store refuses an empty name | ||
| 135 | // as well, but a route that answers ok has to mean a name the rest of the path | ||
| 136 | // can be applied to, or the next caller has to remember to check. | ||
| 137 | if name == "" { | ||
| 138 | return "", "", false | ||
| 139 | } | ||
| 140 | return name, rest, true | ||
| 134 | 141 | } | |
| 135 | 142 | ||
| 136 | 143 | // IsPush reports whether a request is asking to write. | |