Phase 7: OCI delete path for manifests and blobs

Manifest delete (DELETE /v2/<name>/manifests/<digest>): rejects tag
references with 405 UNSUPPORTED per OCI spec, cascades to tags and
manifest_blobs via ON DELETE CASCADE, returns 202 Accepted.

Blob delete (DELETE /v2/<name>/blobs/<digest>): removes manifest_blobs
associations only — blob row and file are preserved for GC to handle,
since other repos may reference the same content-addressed blob.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 20:23:47 -07:00
parent dddc66f31b
commit c01e7ffa30
9 changed files with 623 additions and 7 deletions

View File

@@ -6,7 +6,7 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
## Current State
**Phase:** 6 complete, ready for Phase 7
**Phase:** 7 complete, ready for Phase 9
**Last updated:** 2026-03-19
### Completed
@@ -18,6 +18,7 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
- Phase 4: Policy engine (all 4 steps)
- Phase 5: OCI pull path (all 5 steps)
- Phase 6: OCI push path (all 3 steps)
- Phase 7: OCI delete path (all 2 steps)
- Phase 8: Admin REST API (all 5 steps)
- `ARCHITECTURE.md` — Full design specification (18 sections)
- `CLAUDE.md` — AI development guidance
@@ -26,14 +27,51 @@ See `PROJECT_PLAN.md` for the implementation roadmap and
### Next Steps
1. Phase 7 (OCI delete)
2. After Phase 7, Phase 9 (garbage collection)
3. Phase 10 (gRPC admin API)
1. Phase 9 (garbage collection)
2. Phase 10 (gRPC admin API)
---
## Log
### 2026-03-19 — Phase 7: OCI delete path
**Task:** Implement manifest and blob deletion per OCI Distribution Spec.
**Changes:**
Step 7.1 — Manifest delete:
- `db/delete.go`: `DeleteManifest(repoID, digest)` — deletes manifest
row; ON DELETE CASCADE handles manifest_blobs and tags
- `oci/delete.go`: `handleManifestDelete()` — policy check
(registry:delete), rejects deletion by tag (405 UNSUPPORTED per OCI
spec), returns 202 Accepted, writes `manifest_deleted` audit event
- Updated `oci/routes.go` dispatch to handle DELETE on manifests
Step 7.2 — Blob delete:
- `db/delete.go`: `DeleteBlobFromRepo(repoID, digest)` — removes
manifest_blobs associations only; does NOT delete the blob row or
file (GC's responsibility, since other repos may reference it)
- `oci/delete.go`: `handleBlobDelete()` — policy check, returns 202,
writes `blob_deleted` audit event
- Updated `oci/routes.go` dispatch to handle DELETE on blobs
- Extended `DBQuerier` interface with delete methods
**Verification:**
- `make all` passes: vet clean, lint 0 issues, all tests passing,
all 3 binaries built
- DB delete tests (5 new): delete manifest (verify cascade to tags and
manifest_blobs, blob row preserved), manifest not found, delete blob
from repo (manifest_blobs removed, blob row preserved, manifest
preserved), blob not found, blob exists globally but not in repo
- OCI delete tests (8 new): manifest delete by digest (202), delete by
tag (405 UNSUPPORTED), manifest not found (404 MANIFEST_UNKNOWN),
repo not found (404 NAME_UNKNOWN), cascading tag deletion verified,
blob delete (202), blob not in repo (404 BLOB_UNKNOWN), blob delete
repo not found
---
### 2026-03-19 — Phase 6: OCI push path
**Task:** Implement blob uploads (monolithic and chunked) and manifest