Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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 5: LFS objects, over SSH for writes and the proxy for reads

64ac5071a173e4e9ce8bc8d7170f9b0411bee52a · Keenan Nemetz · 17d ago · parent 35eaeccf

Phase 5: LFS objects, over SSH for writes and the proxy for reads

Large files leave the git object database and land in one content-addressed
store per instance. Reads are anonymous like clone; writes ride the SSH key
that already authenticates the push, so no token exists anywhere.

- internal/lfs: sha256-addressed store that verifies content and size before
  an object becomes visible; parser for the pointer format a client writes
- HTTP: POST .../info/lfs/objects/batch for downloads, GET .../objects/<oid>
  with the object id as ETag; upload over HTTP is refused and names SSH
- SSH: git-lfs-transfer speaking the pure SSH protocol (pkt-line), so
  `git lfs push` needs nothing but the key at the handshake
- pre-receive: a pointer whose object is missing, or whose size disagrees
  with the stored object, fails the push that introduced it; a binary over
  lfs_warn_bytes is accepted with a `git lfs track` suggestion. Checks run
  before the protected-branch gate, because an admin's approval bypass is
  about review, not about whether the commit can be checked out
- runs: a finished log becomes a content-addressed object in the same write
  that records the status, served at /r/<repo>/runs/<id>/log
- vole gc [--dry-run] [--grace]: marks pointer targets from every ref in
  every repository plus archived logs, sweeps the rest. Mark-and-sweep
  rather than reference counts: a counter that is one too low deletes an
  artifact, a walk over the refs cannot be wrong about what is reachable

README.md +45−2

@@ -18,7 +18,7 @@ See [docs/roadmap.md](docs/roadmap.md) for the phased implementation plan.
18 18
19 19 ## Status
20 20
21 **Phase 1 is implemented.** Vole is a working forge: writes go over SSH and are
21 **Phases 1–5 are implemented.** Vole is a working forge: writes go over SSH and are
22 22 authenticated by your key; reads are open.
23 23
24 24 Working today:
@@ -42,12 +42,22 @@ Working today:
42 42 branch, validated at push time and rendered read-only on the web
43 43 - Review as a git artifact: an approval names the exact commit it reviewed, and
44 44 `git push` is the merge, gated by `pre-receive`
45 - CI: workflows in `.vole/workflows/*.yaml`, validated by the push that introduces
46 them. A push queues jobs; `vole runner` leases one over SSH with the same key, runs
47 the shell steps, heartbeats and reports the log. Protected branches can require
48 green checks as well as approvals
49 - LFS: large files stay out of the git object database and live in one
50 content-addressed store per instance. Uploads ride the SSH key
51 (`git-lfs-transfer`); downloads come through the HTTP clone URL, anonymously for a
52 public repository. A pointer whose object is missing fails the push that introduced
53 it, and `vole gc` sweeps what nothing reaches
45 54 - Repo create / rename / delete from the CLI
46 55 - A derived SQLite index that can be deleted and rebuilt from the repos
47 56 - An instance ed25519 key generated at first boot (used for metadata signing in
48 57 Phase 7)
49 58
50 Not yet: change requests, CI, LFS, static sites, signature verification.
59 Not yet: workflow artifact uploads, static site hosting, signature verification, LFS
60 locking.
51 61
52 62 ## Try it
53 63
@@ -170,6 +180,39 @@ admin can, and that is audited). The names in `meta.json` — `author` on an iss
170 180 request — are display fields and carry no authority; the approval path is the only
171 181 name that decides who may land a commit.
172 182
183 ## Large files
184
185 Track a pattern with git-lfs as usual; the only thing that changes is where the bytes
186 go. Vole answers `git-lfs-transfer` on the SSH connection it already trusts, so there
187 is no token to mint and nothing extra to configure:
188
189 ```sh
190 git lfs install # once per machine
191 git lfs track "*.psd"
192 git add .gitattributes logo.psd
193 git commit -m "add the logo" && git push origin main
194
195 git clone http://host/git/demo.git # LFS objects come through the same URL
196 ```
197
198 Repositories keep the pointer; Vole keeps the object, once, however many repositories
199 use it. Configure the sizes in `vole.toml`:
200
201 ```toml
202 lfs_object_max_bytes = 2147483648 # one object; larger is refused, not spooled
203 lfs_warn_bytes = 5242880 # a binary this big committed raw gets a warning
204 ```
205
206 A push that lands a binary over `lfs_warn_bytes` without LFS is accepted with the
207 `git lfs track` command to fix it; a push that commits a pointer whose object was never
208 uploaded is refused, because nobody could check that commit out. Objects are swept
209 only when nothing reaches them:
210
211 ```sh
212 vole gc --dry-run # mark from every ref, report what is unreachable
213 vole gc # remove it (objects younger than --grace stay)
214 ```
215
173 216 ## Backup
174 217
175 218 Two things, and both are small: