Files
cozystack/hack/lib/promoted-packages.sh
T
Myasnikov Daniil e85482bacc ci(release): complete the candidate-aware promotion pipeline on release-1.6
Promote RC refuses to promote a release whose target base cannot verify
the packages candidate. It checks five markers on the base branch before
its first registry write and fails closed with "Target base
'release-1.6' lacks '<path>'". This branch satisfied one of the five
(hack/lib/image-refs.sh), so the next patch release off release-1.6
could not be dispatched at all.

Add the two halves the base has to carry:

  * hack/verify-promoted-packages.sh and hack/lib/promoted-packages.sh,
    byte-identical to main. The verifier pulls the candidate by its
    committed digest and proves it matches the merge tree apart from the
    artifact's impossible self-reference, that promotion rewrote every
    version-line image tag, and that the container repo@digest set is
    unchanged from the rc artifact.

  * the two jobs that run it. verify-release-candidate in
    pull-requests.yaml checks GitHub's prospective merge tree so a
    packages/ edit pushed to the promote PR shows up as a failed check,
    and a Verify stable packages candidate step in the finalize job of
    pull-requests-release.yaml repeats it against the real merge commit.

Position is the whole point of the finalize half: it runs before the
write-once stable tag, the draft-release publish and the retag, so a bad
candidate is refused while nothing stable-named exists yet. The former
"Set up toolchain (skopeo, yq, helm)" and "Login to registry (GHCR)"
steps moved up with it and are no longer duplicated later in the job;
the toolchain now also installs flux and pins yq by version and sha256,
because an irreversible step must not depend on whatever
releases/latest/download resolves to today.

verify-release-candidate is keyed on the promote PR's author and its
head-branch shape rather than on the `release` label main matches. This
branch's on.pull_request.types has no `labeled` event, and the label is
applied about a second after the PR opens (a separate call in
gh pr create), so the `opened` payload carries no labels and a
label-keyed guard would never fire here.

.release-tooling is gitignored, matching main, so the trusted-base
checkout can never be staged.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-08-17 14:52:28 +05:00

26 lines
1.5 KiB
Bash

# shellcheck shell=sh
# Shared definitions for the stable-candidate packages artifact.
#
# Sourced by hack/promote-packages-artifact.sh, which publishes the candidate,
# and hack/verify-promoted-packages.sh, which proves it. The publisher's whole
# reason to inspect the pin at all is to make the verifier's refusal land at
# dispatch time, before a registry write, two commits and a draft release exist
# — so the two have to be testing the same thing. Copied constants would drift
# apart silently and turn that dispatch-time refusal back into the late failure
# it was added to remove; they live here instead.
#
# Not a general library: promotion is the only caller, and both halves run from
# a `hack`-only sparse checkout of a trusted ref, so this file has to stay
# inside hack/ next to them.
# The one OCI repository a packages candidate may ever be published to or read
# back from. Overridable only so the behavioural suites can point both halves
# at a fixture registry; production never sets it.
EXPECTED_PACKAGES_REPOSITORY="${EXPECTED_PACKAGES_REPOSITORY:-oci://ghcr.io/cozystack/cozystack/cozystack-packages}"
# An immutable Flux OCI source pin, `digest=sha256:<64 lowercase hex>`. The
# tag form Flux also accepts is exactly what promotion must neither publish nor
# accept: a stable installer pinned by tag resolves to whatever that tag points
# at later, which is how a stable install ends up serving rc content (#3477).
PACKAGES_DIGEST_REF_PATTERN='^digest=sha256:[0-9a-f]{64}$'