feat(release): publish a Registry Discovery image - #797
Conversation
Registry Discovery had no released artifact. Add release/docker/Dockerfile.discovery and carry the discovery image and a discovery-<tag>-linux-amd64 binary through the release pipeline, gated at v0.24.0 so every released and staged version keeps its exact recorded inventory. Discovery serves one immutable index and writes nothing, so unlike the other runtime images it pre-owns no managed state or audit directory. It also reads no environment variable, so the runtime file is bound by the command rather than by ENV. check-debian13-images.py now models that: the environment key of an HTTP-probed contract is optional, and a service that declares none must carry no ENV in its runtime stage, so a second undeclared configuration source cannot appear later. Security review notes (release provenance): - The image roster stays version-derived from _candidate_image_names, so the candidate manifest, per-image SPDX, Syft and Grype reports, advisory subjects, and the promotion binding all pick discovery up together at v0.24.0 and never retroactively for an already-published tag. - Candidate cleanup gains discovery-candidate in the exact allowlist and discovery in the public denylist, so its private candidate versions expire on the same eight-day schedule and its public package can never be deleted. - The weekly repeatability proof now rebuilds and byte-compares the discovery binary alongside the others. - release/security/discovery-advisory-baseline.json is deliberately not included: a v4 baseline binds a reviewed runtime block, exception set, owner, and expiry to a real candidate image, which does not exist yet. The candidate fails closed on the missing file, and OPERATIONS.md now states how to author it from the first discovery candidate run. Verified: the OCI label smoke builds Dockerfile.discovery twice under the pinned BuildKit and compares the layouts, so the image is reproducible and carries the required source, revision, and version labels; 388 release-tooling tests, check-debian13-images.py, check-gates-inventory.py, check-release-source-model.sh, and shellcheck on the changed scripts all pass. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The release artifacts row lists the container images the release workflow publishes, so it goes stale the moment Registry Discovery ships one. Name `ghcr.io/registrystack/discovery` there with the version it starts at, so the row keeps describing the roster a reader can actually pull. The row states a covered interface rather than a reviewed claim about the rest of the page, so `last_reviewed` stays where the last human review left it. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
4944a08 to
89cf002
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4944a08bbd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The `discovery` binary declared no version, so `discovery --version` exited 2 with "unexpected argument". The release candidate asserts every image reports `<name> <version>`, so no Discovery image could ever pass that gate. Take the version from `registry-platform-buildinfo::DISPLAY_VERSION`, as every other Registry Stack executable does, so a build without `REGISTRY_RELEASE_TAG` reports `<version>-dev` and only a release build reports the bare version. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The binary recipe runs for every supported version, including a candidate rebuilt for a version whose recorded inventory predates Discovery. Staging `discovery-<tag>-linux-amd64` unconditionally would hand seal-candidate a payload the recorded inventory does not name, so a rebuild of an earlier release would fail. Gate the build and the staged asset lists on the same 0.24.0 boundary the release inventory already uses, and keep the pre-0.24 asset ordering so those candidates still produce byte-identical SHA256SUMS. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
The daily cleanup lists exactly the names in `CANDIDATE_PACKAGES` and fails closed on a package it cannot list, a deliberate and tested behaviour. Naming `discovery-candidate` before v0.24.0 publishes it would abort every scheduled run on a 404, and it sorts first, so no other candidate would be cleaned. Withdraw the name until the package exists and record the enrolment step in release operations beside the advisory-baseline prerequisite. The public `discovery` name stays on the denylist, so cleanup can never reach a released image. Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0200227ed2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
What
Registry Discovery had no released artifact. This adds
release/docker/Dockerfile.discoveryand carries both aghcr.io/registrystack/discoveryimage and adiscovery-<tag>-linux-amd64binary through the release pipeline, gated at v0.24.0 so every released and
staged version keeps its exact recorded inventory (v0.23.0 / beta-34 is already
staged and is untouched).
Why the Dockerfile differs from the other runtimes
Discovery serves one immutable index and writes nothing, so unlike relay,
evidence, and mint it pre-owns no managed state or audit directory and needs no
chown. It also reads no environment variable: the runtime file is bound byCMD, notENV.release/scripts/check-debian13-images.pynow models that. Theenvironmentkey of an HTTP-probed contract became optional, and to keep that from being a
silent weakening, a service that declares no environment must carry no
ENVinits runtime stage, so a second undeclared configuration source cannot appear
later. A test injects
ENV SMUGGLED_CONFIG=...and expects the failure.Security review notes (release provenance)
_candidate_image_names, so thecandidate manifest, per-image SPDX, Syft and Grype reports, advisory
subjects, and the promotion binding all pick discovery up together at
v0.24.0 and never retroactively for an already-published tag.
discovery-candidatein the exact allowlist anddiscoveryin the public denylist, so its private candidate versions expireon the same eight-day schedule and its public package can never be deleted.
binary alongside the others.
Known follow-up: the advisory baseline
release/security/discovery-advisory-baseline.jsonis deliberately notincluded. A v4 baseline binds a reviewed runtime block (image digest, ordered
layer IDs, exact OCI process config, definition digest), an exception set,
owner, and expiry to a real candidate image, which does not exist yet. An empty
exception list would not clear the pinned Debian 13 runtime's High/Critical
findings.
The candidate fails closed on the missing file, which is the correct behavior.
release/OPERATIONS.mdnow states how to author the baseline from the firstdiscovery candidate run. This needs a human security sign-off before the
first v0.24.0 candidate.
Verification
release/scripts/smoke-release-image-oci-labels.shagainst real Docker29.4.0 / buildx v0.33.0: builds
Dockerfile.discoverytwice with differentsource mtimes and compares the OCI layouts blob-for-blob, so the image is
reproducible and carries the required source, revision, and version labels.
check-debian13-images.py,check-gates-inventory.py(151 gates),check-release-source-model.sh,registry-release validateon the staged beta-34 manifest.shellcheckclean on the changed scripts;cargo build --locked -p registry-discovery --bin discovery.npm run checkequivalent green (check:source18sub-checks,
build,check:built:currentincluding 18439 link targets).