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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software: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 · 18d 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/hook/hook_test.go +12−7

@@ -56,15 +56,20 @@ func newFixture(t *testing.T, blob string) *fixture {
56 56
57 57 func (f *fixture) run(actor, ref string, maxBlob int64) (int, string) {
58 58 f.t.Helper()
59 var out bytes.Buffer
60 code := PreReceive(Config{
61 RepoDir: f.m.Dir,
59 return f.runWith(Config{
62 60 Actor: actor,
63 61 MaxBlobBytes: maxBlob,
64 In: strings.NewReader(gitx.ZeroSHA + " " + f.head + " " + ref + "\n"),
65 Out: &out,
66 })
67 return code, out.String()
62 }, ref)
63 }
64
65 // runWith runs pre-receive with a full config, so LFS rules can be exercised.
66 func (f *fixture) runWith(cfg Config, ref string) (int, string) {
67 f.t.Helper()
68 cfg.RepoDir = f.m.Dir
69 var out bytes.Buffer
70 cfg.In = strings.NewReader(gitx.ZeroSHA + " " + f.head + " " + ref + "\n")
71 cfg.Out = &out
72 return PreReceive(cfg), out.String()
68 73 }
69 74
70 75 func (f *fixture) setACL(mut func(*acl.ACL)) {