Authentication
Every request except /health carries a ChirpAuth ID token. amber-git checks
the token, then whether you may reach the repository, before anything else.
Tokens amber-git accepts
| Token | Who holds it | How to get it |
|---|---|---|
| Machine token | An agent or service | The client_credentials grant, from a ChirpAuth client Stackwell has registered with amber-git |
| Person’s token | A person | A ChirpAuth sign-in token issued for amber-git |
Only production ChirpAuth tokens are accepted, and only while they are unexpired. amber-git has no sign-in page of its own; agents, services and scripts use machine tokens:
TOKEN=$(curl -sS https://signin.chirpauth.com/token \
-d grant_type=client_credentials \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET" | jq -r .id_token)
Every ChirpAuth machine client is owned by a person. amber-git sends force-pushes and deletes to the repository’s owner for approval, never to the client’s owner.
Sending the token
Either way works for git and for amber-git’s other routes:
-
Bearer:
Authorization: Bearer <token>. With git:git -c http.extraHeader="Authorization: Bearer $TOKEN" .... -
Basic: the token as the password, with any username. This lets a git credential helper supply it. A helper is a program git runs with
getthat prints the credential:#!/bin/sh # Save as git-credential-amber-git on your PATH, then run: # git config --global credential.https://amber-git.stackwell.tech.helper amber-git [ "$1" = get ] || exit 0 echo username=token echo "password=$(my-command-that-prints-a-fresh-token)"
Without a valid token, amber-git answers 401 with two challenges, so git asks
its credential helper:
HTTP/2 401
www-authenticate: Basic realm="amber-git"
www-authenticate: Bearer
unauthenticated
curl -sS -o /dev/null -w '%{http_code}\n' 'https://amber-git.stackwell.tech/any-repo.git/info/refs?service=git-upload-pack' | grep -Fx 401
Access to a repository
- Closed by default. A repository admits only the people and ChirpAuth
clients Stackwell has granted on it. Anyone else gets
403or404. - A machine client reaches the repositories granted to it and those granted to the person who owns it.
- A read-only client is one Stackwell has registered for reading only, such
as a CI runner. It reaches only the repositories granted to the client
itself, may fetch and use the read routes, and is refused (
403) on every push, including the first step of one.
What each caller may do
| Action | Anyone granted on the repository | Read-only client |
|---|---|---|
| Clone, fetch | Yes | Yes |
| Read files without cloning | Yes | Yes |
| Re-send to the GitHub mirror | Yes | Yes |
| Push new branches, tags and branch fast-forwards | Yes | No (403) |
| Move an existing tag | No (refused for everyone) | No (403) |
| Force-push or delete a branch or tag | Queued for the owner’s approval | No (403) |
| Withdraw a queued force-push or delete | The pusher who queued it, or the repository’s owner as a person | No (it can’t queue anything) |
| Check whether a queued push is still waiting | The same as withdraw | No (it can’t queue anything) |
| Approve or deny a queued force-push or delete | Only the repository’s owner, in Granite | No |
A repository with no recorded owner refuses every force-push and delete outright.