ref:main

feat: git lfs (pointer, store, batch API, transfer, locks) #38

closed Opened by cole.christensen@gmail.com

Links

No links yet.

Add full Git LFS support: pointer parsing, object storage abstraction with FS/S3/Memory backends parallel to the existing Storage behaviour, Batch API, object transfer, locks API, and SHA256 verification. Exposed as pure request/response modules consistent with the existing UploadPack/ReceivePack style (no HTTP server in-tree).

Scope

  • Pointer blob parser/emitter (spec v1) with strict validation
  • ExGitObjectstore.Lfs.Store behaviour, keyed by SHA256
  • Backends: Lfs.Store.Filesystem, Lfs.Store.S3, Lfs.Store.Memory — parity with existing Storage.* (same config/prefix style)
  • Batch API (POST /objects/batch) — upload/download action generation, presigned-URL mode for S3 (direct-to-backend), streamed mode for Filesystem/Memory
  • Object transfer (GET/PUT /objects/:oid, POST /objects/:oid/verify) — streaming, SHA256 verified on PUT
  • Locks API v1 (POST /locks, POST /locks/:id/unlock, GET /locks, POST /locks/verify)
  • Auth hook pattern consistent with existing protocol modules (caller enforces; library provides request context)
  • Telemetry spans parallel to existing fetch/push spans

Acceptance Criteria

  • Pointer parser round-trips (parse then emit == input) for all spec-compliant pointer blobs
  • Parser rejects malformed pointers (wrong version, non-sha256 OID, non-integer size, unknown keys in non-canonical position)
  • Lfs.Store behaviour defined; three backends implement it with passing shared conformance tests
  • Batch API returns spec-compliant JSON for upload, download, verify operations
  • Transfer handlers stream multi-GB blobs without loading into memory (verified by test with >RAM-safe-size stream)
  • SHA256 mismatch on PUT returns 422 and does not persist
  • Locks API passes basic create/list/unlock/verify round-trips
  • S3 backend: batch returns presigned URLs; Filesystem/Memory: batch returns library-served URLs
  • Auth hook invoked per request; rejection surfaces as 401/403
  • Telemetry events emitted: [:ex_git_objectstore, :lfs, :batch], [:transfer], [:lock]
  • CHANGELOG updated in feature branch before PR
  • Requirements defined via anvil requirement and anvil requirement status passes

Non-goals

  • Running the HTTP server itself (library exposes pure request/response functions)
  • LFS transfer adapters beyond basic (e.g., lfs-standalone-file, custom transfer agents)
  • Migration tooling (git lfs migrate)