package oci import ( "errors" "fmt" "net/http" "git.wntrmute.dev/kyle/mcr/internal/db" "git.wntrmute.dev/kyle/mcr/internal/policy" ) // handleManifestDelete handles DELETE /v2//manifests/. // Per OCI spec, deletion by tag is not supported — only by digest. func (h *Handler) handleManifestDelete(w http.ResponseWriter, r *http.Request, repo, reference string) { if !h.checkPolicy(w, r, policy.ActionDelete, repo) { return } // Reference must be a digest, not a tag. if !isDigest(reference) { writeOCIError(w, "UNSUPPORTED", http.StatusMethodNotAllowed, "manifest deletion by tag is not supported; use digest") return } repoID, err := h.db.GetRepositoryByName(repo) if err != nil { if errors.Is(err, db.ErrRepoNotFound) { writeOCIError(w, "NAME_UNKNOWN", http.StatusNotFound, fmt.Sprintf("repository %q not found", repo)) return } writeOCIError(w, "UNKNOWN", http.StatusInternalServerError, "internal error") return } if err := h.db.DeleteManifest(repoID, reference); err != nil { if errors.Is(err, db.ErrManifestNotFound) { writeOCIError(w, "MANIFEST_UNKNOWN", http.StatusNotFound, fmt.Sprintf("manifest %q not found", reference)) return } writeOCIError(w, "UNKNOWN", http.StatusInternalServerError, "internal error") return } h.audit(r, "manifest_deleted", repo, reference) w.WriteHeader(http.StatusAccepted) } // handleBlobDelete handles DELETE /v2//blobs/. // Removes manifest_blobs associations for this repo only. Does not delete // the blob row or file — that is GC's responsibility. func (h *Handler) handleBlobDelete(w http.ResponseWriter, r *http.Request, repo, digest string) { if !h.checkPolicy(w, r, policy.ActionDelete, repo) { return } repoID, err := h.db.GetRepositoryByName(repo) if err != nil { if errors.Is(err, db.ErrRepoNotFound) { writeOCIError(w, "NAME_UNKNOWN", http.StatusNotFound, fmt.Sprintf("repository %q not found", repo)) return } writeOCIError(w, "UNKNOWN", http.StatusInternalServerError, "internal error") return } if err := h.db.DeleteBlobFromRepo(repoID, digest); err != nil { if errors.Is(err, db.ErrBlobNotFound) { writeOCIError(w, "BLOB_UNKNOWN", http.StatusNotFound, fmt.Sprintf("blob %q not found in repository", digest)) return } writeOCIError(w, "UNKNOWN", http.StatusInternalServerError, "internal error") return } h.audit(r, "blob_deleted", repo, digest) w.WriteHeader(http.StatusAccepted) }