Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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