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
internal/lfs/pointer_real_test.go +30
| @@ -0,0 +1,30 @@ | |||
| 1 | package lfs | ||
| 2 | |||
| 3 | import "testing" | ||
| 4 | |||
| 5 | // TestParsePointerFromARealClient pins the exact bytes git-lfs writes. An earlier | ||
| 6 | // version of this parser accepted a first line without the `version ` key and the | ||
| 7 | // hook silently stopped recognising pointers — the whole gate went quiet, and only | ||
| 8 | // the end-to-end test noticed. | ||
| 9 | func TestParsePointerFromARealClient(t *testing.T) { | ||
| 10 | text := "version https://git-lfs.github.com/spec/v1\n" + | ||
| 11 | "oid sha256:6c82914b2d961ffcbbe375c41515e962207893b7207bfd293d37e5cf58bb752b\n" + | ||
| 12 | "size 30\n" | ||
| 13 | if len(text) != 127 { | ||
| 14 | t.Fatalf("fixture is %d bytes; the client writes a 127-byte pointer for these fields", len(text)) | ||
| 15 | } | ||
| 16 | p, ok := ParsePointer([]byte(text)) | ||
| 17 | if !ok { | ||
| 18 | t.Fatalf("did not parse the bytes a client actually writes:\n%s", text) | ||
| 19 | } | ||
| 20 | if p.OID != "6c82914b2d961ffcbbe375c41515e962207893b7207bfd293d37e5cf58bb752b" || p.Size != 30 { | ||
| 21 | t.Fatalf("parsed %+v", p) | ||
| 22 | } | ||
| 23 | // A url with no `version` key is a filter line, not a pointer. | ||
| 24 | bare := "https://git-lfs.github.com/spec/v1\n" + | ||
| 25 | "oid sha256:6c82914b2d961ffcbbe375c41515e962207893b7207bfd293d37e5cf58bb752b\n" + | ||
| 26 | "size 30\n" | ||
| 27 | if _, ok := ParsePointer([]byte(bare)); ok { | ||
| 28 | t.Fatal("a bare url on the first line was accepted as a pointer") | ||
| 29 | } | ||
| 30 | } | ||