krz/gitbay
A CLI-first git forge.
clone: git clone https://gitbay.org/krz/gitbay.git
main: README.org · raw
1#+title: gitbay
2#+author: Christian Cleberg
3
4A CLI-first git forge. One binary, SQLite, and the system =git= — designed
5so the command line is the product and the web UI is a rendering of state
6the CLI already manages. Runs at [[https://gitbay.org]].
7
8* Design
9
10SSH is the API. The server authenticates by public key, then dispatches the
11requested command: =git-upload-pack= / =git-receive-pack= stream the git
12transport, anything else is a control command. The control plane is fully
13usable from stock OpenSSH with no client installed:
14
15#+begin_src sh
16ssh git@gitbay.org repo create you/project --private
17ssh git@gitbay.org issue create you/project --title "bug" --file - < body.md
18ssh git@gitbay.org repo log you/project --json
19#+end_src
20
21The =gitbay= CLI is ergonomics on top — instance profiles, repo inference
22from the origin remote, =$EDITOR= for long text — never a requirement. A
23registry test enforces that every command stays reachable over bare ssh.
24
25Properties that follow from the design:
26
27- pushing is SSH-only. HTTPS and =git://= serve anonymous reads of public
28 repositories; a push over HTTPS is answered with a pkt-line ERR that
29 every git version prints as =remote error:= — no credential prompt,
30 ever. Private repositories answer 404/not-found identically to
31 nonexistent ones on every surface.
32- commit signatures (OpenPGP and SSHSIG) are verified against registered
33 keys and verified emails, with six distinct states — =verified=,
34 =signed_unknown_key=, =signed_email_mismatch=, =signed_key_expired=,
35 =signed_key_revoked=, =bad_signature=, =unsigned= — cached and
36 invalidated by a global key epoch, so registering a key retroactively
37 verifies old commits.
38- there is no server signing key. Server-created commits (web edits,
39 merge/squash/rebase commits) display honestly as unsigned, and branches
40 with =require_signed_commits= accept only fast-forward merges of
41 verified commits — enforced at push time and merge time.
42- the web UI is server-rendered with no JavaScript required. In
43 =view_only= mode the mutating routes are never registered on the mux;
44 browser sessions, where enabled, are minted over SSH (=web login=) —
45 there are no passwords.
46
47* Features
48
49- repositories with per-branch protection, forks, and organizations
50 (shared owner namespace, membership-derived access)
51- issues and merge requests (fast-forward, merge-commit, squash, rebase)
52 entirely over ssh, with reviews that go stale on force-push
53- merge request heads are fetched /into/ the target repository, so an MR
54 survives deletion of its source fork
55- =repo import= mirrors from any http(s)/git URL, tokens via stdin only
56- registration modes: =closed= (admin creates users), =invite=, =open=
57 with SMTP email verification
58- signed outbound webhooks with retries, dead-lettering, and SSRF
59 guarding; a JSON API (=POST /api/v1/cmd=) fronting the same command
60 registry, with bearer tokens mintable only over SSH
61- built-in ACME (Let's Encrypt) TLS; =admin backup= produces one
62 restore-tested archive (database snapshot first, then repositories)
63
64* Server quickstart
65
66#+begin_src sh
67# /etc/gitbay/config.toml
68[server]
69root = "/var/lib/gitbay"
70site_url = "https://forge.example.org"
71
72[http]
73acme_email = "you@example.org"
74#+end_src
75
76#+begin_src sh
77gitbayd --config /etc/gitbay/config.toml check-config
78gitbayd --config /etc/gitbay/config.toml admin user create you \
79 --key ~/.ssh/id_ed25519.pub --email you@example.org --verified --admin
80gitbayd --config /etc/gitbay/config.toml serve
81#+end_src
82
83The embedded SSH listener takes port 22 (move the host sshd, or set
84=ssh.mode = "system"= to run under it via =AuthorizedKeysCommand=). See
85=deploy/= for a cloud-init file, hardened systemd unit, and nightly
86backup timer.
87
88* Client quickstart
89
90#+begin_src sh
91gitbay remote add myforge forge.example.org --default
92gitbay auth whoami
93gitbay repo create you/project
94gitbay repo clone you/project && cd project
95gitbay issue create --title "first issue" # repo inferred from origin
96gitbay mr checkout 4 # fetches refs/merge-requests/4/head
97#+end_src
98
99Every read command takes =--json=; stdout is data, stderr is messages;
100exit codes are stable (0 ok, 2 usage, 3 not found, 4 denied). Man pages
101via =gitbay man=, completions via =gitbay completion <shell>=.
102
103* Documentation
104
105- [[file:docs/users.org][user guide]] — accounts, keys, verified commits, repos, issues, MRs, scripting
106- [[file:docs/admin.org][admin guide]] — install, full configuration reference, backup/restore, upgrades
107- [[file:docs/api.org][API and webhooks]] — the JSON API contract, tokens, webhook payloads and HMAC
108
109* Development
110
111#+begin_src sh
112go build ./...
113go test ./... # e2e drives real git, ssh, sshd, and gpg binaries
114#+end_src
115
116Layout: =cmd/gitbay= (CLI), =cmd/gitbayd= (daemon, hooks, admin),
117=internal/control= (command registry — the single source of truth fronted
118by ssh and the JSON API), =internal/sshd= / =httpd= / =gitd= (transports),
119=internal/sig= (signature verification), =internal/policy= (access rules),
120=internal/store= (SQLite, migrations), =e2e/= (integration tests).
121
122* License
123
1240BSD.