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.
Bound the anonymous Git HTTP read path
86991e7020a418a08a5e3a36ce8f296561392e3b · Keenan Nemetz · 13d ago · parent e05f1c48
Bound the anonymous Git HTTP read path The transport that needs no account had no bound on anything: the request body was capped only at "not negative", the backend ran without a request context or deadline, the path check accepted any suffix after `git-upload-pack` and handed it to the CGI as `PATH_INFO`, and the server set no `ReadTimeout` and no `MaxHeaderBytes`. Bound what the read side can spend, which is every dimension available to a fetch and none of the ones a push would need: a 2 MiB body cap with a required `Content-Length`, exactly two endpoints with one method and one service each so the CGI never sees an unvalidated path, `exec.CommandContext` plus `WaitDelay` plus an explicit kill so a disconnect or an expired budget stops git instead of leaving it running, and a concurrency semaphore with a per-client bound that answers 503 with Retry-After rather than queueing. The client address is the connection's own unless the operator names a proxy header, because behind a proxy the connection address is the proxy. Both limits and the header name are configuration, `git_http` turns the transport off entirely, and `status` lists them so an operator can see what is in force. `WriteTimeout` is deliberately not set: clone, archives, LFS objects and site files are streamed, so those flows are bounded where they are produced.
server/routes.go +6
| @@ -191,6 +191,12 @@ func (s *Server) repoRoutes(mux *http.ServeMux) { | |||
| 191 | 191 | // gitRoutes are the Git transports. Reads are anonymous and filtered by the same | |
| 192 | 192 | // visibility rule the pages use; writes never arrive here, they come over SSH. | |
| 193 | 193 | func (s *Server) gitRoutes(mux *http.ServeMux) { | |
| 194 | // An instance that only serves internal repositories can turn the anonymous | ||
| 195 | // transport off entirely: the endpoints then do not exist, so there is no | ||
| 196 | // behaviour to reason about rather than a handler that refuses. | ||
| 197 | if !s.Cfg.GitHTTP { | ||
| 198 | return | ||
| 199 | } | ||
| 194 | 200 | // Registered without a method so git's POSTs reach the proxy. | |
| 195 | 201 | mux.Handle("/git/", s.Proxy) | |
| 196 | 202 | // LFS reads share the same read rule and the same URLs as clone; uploads are | |