packlimit: one limit on pack generation across transports !506

merged merged by cmc on 2026-09-28 23:13 UTC · krz/gitbay:pack-limit into main

Discussion

cmc

One limit on git pack generation across SSH, smart HTTP, git:// and web archives.

  • internal/packlimit: a global cap, a per-principal cap and a bounded queue with a wait. One limiter is built in serve and shared by every transport. [limits] pack_concurrency (3), pack_per_principal (2), pack_queue (32), pack_queue_wait ("60s"); 0 takes the default, a negative value turns that bound off.
  • Principals: user:<id> for SSH and for a tokened or signed-in HTTP request; the client address for anonymous HTTP and git://, an IPv6 client by its /64. Anonymous clients together hold at most pack_concurrency − 1 slots, so an account can take the last one when it is free.
  • upload-pack, upload-archive and web archives take a slot after every access check; pushes and ls-refs never do. A clone is killed when its client leaves (SSH), its key is revoked, or nothing has been written to the client for two minutes; upload-pack runs with uploadpack.keepAlive=5. The slot is released only after git has exited.
  • Busy: SSH prints that the server is at its clone limit and exits 1; HTTP answers 503 with Retry-After: 30; git:// sends an ERR packet. Refusals are logged at most once a minute per transport, without addresses.
  • Hook-side refusals are audited: a hook request without a valid push token or from another uid as refused hook, policy denials in pre-receive as refused push (#275).
  • deploy/clonebench.sh; Admin, Performance, Threat-Model, Architecture 09/10; CHANGELOG. ssh.mode = "system" has no limiter (Known-Gaps).

Stacked on !505 (builds-badge-org).

Closes #262