Commit f591848f8a
Verified · cmc
Layout: unified · split
LICENSE added +10
| @@ -0,0 +1,10 @@ | |||
| 1 | Permission to use, copy, modify, and/or distribute this software for any | ||
| 2 | purpose with or without fee is hereby granted. | ||
| 3 | |||
| 4 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 5 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 6 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 7 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 8 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 9 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 10 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
README.org added +118
| @@ -0,0 +1,118 @@ | |||
| 1 | #+title: gitbay | ||
| 2 | #+author: Christian Cleberg | ||
| 3 | |||
| 4 | A CLI-first git forge. One binary, SQLite, and the system =git= — designed | ||
| 5 | so the command line is the product and the web UI is a rendering of state | ||
| 6 | the CLI already manages. Runs at [[https://gitbay.org]]. | ||
| 7 | |||
| 8 | * Design | ||
| 9 | |||
| 10 | SSH is the API. The server authenticates by public key, then dispatches the | ||
| 11 | requested command: =git-upload-pack= / =git-receive-pack= stream the git | ||
| 12 | transport, anything else is a control command. The control plane is fully | ||
| 13 | usable from stock OpenSSH with no client installed: | ||
| 14 | |||
| 15 | #+begin_src sh | ||
| 16 | ssh git@gitbay.org repo create you/project --private | ||
| 17 | ssh git@gitbay.org issue create you/project --title "bug" --file - < body.md | ||
| 18 | ssh git@gitbay.org repo log you/project --json | ||
| 19 | #+end_src | ||
| 20 | |||
| 21 | The =gitbay= CLI is ergonomics on top — instance profiles, repo inference | ||
| 22 | from the origin remote, =$EDITOR= for long text — never a requirement. A | ||
| 23 | registry test enforces that every command stays reachable over bare ssh. | ||
| 24 | |||
| 25 | Properties 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] | ||
| 69 | root = "/var/lib/gitbay" | ||
| 70 | site_url = "https://forge.example.org" | ||
| 71 | |||
| 72 | [http] | ||
| 73 | acme_email = "you@example.org" | ||
| 74 | #+end_src | ||
| 75 | |||
| 76 | #+begin_src sh | ||
| 77 | gitbayd --config /etc/gitbay/config.toml check-config | ||
| 78 | gitbayd --config /etc/gitbay/config.toml admin user create you \ | ||
| 79 | --key ~/.ssh/id_ed25519.pub --email you@example.org --verified --admin | ||
| 80 | gitbayd --config /etc/gitbay/config.toml serve | ||
| 81 | #+end_src | ||
| 82 | |||
| 83 | The 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 | ||
| 86 | backup timer. | ||
| 87 | |||
| 88 | * Client quickstart | ||
| 89 | |||
| 90 | #+begin_src sh | ||
| 91 | gitbay remote add myforge forge.example.org --default | ||
| 92 | gitbay auth whoami | ||
| 93 | gitbay repo create you/project | ||
| 94 | gitbay repo clone you/project && cd project | ||
| 95 | gitbay issue create --title "first issue" # repo inferred from origin | ||
| 96 | gitbay mr checkout 4 # fetches refs/merge-requests/4/head | ||
| 97 | #+end_src | ||
| 98 | |||
| 99 | Every read command takes =--json=; stdout is data, stderr is messages; | ||
| 100 | exit codes are stable (0 ok, 2 usage, 3 not found, 4 denied). Man pages | ||
| 101 | via =gitbay man=, completions via =gitbay completion <shell>=. | ||
| 102 | |||
| 103 | * Development | ||
| 104 | |||
| 105 | #+begin_src sh | ||
| 106 | go build ./... | ||
| 107 | go test ./... # e2e drives real git, ssh, sshd, and gpg binaries | ||
| 108 | #+end_src | ||
| 109 | |||
| 110 | Layout: =cmd/gitbay= (CLI), =cmd/gitbayd= (daemon, hooks, admin), | ||
| 111 | =internal/control= (command registry — the single source of truth fronted | ||
| 112 | by ssh and the JSON API), =internal/sshd= / =httpd= / =gitd= (transports), | ||
| 113 | =internal/sig= (signature verification), =internal/policy= (access rules), | ||
| 114 | =internal/store= (SQLite, migrations), =e2e/= (integration tests). | ||
| 115 | |||
| 116 | * License | ||
| 117 | |||
| 118 | 0BSD. | ||