REST management API (S17)
## Summary
REST CRUD surface (`/api/v1/:slug/...`) for Artifact Registry repositories and artifacts. Owns the `/api/v1` management surface (S01), distinct from the protocol client APIs (Maven, npm, OCI) and from the platform-facing [GitLab API (S33, &22846)](https://gitlab.com/groups/gitlab-org/-/work_items/22846). See [ADR-009](https://gitlab.com/gitlab-org/ops/artifact-registry/-/blob/main/docs/adr/009_api_design.md) and [ADR-022](https://gitlab.com/gitlab-org/ops/artifact-registry/-/blob/main/docs/adr/022_namespace_decoupling.md).
Shipped in phases; each phase patches the spec and follows the repo gate (spec MR, plan MR, implementation). **This epic tracks the closed-beta work; GA-scope phases live in [REST management API (S17): GA phases (&23063)](https://gitlab.com/groups/gitlab-org/-/epics/23063).** This split, and most of the changes in this description, follow the closed-beta rescope decided on 2026-07-31: [closed beta ships hard delete only; soft delete, restore, trash, and expiration ship together at GA](https://gitlab.com/gitlab-org/ci-cd/package-stage/unified-artifact-management/-/merge_requests/77#note_3630113302). Phase numbers are identifiers and are never reused; gaps in the closed-beta sequence are phases that moved (see the table).
## Phase map: closed beta vs GA
| Phase (spec ref) | What | Release | Status | Tracked in |
|---|---|---|---|---|
| Hosted repository CRUD (P1) | list, detail, create, update, delete | Closed beta | **Complete** | [&22342](https://gitlab.com/groups/gitlab-org/-/epics/22342) (closed) |
| Namespace lifecycle (P2) | provisioning, resolution, service conditions | — | **Moved to S33** | [&22846](https://gitlab.com/groups/gitlab-org/-/work_items/22846) |
| Format artifact reads (P3) | images/tags, packages, versions, files | Closed beta | In progress | [#312](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/312) |
| Artifact writes (P4) | delete, tag mutations, bulk delete | Closed beta | Gated, see below | [#313](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/313) |
| Repository soft-delete and trash (P5) | soft delete, restore, purge, trash listing | **GA** | Decided 2026-07-31, see below | [#197](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/197) → move to [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063) |
| Virtual and remote repository CRUD (P6) | remote/virtual `settings`, connection test | Closed beta | Gated on S13 | [#314](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/314) |
| Lifecycle policies (P7) | policy and rule configuration | **GA** | Gated on S19/S29 | [#315](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/315) → move to [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063) |
| Statistics, storage slice (P8) | namespace/format/repository storage figures | Closed beta | Gated on S22 | [#316](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/316), narrow to storage |
| Statistics, downloads slice (P8) | download counts and timestamps | **GA** | Gated on S18 (no spec yet) | split out of [#316](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/316) → new issue in [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063) |
| Security and compliance query APIs (P9) | checksum search, provenance, audit queries | Post-beta | Schema requirements feed the current design (S26) | [gitlab#593965](https://gitlab.com/gitlab-org/gitlab/-/issues/593965) |
| Artifact quarantine endpoints | per-artifact `PATCH`, split from P4 | **GA** | Deferred | [#482](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/482) → move to [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063) |
Hardening follow-ups from reviews belong to this epic without a phase number: [#423](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/423), [#451](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/451), [#461](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/461), [#468](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/468), [#480](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/480).
### P4 gates
Closed-beta deletes are permanent ([decision, 2026-07-31](https://gitlab.com/gitlab-org/ci-cd/package-stage/unified-artifact-management/-/merge_requests/77#note_3630113302); [ADR amendments](https://gitlab.com/gitlab-com/content-sites/handbook/-/merge_requests/20627)). The endpoints invoke per-format hard-delete machinery: the container deleter exists, maven has no delete path yet, and npm soft-deletes today and must be corrected first ([#470](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/470)). Usage events are [#423](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/423). S20 gates only the GA soft-delete semantics, not this phase.
### P5 decision
Closed beta ships hard delete only; soft delete, restore, trash, and expiration ship together at GA as one feature. The repository-level cascade closed beta does need is S20's [#464](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/464), mechanism discussion on [&22815](https://gitlab.com/groups/gitlab-org/-/work_items/22815#note_3636791368).
## Boundaries
- **S17 owns the HTTP surface only**; mechanisms live in their workstreams.
- **S20 (lifecycle)**: deletion and lifecycle mechanics. P4 calls the per-format deleters; soft-delete/restore/purge is S20's GA model.
- **S22 (storage accounting)**: counters and reconciliation. P8 exposes them and implements no accounting.
- **S28 (garbage collection)**: no S17 surface; blob reclamation is invisible to the API.
- **S13-S16 (remote/virtual foundations)**: datastore and service plumbing. P6 wires HTTP CRUD onto it (S15 Step 7 built the npm remote create service; the endpoint is P6).
## Follow-ups to complete this restructure
- [ ] Move [#197](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/197), [#482](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/482), and [#315](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/315) to [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063)
- [ ] Split the downloads slice out of [#316](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/316) into a new issue under [&23063](https://gitlab.com/groups/gitlab-org/-/epics/23063), and narrow #316 to the S22-backed storage slice
- [ ] Attach [#480](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/480) to this epic
- [ ] Fix the stale closed-beta scope line in [#313](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/313) (it still calls the deletion decision open)
- [ ] Fix the deferral rationale in [#482](https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/482): it cites "soft-delete plus restore covers the launch need", but closed beta ships neither; the deferral stands, the reason is the GA lifecycle scope
- [ ] Sync the S17 spec's phase overview (`docs/specs/S17-rest-management-api.md`) with this split; can ride the next phase spec MR
- [ ] Verify `docs/roadmap/closed-beta.md` reflects the split and the 2026-07-31 decision; the update vehicle is [!1259](https://gitlab.com/gitlab-org/ops/artifact-registry/-/merge_requests/1259), which still carries a stale "needs decision on soft-delete" note
epic