Languages: Français · English
How gitfed works
This document explains gitfed's central mechanism: how two instances that
have never met can let their users collaborate without a shared account
ever existing between them. For the bigger picture (files, code,
deployment), see the README; for the detail of each Go
package, see ARCHITECTURE.en.md; for the practical
how-to (setting up a real federated collaboration step by step), see
../FEDERATION.md (French).
1. The problem this solves
On GitHub or GitLab, collaborating with someone assumes you both have an account on the same platform, or that one of you migrates. gitfed starts from a different premise, closer to email or ActivityPub: each person has an account on exactly one instance — their own — and that instance can prove their identity to any other instance that agrees to trust it.
Concretely: alice has an account on chez-moi.fr. Bob has an account on
ailleurs.net. Bob can push code to one of alice's repos without ever
creating an account with her — as long as alice's instance has chosen to
trust Bob's instance.
2. Identity: a certificate instead of a shared password
Every gitfed instance generates its own certificate authority when it's created (an ed25519 key pair, stored on the data volume). That's the foundation the whole model rests on:
- A local user registers an SSH public key with their instance (via
gitfed-tuifor the very first account, or on their own afterward underSettings → SSH keys). - When they need one, they ask their instance for a certificate
(
ssh git@instance gitfed-cert, or via thegitfed-renew-certtool on a scheduled task). The instance checks that the key really belongs to them, then signs an SSH certificate in OpenSSH format. - That certificate embeds a principal —
bob@ailleurs.net, never a bare username — and a short validity window, 24 hours by default. - When Bob connects to alice's instance, he presents this certificate instead of his bare key. Alice's instance checks two things: that the certificate's signature matches an authority it trusts, and that the certificate hasn't been revoked (§6).
Neither instance needs to contact the other directly for this check — the signature is enough, much like a passport doesn't need a phone call to the issuing country to be checked at a border, as long as the border knows the issuing authority's public key.
3. Trust between instances: the trust store
Trusting an authority is something that has to be built. The first time
alice's instance encounters the domain ailleurs.net (typically because
alice granted bob@ailleurs.net access to one of her repos), it triggers a
federated discovery:
- It fetches
https://ailleurs.net/.well-known/gitfed.json, a public document containing that instance's certificate authority's public key. - It checks that the document is consistent (the declared domain matches,
a key is present) and that the request doesn't point at an internal or
private address (anti-SSRF protection: IP literals,
127.0.0.0/8,10.0.0.0/8,169.254.0.0/16/cloud metadata, etc. are all refused, including after DNS resolution). - Depending on the policy configured on alice's instance:
- whitelist (default) — the domain is recorded as pending; an
administrator has to explicitly approve it under
Admin → Trust storebefore any access is granted. - auto-trust (TOFU — "trust on first use") — the domain is approved immediately on first discovery, to enable only if you're comfortable with that level of risk.
- whitelist (default) — the domain is recorded as pending; an
administrator has to explicitly approve it under
- Discovery is capped at 10 new domains per minute for the whole instance, to keep a compromised account from using it as a large-scale network probe.
Once a domain is approved, verifying a certificate that comes from it is
entirely local: no network request is repeated on every git push.
4. Authorization: who can do what on which repo
Federated identity says who you are; it says nothing about what you're allowed to do. That's the job of the ACL model, entirely local to each repo:
- Every repo has an owner (always admin) and, optionally, collaborators, each with an explicit role: read, write, or admin.
- A repo is also public or private. A public repo grants read access to any authenticated principal, from any trusted instance, without needing to be added as a collaborator. Write, on the other hand, is never implicit — even on a public repo, pushing code requires an explicit role.
- Granting access to a principal on a domain the instance doesn't know yet is exactly what triggers the federated discovery described in §3.
5. The full cycle, step by step
Back to the example: alice wants to give Bob write access to
alice/mon-projet.
- On alice's instance — alice goes into the repo's settings and grants
the write role to
bob@ailleurs.net. - If
ailleurs.netis a domain alice's instance doesn't know yet, it triggers discovery (§3) and the domain stays pending until an admin approves it. - On Bob's instance — Bob asks his own instance for a certificate
(
gitfed-certor automatic renewal). His instance signs a certificate carrying the principalbob@ailleurs.net. - Bob runs
git push ssh://git@chez-moi.fr:2222/alice/mon-projet.git, authenticating with his certificate. - Alice's instance checks the certificate's signature against the
authority key it approved for
ailleurs.net, checks it hasn't been revoked, then checks in its local ACL thatbob@ailleurs.netreally has the write role onalice/mon-projet. - If everything checks out,
git-receive-packruns normally, exactly as it would for a local user.
At no point did Bob need an account, a password, or a registered key on alice's side.
6. Expiry and revocation
A 24h certificate lingering after an account is deleted is, in theory, a residual access path. gitfed handles that with two complementary mechanisms:
- The TTL is short (24h by default, configurable) — the exposure window of a compromised key is bounded even without any administrator action.
- Revocation is immediate. Deleting a user or removing one of their SSH keys records the corresponding revocation (by principal and/or by key fingerprint); every SSH authentication checks this list before accepting a certificate, even one that's still cryptographically valid.
7. What is not federated
To be clear about the model's limits: a repo lives on exactly one instance. There's no replication, no automatic mirroring between instances. Federation is only about identity — who's allowed to push or read — never about the data itself. If alice's instance goes down, her repo isn't available anywhere else unless it was cloned elsewhere first.
8. Special case: cloning a public repo with no account
Everything above describes authenticated access — required for any private repo, and for any write, even to a public one. But a public repo can also be cloned over HTTPS, with no certificate, no SSH key, no account at all:
git clone https://chez-moi.fr/alice/mon-projet.git
This is strictly a read shortcut, not a second authentication path: no
write is possible this way (there is no git-receive-pack route over
HTTP, literally none), and a repo that goes back to private instantly
stops being reachable this way. See ARCHITECTURE.en.md
§7 for the implementation detail.
9. Special case: merging a branch from the web
Merge requests let a write collaborator merge one branch into another from
the web UI — a "write" that doesn't go over SSH, which sounds like a
second exception to §2's identity model. It isn't one: the browser never
sends git data, it only tells the server to combine two branches it
already has, and every commit either branch points at only got into the
repo through a real SSH-authenticated push in the first place. Access is
gated by the exact same write-role check a git push already goes
through — the web button grants no capability a write collaborator
couldn't already reach by cloning, merging locally, and pushing back. See
ARCHITECTURE.en.md §8 for how the merge itself is
isolated from a branch's real state (scratch worktree, conflict detection
before any write, compare-and-swap ref update).