Prepare a release

Maintainer workflow for requesting, gating, publishing, and verifying an OpenBao Operator release.

Updated 16 October 2026 · 10 min read

On this page

The release path creates a signed tag and draft GitHub Release from an approved release-please PR. The tag starts a build-once workflow that verifies the candidate before it promotes images by digest and publishes the release.

Choose the source branch

ReleaseSource branchRule
Prerelease or first stable X.Y.0Frozen mainDo not create the release branch before the first stable release succeeds.
Patch X.Y.Zrelease-X.YBackport only the fixes and documentation intended for that release line.
Edgemain after successful CIValidation channel, not a stable release.
NightlySuccessful Nightly runScheduled drift and compatibility channel, not a stable release.

Create release-X.Y from the published X.Y.0 commit. Normal development can then resume on main while patch releases remain narrow.

Prepare the release content

Keep CHANGELOG.md generated by release-please. Put the human summary, upgrade notes, and migration callouts in release-notes/X.Y.Z.md. The tag workflow prepends that file to the generated changelog section when it creates the draft release. Prereleases use their exact version, for example release-notes/X.Y.Z-rc.1.md; do not reuse stable notes whose installation commands reference a version that has not been published yet.

For every stable release, including patches, add website/content/releases/X.Y.Z.md and update the highlighted release and archive in website/content/releases/_index.md. These pages are maintained by hand; the docs build does not generate them from GitHub Releases or CHANGELOG.md. Include the release highlights, upgrade guidance, and links to the published artifacts and applicable migration procedures. Run make docs-build to validate the pages.

When a stable X.Y.0 follows one or more release candidates, release-please generates its new changelog section from the latest release-candidate tag. After release-please creates the stable release PR, replace only that new section with a concise rollup from the previous stable release to X.Y.0. Use the previous stable tag in the comparison link, and keep the incremental release-candidate sections below it. Do not add the stable section before release-please creates the PR because that can produce duplicate version headings.

If the final release candidate contains all user-facing commits, the pinned exact-version wrapper permits release-please to create a stable PR with only the new version heading. Replace that heading-only section with the same reviewed previous-stable rollup before you authorize the release.

For a patch, make the conventional commit or squash title describe the user-visible fix. Release-please uses that text to generate the changelog.

verify

Check release automation locally

devenv test
devenv tasks run operator:bootstrap
devenv tasks run operator:doctor
devenv tasks run operator:ci-core
devenv shell -- make verify-workflows

Also confirm that compatibility guidance, generated API surfaces, and release notes match the candidate. Review current main, Nightly, release-gate E2E, previous-stable operator-upgrade, security, provenance, and performance evidence before authorizing publication.

Set the previous stable version, target release, and pinned baseline init image in test/fixtures/operator-upgrade/versions.env. Keep the Hardened fixture’s init image consistent with that pin. Add the target migration fixture and an upgrade section in its release notes. The runtime upgrade baseline is independent of the historical API stability baseline in api/stability/v1alpha1.yaml.

Request an exact version

Release-please opens normal release PRs from conventional commits. Use the Prepare Release-As PR workflow when a prerelease, patch, or other exact version must be requested explicitly.

request

Create an auditable Release-As marker PR

gh workflow run prepare-release-as-pr.yml \
  --repo kubebao/openbao-operator \
  -f target_branch=main \
  -f version=X.Y.Z-rc.1

For a patch, use target_branch=release-X.Y and a version in that release line. The workflow rejects invalid SemVer, missing or mismatched branches, existing tags or releases, open release-please PRs, and conflicting marker state. It creates an empty signed-off commit containing Release-As: <version> on an automation/release-as-* branch.

Merge the marker PR first. Because protected branches require squash merges, the branch-aware Release Please PR workflow validates that the resulting marker commit is empty and recovers the exact version from its generated squash subject. It then opens or updates the actual release PR. The direct release_as dispatch input remains available, but the marker PR is the preferred auditable path.

Review and merge the release PR

Before merge, verify that the release PR updates these surfaces consistently:

  • .release-please-manifest.json and generated CHANGELOG.md;
  • charts/openbao-operator/Chart.yaml version and appVersion;
  • Artifact Hub changes, image metadata, prerelease flag, and security-update flag;
  • release-notes/X.Y.Z.md when the release needs a human summary or upgrade guidance;
  • website/content/releases/X.Y.Z.md and the release index for stable releases.

The release PR gate requires the release:ready label and approval from the configured release manager (dc-tec in the current workflow). Do not bypass that gate to repair automation.

After merge, the Release Tag workflow resolves the exact merged release PR, verifies its release files, creates a GPG-signed annotated SemVer tag, and creates or refreshes the matching draft GitHub Release. The tag GitHub App is the only automation identity that should have SemVer tag-ruleset bypass.

Use the manual branch-head tag target to retry an unpublished release after an approved release-branch fix. The branch head must descend from the release PR merge and carry the same release version.

To remove a failed unpublished candidate, dispatch Release Tag with operation=remove-unpublished. Provide its expected_tag_object_sha, expected_commit_sha, and completed failed_run_id. The workflow requires an empty draft or an already removed draft, a matching signed tag, and a failed or cancelled Release run whose promotion job never starts. It checks promotion jobs across all run attempts. The release App removes the draft and tag without changing tag protections. After merging and qualifying the fix, dispatch operation=create with tag_target=branch-head to create the corrected signed tag and draft. Corrections to a published release require a new version.

Let the tag workflow publish

The tag triggers the Release workflow. It:

  1. checks that the chart version, app version, tag, and draft release agree;
  2. builds the four images and performs an independent rebuild;
  3. runs vulnerability, Semgrep, image, release E2E, operator-upgrade, provenance, and byte-reproducibility gates;
  4. waits at the release-publish environment before public promotion;
  5. promotes the verified image manifests by digest, without rebuilding;
  6. signs images and the OCI Helm chart with the tag-scoped workflow identity;
  7. signs and attests checksums, generates SBOMs and provenance-index.json, uploads assets, and publishes the draft GitHub Release.

The stable public distribution surface is:

SurfacePublished result
GHCR imagesVersion-tagged, digest-addressable, signed manager, init, backup, and upgrade images
GHCR Helm OCICanonical signed chart at ghcr.io/kubebao/charts/openbao-operator
GitHub ReleaseInstaller manifest, CRDs, policy approval files, checksums and signature bundles, SBOMs, and provenance index
Artifact HubDiscovery and metadata for the GHCR chart

These coordinates apply to releases published under KubeBao. Historical releases, including 0.5.1 and earlier, retain their ghcr.io/dc-tec images and charts, dc-tec/openbao-operator signing identities, and original provenance. Use the repository and signer recorded in each release’s provenance index when verifying historical artifacts. Do not republish a historical version under the new coordinates.

OLM bundles remain repository and CI validation assets; public OperatorHub publication is not part of the supported release procedure.

dist/install.yaml and dist/crds.yaml are generated release outputs. Do not treat local copies as source-controlled publication artifacts.

make build-policy-approvals generates operator-policy-approval.hcl and operator-policy-approval-with-backup.hcl in dist/. Both approve the two supported upgrade strategies; only the second includes backup policy management. The Release workflow generates and compares both files in its reproducibility check, includes them in signed checksums and the provenance index, and uploads them with the release.

Verify the published release

Post-Release Verification runs after a successful Release workflow and can also be dispatched for a tag. It verifies the remote tag, required assets, checksum signature, OCI chart signature, release-please label cleanup, and absence of open or stale release-please branches. It stores JSON evidence for 30 days and adds the evidence link and digest to the release PR.

verify

Run post-release verification

VERSION=X.Y.Z \
REPO=kubebao/openbao-operator \
EVIDENCE_OUT=dist/post-release-verification.json \
hack/ci/verify-post-release.sh

Local verification requires gh, jq, git, Docker Buildx, Helm, and cosign.

For manual workflow runs, select current as the publisher for releases published from the current repository. Select dc-tec/openbao-operator for pre-transfer releases, including 0.5.1. Automatic runs use the current repository as the publisher.

For local verification of a historical release, keep REPO=kubebao/openbao-operator and set PUBLISHER_REPO=dc-tec/openbao-operator. Set EXPECTED_CHART_FILE to the charts/openbao-operator/Chart.yaml extracted from that release’s tag. The verifier reads tags, release assets, and PRs from REPO, but checks signatures, attestations, image paths, and chart paths against PUBLISHER_REPO. It records both repositories in the verification evidence and rejects provenance from a different publisher.

The verifier retrieves image and chart attestations from their OCI registries and checksum provenance from the published checksums.intoto.jsonl asset. This avoids repository-scoped attestation lookup after a repository transfer. Each verification still requires the selected publisher, signer workflow, source ref, artifact digest, GitHub OIDC issuer, and GitHub-hosted runner.

Release-please cleanup checks still apply to the current repository. An open release PR prevents an overall pass even when historical artifact verification succeeds.

Use the provenance index to select digest-pinned subjects for additional checks:

verify

Verify release identity and subjects

gh release download X.Y.Z \
  --repo kubebao/openbao-operator \
  --pattern provenance-index.json \
  --pattern checksums.txt \
  --pattern checksums.txt.bundle

jq '.release, .identity_constraints, .images, .chart' provenance-index.json

cosign verify \
  --new-bundle-format=true \
  --certificate-identity \
    "https://github.com/kubebao/openbao-operator/.github/workflows/release.yml@refs/tags/X.Y.Z" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  "ghcr.io/kubebao/openbao-operator@sha256:<digest>"

gh attestation verify \
  "oci://ghcr.io/kubebao/charts/openbao-operator@sha256:<digest>" \
  --bundle-from-oci \
  --repo kubebao/openbao-operator \
  --signer-workflow kubebao/openbao-operator/.github/workflows/release.yml \
  --source-ref refs/tags/X.Y.Z \
  --cert-oidc-issuer https://token.actions.githubusercontent.com \
  --deny-self-hosted-runners

If artifacthub-repo.yml changes, refresh the repository metadata separately:

publish

Publish Artifact Hub repository metadata

oras push \
  ghcr.io/kubebao/charts/openbao-operator:artifacthub.io \
  --config /dev/null:application/vnd.cncf.artifacthub.config.v1+yaml \
  artifacthub-repo.yml:application/vnd.cncf.artifacthub.repository-metadata.layer.v1.yaml

If verification fails or publication state is unexpected, stop and use the publishing incident runbook.

Publish edge Helm charts

Successful main CI builds and verifies an edge chart with version 0.0.0-edge.<run-id>.<attempt>.g<commit>. The fixed 0.0.0 base keeps edge identity independent of release versions. The shared channel workflow compares independent package builds and installs the packaged chart in Kind without image overrides. The edge publisher then pushes those package bytes to ghcr.io/kubebao/charts-edge/openbao-operator, signs the OCI digest, and verifies its GitHub attestation. A publisher rerun accepts an existing chart version only when its bytes match.

The source chart remains shared with releases. Edge packaging sets the operator version and manager digest, and sets helperImages.init, helperImages.backup, and helperImages.upgrade. The controller receives these values as OPERATOR_INIT_IMAGE, OPERATOR_BACKUP_IMAGE, and OPERATOR_UPGRADE_IMAGE. These complete image references take precedence over the repository/version defaults. A cluster’s explicit helper image still takes precedence over the operator default.

The edge repository must remain unregistered in Artifact Hub. Do not publish artifacthub-repo.yml or an Artifact Hub repository registration for it. Stable and release-candidate charts continue to use ghcr.io/kubebao/charts/openbao-operator. Nightly chart publication remains a separate future change and must use a separate unregistered repository too.

On the first publication, check that the new GHCR package permits anonymous pulls and inherits the repository’s Actions access. The edge metadata at edge/latest/metadata.json records the chart reference, version, and digest. The same candidate’s chart archive and checksum are available alongside the manifests on GitHub Pages.

The publisher adds edge-chart-<chart-version> tags to all four image manifests. GHCR housekeeping protects these tags and their reachable platform manifests and signatures. Published charts and these image sets have no automatic expiry. Any future chart cleanup must coordinate chart deletion with removal of the corresponding image retention tags.

Run make verify-edge-chart to check package contents, Helm rendering, reproducibility, and publication retry guards.

Search the handbook

Try “install”, “threat model”, or “compatibility”.