Add README
What the project is, how the certificate-based federation model works, what each binary does, and how to run it both locally and for real (pointing at deploy/k8s/README.md for the full deployment walkthrough).
1 files changed
+160 −0
A
README.md
+160 −0
README.md
@@ -0,0 +1,160 @@
+# gitfed
+
+A self-hosted git server where pushing to someone else's instance doesn't
+mean creating a second account there. Your home instance vouches for you —
+literally, via a short-lived SSH certificate it signs — and any instance
+that trusts your home instance's certificate authority accepts it.
+
+Current version: see [CHANGELOG.md](CHANGELOG.md) (also served at
+`/changelog` in the web UI, next to a `gitfed X.Y.Z` link in the footer).
+
+## What this is (and isn't)
+
+- **Git over SSH only.** No HTTP git protocol, no reimplementation of git
+ itself — gitfed wraps `git-upload-pack`/`git-receive-pack` as
+ subprocesses and lets git do what git does.
+- **Federated identity, not federated data.** A repo lives on exactly one
+ instance; there's no replication or mirroring. Federation is purely
+ about who's allowed to push/pull, carried by certificates instead of
+ per-instance accounts.
+- **Not a GitHub/GitLab clone**, even though the web UI looks like one.
+ The point of the project is the identity model above — everything else
+ (file browser, self-service repos, admin panel) exists to make that
+ model usable day to day, not to compete on feature count.
+
+Full design rationale and the protocol-level detail live in
+[DESIGN.md](DESIGN.md); this file is the practical "what do I actually run"
+version.
+
+## How it works
+
+- Each instance generates its own ed25519 **certificate authority** on
+ first run. A local user with a registered SSH key can ask their own
+ instance for a certificate (`ssh git@host gitfed-cert`, or the
+ `gitfed-renew-cert` helper below); the certificate embeds the principal
+ `<username>@<domain>` and expires in a couple of days by default.
+- To let someone from another instance collaborate on a repo, an admin (or
+ the repo owner) grants their principal a role — `read`, `write`, or
+ `admin`. The first time a given remote domain shows up, the instance
+ fetches `https://<domain>/.well-known/gitfed.json` to learn that
+ instance's CA public key, and either trusts it immediately or holds it
+ **pending** for an admin to approve, depending on the configured trust
+ policy (whitelist by default, auto-trust/TOFU opt-in).
+- Once a domain is trusted, verifying a certificate from it is entirely
+ local — no network call on every SSH connection, no dependency on the
+ remote instance being reachable at push/pull time.
+- Repos can be public (readable by any authenticated principal, from any
+ trusted domain, without an explicit grant) or private (owner and
+ explicitly granted collaborators only). Write access always requires an
+ explicit grant regardless of visibility.
+
+## What's included
+
+- **`gitfed-server`** — the daemon: SSH server (git + cert issuance) and
+ the `/.well-known/gitfed.json` HTTP endpoint.
+- **`gitfed-web`** — the web UI: a public, unauthenticated repo browser
+ (file tree, rendered README/LICENSE, tags, topics) plus, behind a
+ username/password login, self-service (your own keys and repos) and an
+ admin section (users, trust store, audit log) gated by an admin flag on
+ the account. The web login only ever grants access to this UI — git
+ push/pull always goes over SSH with a key or certificate, independently
+ of it.
+- **`gitfed-tui`** — a terminal admin tool that talks to the same store
+ gitfed-web does. It's the way to bootstrap the very first account (there
+ is no self-registration), and works even if the web UI is down, since it
+ can also open the database directly when the server isn't running.
+- **`gitfed-renew-cert`** — a small client-side tool end users run on
+ *their own* machine (e.g. from a cron job or systemd timer) to renew
+ their certificate shortly before it expires.
+
+## Project layout
+
+```
+cmd/
+ gitfed-server/ SSH server + well-known endpoint
+ gitfed-web/ web UI (public browsing + self-service + admin)
+ gitfed-tui/ terminal admin tool
+ gitfed-renew-cert/ client-side certificate renewal helper
+internal/
+ ca/ CA key generation + certificate signing
+ ssh/ SSH server, auth, ACL enforcement, git exec
+ federation/ .well-known discovery, trust store
+ acl/ repo access-control checks
+ gitexec/ git-upload-pack/receive-pack + tree/blob reads
+ store/ bbolt-backed persistence
+ admin/ the Ops interface both TUI and web drive
+ adminrpc/ lets gitfed-web talk to a *running* server
+ over a Unix socket instead of racing it for
+ the store's exclusive file lock
+ opsconnect/ picks live-socket vs. direct-store mode
+deploy/
+ docker/Dockerfile multi-stage build for server/web/tui
+ k8s/ manifests + deployment README (k3s/Traefik/
+ cert-manager)
+ update.sh version bump + build + deploy in one command
+DESIGN.md architecture and protocol rationale
+CHANGELOG.md version history
+```
+
+## Running it locally
+
+```sh
+go build -o bin/gitfed-server ./cmd/gitfed-server
+go build -o bin/gitfed-web ./cmd/gitfed-web
+go build -o bin/gitfed-tui ./cmd/gitfed-tui
+
+./bin/gitfed-server -init localhost -data-dir data -config gitfed.json
+# edit gitfed.json if you want different ports (defaults: ssh :2222, http :8443)
+./bin/gitfed-server -config gitfed.json &
+
+./bin/gitfed-tui -config gitfed.json
+# Users -> a (add user): username, your SSH public key, a password, admin: y
+
+./bin/gitfed-web -config gitfed.json &
+# open http://localhost:8088, log in with what you just created
+```
+
+Cloning/pushing always goes over SSH:
+
+```sh
+git clone ssh://git@localhost:2222/<user>/<repo>
+```
+
+## Deploying for real
+
+The setup this project actually runs on is a single-node k3s VPS with
+Traefik and cert-manager already handling another app (specifically,
+[ess-helm](https://github.com/element-hq/ess-helm)) — gitfed reuses both
+rather than standing up its own ingress/TLS. Full walkthrough, including
+why the deployment is shaped the way it is (bbolt's single-writer lock,
+why there are two containers in one pod, why the SSH port can't be 22),
+is in **[deploy/k8s/README.md](deploy/k8s/README.md)**.
+
+Short version:
+
+```sh
+docker build -f deploy/docker/Dockerfile -t gitfed:latest .
+docker save gitfed:latest -o gitfed.tar # then import into your cluster's runtime
+kubectl apply -f deploy/k8s/ # namespace, configmap, pvc, deployment, service, ingress
+```
+
+For every update after the first, use `deploy/update.sh` instead of
+repeating that by hand — it bumps `VERSION`, builds and imports an image
+tagged with the actual version (not just `:latest`), points the deployment
+at it, applies, and commits:
+
+```sh
+# add a "## X.Y.Z" section to CHANGELOG.md describing the change first
+deploy/update.sh # patch bump
+deploy/update.sh minor # or: major, or an explicit X.Y.Z
+```
+
+## Backups
+
+Everything that matters lives on one persistent volume: the database
+(users, repos, ACLs, sessions, trust store, audit log), the instance's CA
+key, the SSH host key, and the bare repos themselves. Losing the CA key
+specifically invalidates every certificate this instance has ever issued
+and breaks every federated trust relationship pointing at it — there's no
+recovery short of everyone re-establishing trust from scratch. Back up the
+whole volume, not just the git data.