Repository navigation
v8.1.0 — Registry Hygiene Pack
Three orthogonal-but-thematic features that close the most operationally-painful gaps versus JFrog without taking on Harbor/JFrog's complexity. Strategy-first: deep-spec + 3 feature-specs written before any code (~3500-word deep-spec, decisions D1-D6 pre-committed).
One sentence to defend
Registry hygiene that operators actually use — provenance you can read, retention you can preview, upstream caching that survives Docker Hub rate limits — without taking on Harbor's or JFrog's operational burden.
What's new
1. Build Provenance Panel (read-only)
New collapsible panel in the manifest-inspect modal. Reads OCI annotations + cosign signature presence:
- Source — clickable link for github/gitlab/bitbucket/codeberg/gitea
- Commit — truncated SHA + tooltip with full one + created timestamp
- Authors, License (SPDX), Vendor, Version, URL, Documentation, Base image
- Signed badge if cosign signatures present (presence detection — cryptographic verification deferred to v8.2.0)
- "Show all annotations" expander
Pure read-side, zero new state. Empty-state hint links to Docker docs on enabling buildx provenance.
2. Retention Policies with Dry-Run
Per-repo cleanup rules with 5 safety layers:
- Default disabled (dry-run only until operator explicitly enables)
- Hard floor: minTagsToKeep ≥ 1, default 3
- Default protected patterns: `latest`, `v*`, `main`, `master`, `prod-*`, `stable`
- Server cap: 200 deletions per run regardless of rule
- Tamper-evident audit trail: each deletion writes its own `registry_tag_delete` entry + umbrella `retention_executed` summary
UX: 4 rule templates + JSON editor + Preview button (dry-run table showing would-delete vs would-keep with reason chips per row, total bytes reclaimed). Save (dry-run) vs Enable — separate two-step gate.
Daily cron at 03:17 (off-:00), leader-only.
3. Remote/Virtual Repository Support
JFrog-style local / remote / virtual taxonomy adapted to Distribution's one-upstream-per-instance constraint:
- local — push target (existing v7.5.0 template, untouched)
- remote — caching proxy of an upstream registry
- virtual — aggregator URL routing across multiple repos via Caddy strip_prefix
New "Private Registry + Cache (3 containers)" template — sibling of the v7.5.0 template:
- 1 local registry + 2 remote proxies (Docker Hub + GHCR) + 1 Caddy router
- Caddyfile shipped via new `extraFiles` template field
- Pull `:5000/dockerhub/library/nginx:alpine` (proxied + cached) or `:5000/myteam/myapp:v1` (catch-all → local)
Browse UI gets a "Repository settings" expander with type editor (radio + upstream URL/creds for remote type, encrypted at rest). Type pill renders next to repo name.
Tests
| Suite | Tests | Coverage |
|---|---|---|
| registry-provenance | 15 | All 12 OCI keys, source linkification, cosign detection (3 variants) |
| retention | 27 | All 4 rule clauses, 5 safety layers, dry-run/real fork, partial-failure |
| registry-repos | 16 | List, upsert ON CONFLICT, encryption round-trip, cascade delete, virtual resolution |
Suite: 1024 → 1082 passing / 67 suites. Lint clean for new code.
Test agents dispatched in parallel — 3 concurrent agents wrote the 58 new tests across independent files with zero conflict.
Anti-features explicitly NOT shipped
(Deep-spec §10 — listing so future contributors don't litigate)
- Federation / multi-region replication
- JFrog Distribution release bundles + edge nodes
- Pre-ingest curation gating
- AppTrust evidence graph
- Multi-format repos (Maven/npm/PyPI — different product, Nexus OSS exists)
- Promotion workflows (deferred to v8.2.0+)
- Cosign cryptographic verification (deferred to v8.2.0+)
- Auto-trigger of `registry garbage-collect`
Migration
Single migration `063_registry_repos_and_retention.js` creates both new tables. Auto-seeds catch-all `local *` repo entry on first read of any registry credential — existing UX (Browse, Push) just works for v7.5.0–v8.0.x operators upgrading.
Roadmap
- v8.2.0 — promotion workflows + cosign cryptographic verification (gated on v8.1.0 production signal)
- AI vuln triage (originally planned v8.1.0) gets pushed back; gate still on production signal from audit NL search
See CHANGELOG.md for the full file-by-file breakdown.