Skip to content

Releasing AdvisoryHub

This is the maintainer runbook for cutting a release. (Deploying a released version is covered by the operations manual.)

A release is one signed git tag vX.Y.Z that produces, automatically:

Artifact Where Built by
Container image X.Y.Z / X.Y (+ SBOM & SLSA provenance attestations, keyless cosign signature) ghcr.io/eclipse-csi/advisoryhub .github/workflows/release-image.yml
Helm chart X.Y.Z (keyless cosign signature) oci://ghcr.io/eclipse-csi/charts/advisoryhub .github/workflows/release.yml
GitHub release with git-cliff notes + chart .tgz, CycloneDX dependency SBOM, checksums.txt repo Releases page .github/workflows/release.yml
Versioned docs X.Y.Z (+ latest alias and root redirect) https://eclipse-csi.github.io/advisoryhub/ .github/workflows/docs.yml

The version lockstep rule

One version, recorded in four places, all of which must agree (and match the tag): pyproject.toml [project] version, the advisoryhub root package in uv.lock, and version + appVersion in charts/advisoryhub/Chart.yaml (image.tag defaults to appVersion, so the chart pulls its own release's image). dev/check_release_versions.sh (mise run release-check) asserts this; release.yml runs it as its first gate. Never bump pyproject.toml without uv lock — the lock records the root version and a stale one fails every uv sync --locked. (mise run release does all of this for you.)

Prerequisites

  • Push rights to main, and your SSH signing key loaded (ssh-add -l) — the release commit and tag are signed (-S) per the commit policy.
  • A clean tree on main (untracked files like TODO.md are fine).
  • The toolchain: mise install (git-cliff, trivy, helm ride mise.toml).

Cutting a release

mise run release -- X.Y.Z

This bumps every recorded version in lockstep (uv version handles pyproject + uv.lock atomically), re-syncs to prove the lock is sound, runs the version gate, previews the git-cliff notes, then creates the signed chore(release): vX.Y.Z commit and the signed vX.Y.Z tag. Nothing is pushed. Review, then:

git push origin main vX.Y.Z

The tag triggers three release workflows in parallel:

  1. Release image builds the production image, smoke-tests it under an arbitrary UID, gates on Trivy, pushes to ghcr.io with SBOM + provenance, and cosign-signs it.
  2. Release gates the versions, renders the notes, waits for the image (polls ghcr.io up to ~20 min — a failed image build fails the release run, so a GitHub release never exists without its image), pushes + signs the chart, and creates the GitHub release.
  3. Docs gates the versions, builds the site strictly, mike-deploys X.Y.Z + the latest alias to the gh-pages branch (each release's docs live in their own directory, so earlier versions are never touched), and deploys the branch content to GitHub Pages.

Verifying a release

# Image and chart signatures (identities are also in the release notes):
cosign verify ghcr.io/eclipse-csi/advisoryhub:X.Y.Z \
  --certificate-identity-regexp 'https://github.com/eclipse-csi/advisoryhub/\.github/workflows/release-image\.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
cosign verify ghcr.io/eclipse-csi/charts/advisoryhub:X.Y.Z \
  --certificate-identity-regexp 'https://github.com/eclipse-csi/advisoryhub/\.github/workflows/release\.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

# The chart installs from the OCI ref:
helm pull oci://ghcr.io/eclipse-csi/charts/advisoryhub --version X.Y.Z

# Release attachments match their checksums (in the downloaded assets dir):
sha256sum -c checksums.txt

When something fails

  • Image build failed (smoke test, Trivy gate): the Release run fails at the wait-for-image poll. Fix the problem; if the fix needs new commits, the tag must move — see "re-tagging" below. If the failure was transient, re-run the Release image workflow for the tag, then re-run Release.
  • Release run failed after the image published (chart push, gh release): fix and re-run the Release workflow — every step is idempotent-safe to retry except gh release create (delete the partial release first).
  • Docs deploy failed: independent of the other two — re-run the Docs workflow for the tag. mike deploy of the same version is idempotent (it replaces only that version's directory on gh-pages).

Re-tagging (the fix needed new commits)

A tag that has been pushed may have been fetched by others — prefer a new patch version when in doubt. To redo vX.Y.Z anyway:

gh release delete vX.Y.Z --yes                       # if it was created
git push origin :refs/tags/vX.Y.Z && git tag -d vX.Y.Z
# ghcr.io cleanup (image + chart package versions, incl. cosign sig tags):
gh api /user/packages/container/advisoryhub/versions --paginate   # find ids
gh api -X DELETE /user/packages/container/advisoryhub/versions/<id>
gh api -X DELETE "/user/packages/container/charts%2Fadvisoryhub/versions/<id>"
# then fix, and run `mise run release -- X.Y.Z` again

First chart push

The first push to oci://ghcr.io/eclipse-csi/charts creates a brand-new ghcr package; package creation in a user namespace via GITHUB_TOKEN occasionally 403s. If it does: push once with a PAT (helm registry login ghcr.io + helm push), grant the repo write access in the package settings, delete the manual version, and re-run the workflow.