feat(datastore): S04-B rotation-tooling store operations

What

S04-B Plan Step 1 — the rotation-tooling concrete-store operations the operator commands drive, plus the ErrKeyVersionActive sentinel. All compose the existing store helpers (withTxVoid, lockAndCheckShredded, the SQLSTATE mapping, the column projection) rather than adding new machinery:

  • RetireKeyVersion — the ordered 5-step guarded delete (barrier + namespace-wide shredded check → active-version resolve with ErrKeyVersionActive → row-local shredded_at IS NULL DELETE → unconditional FK-refusal mapping (SQLSTATE 23001 on PostgreSQL 18, 23503 on 17 and earlier) → ErrKeyStillReferenced).
  • ActiveKeyAge — the active key's age by database time (single statement, no host clock).
  • ListLiveKeysNotUnderRootKeyURI — the root-rotation verification read (inequality, page-ceiling clamp, namespace-wide tombstone exclusion).
  • SuccessorKeyCreatedAt — the retirement pre-flight's successor lookup.

Tests

Integration matrix (//go:build integration) covering the full retirement sentinel matrix (shredded/mixed-state, active/above-active, missing/empty, real composite-FK ON DELETE RESTRICT refusal), age against a backdated created_at, the tombstone-excluded verification read + ceiling clamp, and the successor lookup incl. tombstone-skip. Adds testutil.CreateCredentialFKTable.

Covers spec AC 8, 9 and the retire rows of the Error Cases table; the age/verification/successor reads are consumed by AC 3/5/6 through Steps 4 and 8.

E2E: none — operator store ops have no format-client catalog scenario (per the plan's testing strategy).

Related to https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/496

Size

The diff exceeds the 500-LOC guideline (~990 changed lines, ~480 of them integration tests). Splitting was considered and declined for the reason the plan records: the four store operations share one FOR UPDATE barrier, error envelope, SQLSTATE mapping switch, and integration fixture set, so extracting the two reads would leave a consumer-less step while duplicating the shared foundation across both MRs.

Edited by Suleimi Ahmed

Merge request reports

Loading
Loading