vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Phase 1: a working git remote with access control
653e0cfc227c992e5b26ea10057aa0b424b6ce4f · Keenan Nemetz · 18d ago · parent c5626f1b
Phase 1: a working git remote with access control Vole is now a functioning forge foundation: one CGO-free binary that serves real git over smart HTTP and enforces per-repo policy in pre-receive. What is in: - internal/transport drives `git http-backend` as a CGI subprocess. Chunked uploads are spooled to learn CONTENT_LENGTH (git's default client config produces them), spool files are cleaned on error and abort, and a janitor sweeps anything a crash left behind. Pushes are capped by size and serialised behind a semaphore, because Phase 0 measured 1.13 GB of git RSS for a single 1 GiB push. - internal/acl stores roles on refs/vole/acl inside each repository, so access rules travel with a clone. One evaluation function is shared by the hook and the web layer. - internal/hook enforces policy in pre-receive: authentication, write role, protected refs, per-blob size limits, and a refusal to accept pushes to refs/vole/* - without that last check a writer could push their own acl.json and grant themselves admin. - internal/auth holds users, personal access tokens and web sessions in SQLite. Passwords use PBKDF2-SHA256; tokens are 256-bit random values and are stored as SHA-256 hashes, since there is no low-entropy secret to grind. - internal/index is the derived read model, rebuildable from disk and refs. - internal/repo owns the bare-repo store and the metadata ref CAS helper. - internal/web is the browse surface: repo list, tree, blob, raw, history, login, and per-repo settings for access rules, rename and delete. - internal/signing creates the instance ed25519 key at first boot for the Phase 7 work. Every Phase 1 exit criterion has a test that would fail if it regressed: clone/push against a real listener, read-only and anonymous rejection with the ref proven unmoved, rebuild-from-refs compared against the actual acl ref, a spool file proven absent after an aborted chunked upload, and two pushes completing through a single-slot semaphore. scripts/ci.sh runs gofmt, vet, build, a markdown link check and the race-enabled suite. Verified by hand as well: a clean `vole init` -> user -> token -> push -> clone cycle, web login and browse, and a 256 MiB chunked push killed mid-flight leaving no ref, no spool file and no orphaned git processes.
README.md +47
| @@ -16,3 +16,50 @@ Vole turns a git repo into a fully functional software forge. | |||
| 16 | 16 | ||
| 17 | 17 | See [docs/roadmap.md](docs/roadmap.md) for the phased implementation plan. | |
| 18 | 18 | ||
| 19 | ## Status | ||
| 20 | |||
| 21 | **Phase 1 is implemented.** Vole is a working git remote with access control. | ||
| 22 | |||
| 23 | Working today: | ||
| 24 | |||
| 25 | - Smart HTTP clone / push / fetch with a stock `git` client | ||
| 26 | - Users, personal access tokens, and web sessions | ||
| 27 | - Per-repo roles (read / write / admin) stored *in the repository* at | ||
| 28 | `refs/vole/acl`, so access rules travel with a clone | ||
| 29 | - Policy enforced in `pre-receive`, so a rejected push moves no refs at all | ||
| 30 | - Protected refs, per-blob size limits, push size cap, push concurrency limit | ||
| 31 | - Repo create / rename / delete, and a web browser for files and history | ||
| 32 | - A derived SQLite index that can be deleted and rebuilt from the repos | ||
| 33 | - An instance ed25519 key generated at first boot (used for metadata signing in | ||
| 34 | Phase 7) | ||
| 35 | |||
| 36 | Not yet: issues, change requests, CI, LFS, static sites, signature verification. | ||
| 37 | |||
| 38 | ## Try it | ||
| 39 | |||
| 40 | ```sh | ||
| 41 | go build -o vole ./cmd/vole | ||
| 42 | |||
| 43 | ./vole init -dir . # writes vole.toml | ||
| 44 | VOLE_PASSWORD=correct-horse ./vole user create you | ||
| 45 | ./vole repo create demo -owner you | ||
| 46 | ./vole serve # http://127.0.0.1:8080 | ||
| 47 | ``` | ||
| 48 | |||
| 49 | Create a token to use as your git password: | ||
| 50 | |||
| 51 | ```sh | ||
| 52 | ./vole user token you -scope write | ||
| 53 | git clone http://you:<token>@127.0.0.1:8080/git/demo.git | ||
| 54 | ``` | ||
| 55 | |||
| 56 | A single-user instance treats that user as the instance admin, so a fresh | ||
| 57 | install is usable without editing config. On a multi-user instance, list | ||
| 58 | admins under `admin_users` in `vole.toml`. | ||
| 59 | |||
| 60 | Run everything before pushing: | ||
| 61 | |||
| 62 | ```sh | ||
| 63 | ./scripts/ci.sh | ||
| 64 | ``` | ||
| 65 | |||