feat(oci): add OCI format package (manifests, blobs, uploads, tags) (MR 4/5)

Why

Layer 3 (OCI format) of the S12 OCI-local stack. The internal/format/oci package: the format-specific handling for the 16 OCI Distribution Spec endpoints.

This MR cannot land before MR-3 because:

  • Wiring (cmd/registry, router) imports the OCI handlers.
  • Format integrates the layers below: datastore (manifest/tag state), CAS (blob storage), namespace (authorization scope), auth (request identity).

Issue: #19 (closed) Spec: S12 (already merged via !48 (merged))

Stack and merge order

# MR Branch Targets Blocks
0 !141 (merged) 19-oci-boilerplate main !124 (closed)
1 !124 (closed) 19-oci-foundation 19-oci-boilerplate !125 (closed)
2 !125 (closed) 19-oci-database 19-oci-foundation !126 (closed)
3 !126 (closed) 19-oci-cas 19-oci-database !127 (closed)
4 !127 (closed) ← you are here 19-oci-format 19-oci-cas !128 (closed)
5 !128 (closed) 19-oci-wiring 19-oci-format n/a

What's in MR-4

37 files, ~17,500 insertions, all Go code and fuzz seed corpus. This is the largest MR in the stack. File-by-file review is unrealistic at this size, so this MR description points reviewers at the highest-risk areas.

Worth a closer read:

  • manifest.go and manifest_state_test.go (~2,200 lines): manifest parsing/validation across all OCI mediatypes (image manifest, image index, scratch). State machine for manifest lifecycle (uploaded → tagged → referenced → soft-deleted).
  • upload.go and upload_state_test.go (~1,600 lines): multi-step upload flow (POST → PATCH → PUT) backed by CAS sessions. State transitions covered by property-based and rapid state-machine tests per !55 (merged) §Technique selection.
  • store.go (~1,300 lines): the integration point that ties datastore, CAS, namespace, and the format-specific logic together. Reviewers should check the transaction boundaries on push (manifest write, blob refs, tags) and pull paths.
  • referrers.go: OCI 1.1 §referrers API. Returns subject-referrer manifest index given a digest.
  • digest.go / mediatype.go / Content-Range parser: each has a testing.F fuzz target. Seed corpus committed alongside.
  • tags.go: tag list pagination per OCI Distribution Spec.

The package follows !55 (merged) two-agent test flow per the spec-coverage table (Steps 7-12 of docs/plans/2026-04-28-oci-local.md).

Test plan

  • CI green on this MR (build, vet, lint, full unit test suite). The package is the heaviest test surface in the stack, expected duration ~1 minute.
  • test:integration activates (changes match internal/datastore/** transitively) and store_integration_test.go and store_size_integration_test.go pass.
  • test:fuzz does not retrigger (gated by internal/auth/**).
  • !128 (closed)'s wiring builds the OCI handlers via internal/router, which imports this package. Tested locally.

Reviewer notes

  • The 17k-line size is acknowledged. Pawel proposed a 1k-LOC bar in the !124 (closed) review thread, and this MR is over that. The OCI format is highly cohesive (datastore + CAS + state machines + protocol parsing inseparable), and decomposing it further would only displace complexity into the wiring layer. We accept the size for this milestone (Friday OCI-local deadline) and revisit decomposition post-merge if reviewer feedback identifies natural boundaries.
  • Spec gaps surfaced during implementation are journaled in docs/dev/oci-spec-gaps.md (already in MR-0). Each entry names the resolution and the pointer to where the choice landed.
Edited by Hayley Swimelar

Merge request reports

Loading
Loading