git
The git door. Plain git clients use it; no Pando client is needed.
GET /{owner}/{monorepo}/{repo}.git/info/refs?service=git-upload-pack
GET /{owner}/{monorepo}/{repo}.git/info/refs?service=git-receive-pack
POST /{owner}/{monorepo}/{repo}.git/git-upload-pack
POST /{owner}/{monorepo}/{repo}.git/git-receive-pack
A plain repo drops the repo segment: /{owner}/{name}.git/.... The
other shape answers 404 saying which one fits. An old owner/name
(after a rename or a transfer) still works.
Credentials: HTTP Basic with the user's credential as the password
(any username; this is what pando credential, the git credential
helper, supplies), or Authorization: Bearer <credential>. Without
credentials the door answers 401 with WWW-Authenticate: Basic, so a
credential helper is asked.
Protocol v2 object-info (sizes without downloading): Artifacts does
not offer it, so the door adds object-info to the v2 advertisement and
answers command=object-info itself, in git's own reply format
(size, then <oid> <size> per object; an unknown object gets
<oid> with no size). Sizes come from a per-repo index, filled on
first ask and kept forever. Every other v2 command goes to Artifacts
unchanged.
Clone and fetch also accept the read token from a hook delivery
(read_token for a web hook, 30 minutes; PANDO_READ_TOKEN for a
Buildkite build, at least 24 hours so Buildkite's Retry can still
clone), so CI clones from clone_url with no credential of its own.
Only members of the monorepo get through.
Writes per repo: an Artifacts repo takes about two writes at once, so
every write (a push, a branch create or delete, a merge, a meta layer
commit) waits for one of the repo's two write slots, first come first
served. git just waits. A push that waits 120 s gets
remote error: Pando: <repo> is busy with other writes; try the push again.
The ceiling is about 5 to 10 small pushes a second per repo.
Push rule (receive-pack). The door reads the command list before the
pack. If any command updates or deletes the repo's default branch
(refs/heads/main), it refuses the whole push with git's usual
! [remote rejected] main (main is protected; ...) line. Creating main
when it does not exist yet is allowed: that is the first push of
pando init. Main moves only by a merge.
Busy repos. Artifacts runs about 2 receive-packs at once per repo and
answers others "busy". The door holds a push of up to 1 MiB in memory
and sends it again once, after 150 to 400 ms. A push that is still
refused, or is larger, is rejected with
Pando: <repo> is busy with other pushes right now; push again (every
ref busy; push again), and nothing is written: push again. A call to
Artifacts that fails outright is handled the same way: retried once
for a held push, else Pando: <repo> couldn't take this push right now; push again, never a bare HTTP 500.
Push size. One push carries at most 64 MiB of receive-pack request
(67,108,864 bytes), Artifacts' limit. A push whose Content-Length is
over it is refused before anything goes to Artifacts; a streamed one is
cut off before its pack ends, so it cannot land. Either way git gets
Pando: this push is over 64 MiB, the most one push can carry (Artifacts' limit); nothing landed., how to push in steps (for a
first push of main: pando init, which pushes the history in steps on
refs/pando/import and refs/pando/import-files, then deletes them),
and every ref over 64 MiB; push in steps. Nothing is recorded.
Raw files, GET or HEAD, beside the git door:
/{owner}/{monorepo}/projects/{project}/raw/{path}?ref= for a
monorepo's project (the repo at projects/{project}, named
projects-{project}), /{owner}/{name}/raw/{path}?ref= for a plain
repo, and /{owner}/{monorepo}/raw/{path}?v= for a monorepo's own
files (the meta layer; v is a meta layer version).
Members only, by the session cookie or a Bearer credential. Served so
nothing runs: Content-Security-Policy: sandbox, nosniff, images as
images, everything else as text/plain (HTML and SVG included) or,
with a NUL in its first 8,000 bytes, application/octet-stream.
ETag is the content's hash (the git blob's; a large meta file's
SHA-256). By branch, or a meta file now: private, no-cache (a repeat
is a 304); by a 40-character sha or a v: private, max-age=31536000, immutable.
The door records each pushed branch's head and, on its first push, its
author (the user). Then it delivers the branch.opened and push
hooks.