This guide is for OCM release managers.
Scope: CLI and Kubernetes Controller are released together in version lockstep (RC and final).
Development in the Open Component Model monorepo
happens on main, while releases are prepared and promoted from release branches (releases/vX.Y).
For the time being, we will only ship minor releases (e.g., v0.17.0, v0.18.0) and patch releases (e.g., v0.17.1),
without any major releases.
This repository follows a lockstep release model for multiple components — currently the
CLI and the
Kubernetes Controller.
The default cadence is sprint-based: one release every two weeks. At the start of each sprint, create a new release branch and a new Release Candidate (RC). After one sprint of testing, promote the previous RC to a final release. At the end of each sprint (typically Friday), assign the next release responsible.
Patch releases are handled out-of-band and created on demand for critical fixes. A scheduled release can be skipped if the branch is not ready or there are no meaningful changes.
The release responsible coordinates and executes the release flow. This role rotates each sprint and involves:
- Agreeing with the team, if a new release is needed for the past sprint
- Triggering and supervising release branch creation
- Creating release candidates for all lockstep components
- Agreeing with the team, if the new release is ready for promotion
- Promoting release candidates to final releases
- Coordinating patch releases when needed
- Keeping this guide accurate and up to date
Quick links: Create release branch · Create RC · Promote to Final · Patch release
Copy this checklist to your "Sprint Responsible" issue:
- [ ] New release branch created (e.g `releases/v0.17`)
- [ ] CLI RC created and verified (`v0.17-rc.1`)
- [ ] Controller RC created and verified (`v0.17-rc.1`)
- [ ] CLI Final promoted from last RC (`v0.16-rc.1` --> `v0.16.0`)
- [ ] Controller Final promoted from last RC (`v0.16-rc.1` --> `v0.16.0`)
- [ ] Both releases visible on GitHub Releases page (`v0.16.0`)| When | Action |
|---|---|
| Sprint Start | Create new release branch and RCs for both components |
| During sprint | Issue patch releases or increment RCs if required (Security issues, bugs, ..) |
| Sprint End | Assign next release responsible |
| Next Sprint Start | Promote previous RCs to Final |
The following diagram illustrates a typical release cycle with an initial release (v0.17.0)
and a subsequent patch release (v0.17.1):
gitGraph TB:
commit id: "VERSION 0.17.0-dev"
commit id: "feat: some feature"
branch "releases/v0.17"
commit tag: "v0.17.0-rc.1" type: REVERSE
checkout main
commit id: "fix: hotfix bug" type: HIGHLIGHT
checkout releases/v0.17
cherry-pick id: "fix: hotfix bug"
commit tag: "v0.17.0-rc.2"
branch "tag/v0.17.0"
checkout "tag/v0.17.0"
commit id: "VERSION 0.17.0" tag:"v0.17.0"
checkout main
commit id: "VERSION 0.18.0-dev"
commit id: "fix: another hotfix" type: HIGHLIGHT
checkout releases/v0.17
cherry-pick id: "fix: another hotfix"
commit tag: "v0.17.1-rc.1"
branch "tag/v0.17.1"
checkout "tag/v0.17.1"
commit id: "VERSION 0.17.1" tag:"v0.17.1"
checkout main
commit id: "feat: another feature"
branch "releases/v0.18"
commit tag: "v0.18.0-rc.1"
A new release branch marks the cut-off point for that minor release line. Once created, only bug fixes and documentation changes are allowed.
- Run workflow Release Branch Creation.
- Set target branch to
releases/vX.Y. - Confirm the branch was created successfully.
What happens in the background?
- Validate
target_branchagainst regex patternreleases/v0.[0-9]+(for the time being, we only allow minor releases) - Check if
target_branchalready exists; if yes, skip creation and report success - Check out the repository and identify the latest commit on
source_branch(default:main) - Create a new branch
refs/heads/<target_branch>pointing to this commit - Publish workflow summary with source branch, target branch, and commit SHA
Caution
Cut-off policy for this release branch
- No feature or breaking-change work is accepted.
- Non-bugfix and non-documentation changes require release responsible approval.
- Any change that is not a bug fix or a documentation change require release responsible approval.
- Any bug fix that is not deemed critical must be approved by the release manager.
- Fixes must be merged to
mainfirst, then cherry-picked to this branch.
Release candidates are created for both components sequentially, in lock-step.
- Run workflow CLI Release with:
dry_run = truefirst to validatedry_run = falsefor actual releaseBranch to release fromset to the release branch created in step 1 (e.g.,releases/v0.17)
- Run workflow Controller Release with equivalent inputs.
- Verify both pre-releases were created successfully on the GitHub Releases page.
- CLI assets: platform binaries (
ocm-*) and OCI tarballs - Controller assets: Helm chart (
.tgz)
- CLI assets: platform binaries (
Caution
Always do a dry-run first before the actual release. CLI and Controller are released together. Do not release only one of them.
Understanding the Dry-Run Summary
Dry-run mode validates the release workflow without creating any tags, releases, or artifacts. The workflow summary shows exactly what would happen:
| Field | Description |
|---|---|
| RC Version | The RC version that would be created (e.g., 0.17.1-rc.1) |
| Base Version | The final version after promotion (e.g., 0.17.1) |
| Set Latest | Whether latest tag would be applied to OCI images |
| Highest Final Version | The current highest released version |
Important for Patch Releases:
When releasing a patch for an older version line (e.g., v0.16.1 when v0.17.0 already exists),
the dry-run summary will show:
Set Latest: false
Highest Final Version: 0.17.0
This means the patch release will not be marked as the GitHub "Latest Release"
and the latest OCI tag will not be updated. This is expected behavior to prevent
users from accidentally downgrading when pulling latest.
What happens in the background?
- CLI path (
cli-release.yml)prepare: compute next RC metadata + changelog.tag_rc: create/push RC tag (skipped on dry-run).build: callcli.ymlto build binaries and OCI artifacts.release_rc: publish GitHub pre-release with binary and OCI tarball assets.
- Controller path (
controller-release.yml)prepare: compute next RC metadata + changelog (sharedrelease-candidate-version.yml).tag_rc: create/push RC tag viareleaseenvironment gate (skipped on dry-run).build: callkubernetes-controller.ymlto build the controller image and Helm chart.release_rc: publish GitHub pre-release with Helm chart.tgzas asset.
- If one component fails, do not proceed to final promotion.
Final promotion takes an existing RC and promotes it to a stable release. The workflow verifies attestations before creating any final artifacts.
The final promotion is triggered automatically after the RC phase completes and the respective environment gate is approved.
- Wait for the RC to be tested (typically 1 sprint).
- Go to the CLI Release workflow run in GitHub Actions.
- Approve the
releaseenvironment gate (requires reviewer approval + wait timer). - The CLI workflow will automatically:
- Verify binary and OCI image attestations
- Create final tag from RC commit
- Promote OCI image tags
- Publish final GitHub release with binaries
- Go to the Controller Release workflow run.
- Approve the
releaseenvironment gate (requires reviewer approval). - The Controller workflow will automatically:
- Verify image and Helm chart attestations
- Create final tag from RC commit
- Promote controller image tags
- Re-package the Helm chart with the final version, push it to OCI, and attest it
- Publish final GitHub release with the final Helm chart
- Verify both final releases are published on the GitHub Releases page.
Important
🔐 Security: Both workflows automatically verify all attestations from their respective RC releases before proceeding. If verification fails, the promotion is aborted.
What happens in the background?
- CLI path (
cli-release.yml)verify_attestations: verify binary and OCI image attestations (gated byreleaseenvironment).promote_final: create final tag from RC commit, promote OCI image tags.release_final: publish final GitHub release with assets from RC.
- Controller path (
controller-release.yml)verify_attestations: verify controller image and Helm chart attestations (gated byreleaseenvironment).promote_and_release_final(single combined job):- Create final tag from RC commit.
- Promote controller image tags via ORAS.
- Re-package Helm chart with final version strings (
Chart.yaml,values.yaml), push to OCI registry, and create build-provenance attestation. - Run
helm/verify-promoteto validate RC-to-Final chart consistency. - Publish final GitHub release with the re-packaged Helm chart.
- Due to Helm specifics, the chart cannot simply be re-tagged from RC to Final — it must be re-packaged and re-attested because it embeds version strings.
- Final is only valid when both components are promoted in the same cycle.
Patch releases address critical fixes for an already-released version.
The fix must always land on main first, then be cherry-picked to the release branch.
Important
v0.16.1 when v0.17.0 exists), the release will NOT be marked as "latest"
on GitHub and the latest OCI tags will remain on the newer version.
This is intentional — use dry-run first to verify this behavior in the summary.
- Ensure the fix was merged to
mainfirst. - Cherry-pick the fix to the correct release branch, e.g.
releases/v0.17for a patch tov0.17.1. - Create a PR with the cherry-picked commit to the release branch.
- Create and test RCs for both CLI and Controller.
- Promote both components to final.
Patch PR naming and cherry-pick flow
# Check out the target release branch
git checkout releases/vX.Y
# Cherry-pick the commit from main
git cherry-pick <commit-hash>
# Create a PR to the release branch
gh pr create \
--title "[releases/vX.Y] cherry-pick: <Original PR or Commit>" \
--body "Cherry-pick of <Original PR or Commit> from main to releases/vX.Y" \
--base releases/vX.Y \
--draftMerge the PR, then follow the RC and Final promotion steps as usual.
Release notes are generated automatically by the release workflows using git-cliff. The release responsible does not need to manually compose notes for normal RC or final runs—the changelog is derived from conventional commit messages.
If something goes wrong during a release, check the following common issues:
RC was not created
- Check if the workflow run failed before tag creation.
- Rerun as dry-run first, then rerun with
dry_run=false.
Final promotion fails with "no RC found"
- Verify that the latest RC tag exists on the release branch.
- Create a new RC for both components, then promote again.
CLI and Controller versions diverged
- Ensure both workflows were run for the same release branch in the same cycle.
- Stop promotion and align on a fresh RC cycle in lockstep.
Final release exists for one component but not the other
- Check the status of both workflow runs and the release pages.
- Complete or rerun the missing component release immediately.
Attestation verification failed
- Verify that the RC release binaries have valid build provenance attestations.
- Check that the OCI image was pushed to GHCR with attestation metadata.
- Use
gh attestation verify <file> --repo <repo>to manually verify CLI binaries. - Use
gh attestation verify oci://<image>@<digest> --repo <repo>to verify OCI images. - For the controller, also verify the Helm chart OCI artifact:
gh attestation verify oci://<chart-repo>@<chart-digest> --repo <repo> - If attestations are missing, create a new RC (attestations are generated during build).
Retracting a release
If a release needs to be retracted due to critical bugs or security issues:
- Edit the GitHub Release and mark it as "Pre-release" to hide it from the latest release view.
- Prepend a deprecation notice to the release notes:
> ⚠️ **RETRACTED**: This release has been retracted due to [reason]. > Please upgrade to vX.Y.Z instead. - Create a new patch release with the fix as soon as possible.
- If security-related, consider filing a security advisory via GitHub's Security tab.
The OCI image tags remain available in GHCR for users who have pinned to the specific version, but the retraction notice guides new users to the replacement release.