krz/gitbay
A CLI-first git forge.
clone: git clone https://gitbay.org/krz/gitbay.git
main:
| 100644 | .gitignore | 29 |
| 100644 | LICENSE | 607 |
| 100644 | README.org | 5161 |
| 040000 | cmd/ | |
| 040000 | deploy/ | |
| 040000 | docs/ | |
| 040000 | e2e/ | |
| 100644 | go.mod | 1379 |
| 100644 | go.sum | 8299 |
| 040000 | internal/ |
gitbay
A CLI-first git forge. One binary, SQLite, and the system git — designed
so the command line is the product and the web UI is a rendering of state
the CLI already manages. Runs at https://gitbay.org.
Design
SSH is the API. The server authenticates by public key, then dispatches the
requested command: git-upload-pack / git-receive-pack stream the git
transport, anything else is a control command. The control plane is fully
usable from stock OpenSSH with no client installed:
ssh git@gitbay.org repo create you/project --private ssh git@gitbay.org issue create you/project --title "bug" --file - < body.md ssh git@gitbay.org repo log you/project --json
The gitbay CLI is ergonomics on top — instance profiles, repo inference
from the origin remote, $EDITOR for long text — never a requirement. A
registry test enforces that every command stays reachable over bare ssh.
Properties that follow from the design:
- pushing is SSH-only. HTTPS and
git://serve anonymous reads of public repositories; a push over HTTPS is answered with a pkt-line ERR that every git version prints asremote error:— no credential prompt, ever. Private repositories answer 404/not-found identically to nonexistent ones on every surface. - commit signatures (OpenPGP and SSHSIG) are verified against registered
keys and verified emails, with six distinct states —
verified,signed_unknown_key,signed_email_mismatch,signed_key_expired,signed_key_revoked,bad_signature,unsigned— cached and invalidated by a global key epoch, so registering a key retroactively verifies old commits. - there is no server signing key. Server-created commits (web edits,
merge/squash/rebase commits) display honestly as unsigned, and branches
with
require_signed_commitsaccept only fast-forward merges of verified commits — enforced at push time and merge time. - the web UI is server-rendered with no JavaScript required. In
view_onlymode the mutating routes are never registered on the mux; browser sessions, where enabled, are minted over SSH (web login) — there are no passwords.
Features
- repositories with per-branch protection, forks, and organizations (shared owner namespace, membership-derived access)
- issues and merge requests (fast-forward, merge-commit, squash, rebase) entirely over ssh, with reviews that go stale on force-push
- merge request heads are fetched into the target repository, so an MR survives deletion of its source fork
repo importmirrors from any http(s)/git URL, tokens via stdin only- registration modes:
closed(admin creates users),invite,openwith SMTP email verification - signed outbound webhooks with retries, dead-lettering, and SSRF
guarding; a JSON API (
POST /api/v1/cmd) fronting the same command registry, with bearer tokens mintable only over SSH - built-in ACME (Let's Encrypt) TLS;
admin backupproduces one restore-tested archive (database snapshot first, then repositories)
Server quickstart
# /etc/gitbay/config.toml [server] root = "/var/lib/gitbay" site_url = "https://forge.example.org" [http] acme_email = "you@example.org"
gitbayd --config /etc/gitbay/config.toml check-config
gitbayd --config /etc/gitbay/config.toml admin user create you \
--key ~/.ssh/id_ed25519.pub --email you@example.org --verified --admin
gitbayd --config /etc/gitbay/config.toml serve
The embedded SSH listener takes port 22 (move the host sshd, or set
ssh.mode = "system" to run under it via AuthorizedKeysCommand). See
deploy/ for a cloud-init file, hardened systemd unit, and nightly
backup timer.
Client quickstart
gitbay remote add myforge forge.example.org --default gitbay auth whoami gitbay repo create you/project gitbay repo clone you/project && cd project gitbay issue create --title "first issue" # repo inferred from origin gitbay mr checkout 4 # fetches refs/merge-requests/4/head
Every read command takes --json; stdout is data, stderr is messages;
exit codes are stable (0 ok, 2 usage, 3 not found, 4 denied). Man pages
via gitbay man, completions via gitbay completion <shell>.
Documentation
- user guide — accounts, keys, verified commits, repos, issues, MRs, scripting
- admin guide — install, full configuration reference, backup/restore, upgrades
- API and webhooks — the JSON API contract, tokens, webhook payloads and HMAC
Development
go build ./... go test ./... # e2e drives real git, ssh, sshd, and gpg binaries
Layout: cmd/gitbay (CLI), cmd/gitbayd (daemon, hooks, admin),
internal/control (command registry — the single source of truth fronted
by ssh and the JSON API), internal/sshd / httpd / gitd (transports),
internal/sig (signature verification), internal/policy (access rules),
internal/store (SQLite, migrations), e2e/ (integration tests).
License
0BSD.