Replace release workflows with two-phase release process#788
Conversation
This is based on RFC 0020. Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThe PR adds release-version parsing and validation scripts, introduces pre-release and release GitHub Actions workflows, updates ChangesRelease automation
Sequence Diagram(s)Version gate flow: sequenceDiagram
participant pullRequest
participant versionGate
participant validateRelease
participant yq
participant gh
pullRequest->>versionGate: trigger on `release-**` branch changes to `release.yaml`
versionGate->>validateRelease: run with `github.base_ref` and org name
validateRelease->>yq: read `release.yaml` version and dependencies
validateRelease->>gh: check dependency release tags
validateRelease-->>versionGate: pass or fail with `::error::`
Pre-release flow: sequenceDiagram
participant dispatch
participant preRelease
participant setup
participant prepare
participant openPr
participant yq
participant makePrepare
participant gh
dispatch->>preRelease: version and optional source branch
preRelease->>setup: validate version and compute `release-{MAJOR}.{MINOR}`
setup->>prepare: create release branch if missing
prepare->>yq: set `.dns-operator.version` in `release.yaml`
prepare->>makePrepare: generate release files
prepare->>openPr: push `pre-release-v{VERSION}`
openPr->>gh: create PR into the release branch
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/scripts/validate-release-yaml.sh:
- Around line 13-18: The release YAML validation in validate-release-yaml.sh
only rejects 0.0.0 on non-main branches and does not enforce the release-branch
contract. Update the script to reuse .github/scripts/parse-version.sh for the
VERSION value, read its release-branch output, and compare it against BRANCH so
the gate fails when release.yaml does not match the target release branch. Keep
the existing BRANCH and VERSION checks, but add the metadata mismatch validation
in the same validation flow.
In @.github/workflows/pre-release.yaml:
- Around line 90-94: The Install yq step currently downloads an unpinned binary
from releases/latest, which should be hardened. Update the workflow to fetch a
specific yq release version instead of latest, and add a checksum verification
step for the downloaded binary before making it executable. Use the existing
Install yq job step as the place to pin the version and validate integrity with
the upstream SHA256 for that exact release.
- Around line 31-35: The pre-release workflow is using floating action tags in
privileged jobs, which should be pinned to full commit SHAs. Update every
`uses:` entry in the workflow, including the `actions/checkout` steps and the
`actions/setup-go` step, to reference their current stable commit SHA instead of
`@v4`/`@v5`. Keep the existing step structure and inputs intact while changing
only the action references.
- Around line 20-22: The workflow currently grants both permissions at the
workflow level, so every job inherits unnecessary access. Move the permissions
for the pre-release workflow into the specific jobs instead: give `contents:
write` only to the `setup` and `prepare-release` jobs, and give `pull-requests:
write` only to the `open-pr` job. Keep the permissions scoped to the relevant
job definitions in the workflow rather than the top-level `permissions` block.
In @.github/workflows/release.yaml:
- Around line 99-120: The tag job currently creates and pushes the official
v${VERSION} tag before the release artefacts are fully published, so move tag
creation out of the early “Create and push tag” step and into the end of the
workflow or the final publication job. Keep the existing tag-exists check and
git tag/git push logic, but only run it after the image, chart, binary, and
GitHub Release steps have all succeeded so the release tag cannot be published
ahead of an incomplete release.
- Around line 33-35: The release workflow is re-checking out a moving branch
tip, which can cause different jobs to build and publish from different
revisions. Update the release flow so the read-version job captures the exact
commit once using the checked-out HEAD, exposes it as an output, and then have
the later checkout steps in the release jobs use that fixed SHA instead of
inputs.release-branch. Also replace the build metadata references that currently
use github.sha so the tag, smoke tests, and published artefacts all point to the
same frozen commit.
- Line 33: The release workflow still uses mutable action tags, so update every
`uses:` entry in the workflow to a full commit SHA instead of versions like
actions/checkout@v4. Apply this to each action reference in the release
pipeline, keeping the same action names but replacing the tag with the pinned
SHA so the workflow remains stable and reviewable.
- Around line 15-16: The workflow currently grants write access too broadly and
leaves checkout credentials persisted in jobs that do not need push access.
Change the top-level permissions in release.yaml to contents: read, then add a
job-level permissions override with contents: write only for the tag and
create-release jobs. Also update each actions/checkout@v4 step in read-version,
smoke-tests, and all build-* jobs to set persist-credentials: false so no write
token is stored in .git/config.
- Around line 37-41: The release workflow’s yq installation step is pulling an
unpinned binary from the latest release, so replace the wget-based install in
the “Install yq” step with the repository’s existing make yq target. Update the
workflow job to use the same pinned, verified yq build path already defined in
the repo, and remove the direct download/chmod commands so the release process
stays reproducible.
In @.github/workflows/version-gate.yaml:
- Line 17: The workflow currently uses the floating tag reference for
actions/checkout in the version-gate job, so hard-pin that action to a specific
full commit SHA instead of v4. Update the checkout step in version-gate to
reference the exact commit for actions/checkout, keeping the step name and usage
unchanged so the release-gate workflow remains stable and supply-chain
controlled.
- Around line 19-23: The Install yq step in the version-gate workflow is pulling
from releases/latest without integrity verification. Update that step to
download a specific yq release version instead of latest, and add a checksum
verification step against the official SHA256 for that same version before
making it executable. Use the existing “Install yq” step in version-gate.yaml as
the place to pin the version and validate the download.
In `@docs/RELEASE.md`:
- Around line 12-13: The version-gate description in release docs is too broad
and should explicitly mention the path restriction. Update the wording around
the release.yaml source of truth and the version gate so it says the CI check
only runs on pull requests to release branches when release.yaml changes,
matching the actual behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cac64da5-ac56-44b6-8ab1-a3a80804a15a
📒 Files selected for processing (10)
.github/scripts/parse-version.sh.github/scripts/validate-release-yaml.sh.github/workflows/build-images-for-tag-release.yaml.github/workflows/pre-release.yaml.github/workflows/release-helm-chart.yaml.github/workflows/release.yaml.github/workflows/upload-cli.yml.github/workflows/version-gate.yamldocs/RELEASE.mdrelease.yaml
💤 Files with no reviewable changes (3)
- .github/workflows/build-images-for-tag-release.yaml
- .github/workflows/upload-cli.yml
- .github/workflows/release-helm-chart.yaml
| tag: | ||
| needs: [read-version, smoke-tests] | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ inputs.release-branch }} | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Create and push tag | ||
| env: | ||
| VERSION: ${{ needs.read-version.outputs.version }} | ||
| run: | | ||
| TAG="v${VERSION}" | ||
| if git rev-parse "$TAG" >/dev/null 2>&1; then | ||
| echo "::error::Tag $TAG already exists" | ||
| exit 1 | ||
| fi | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git tag -a "$TAG" -m "Release $TAG" | ||
| git push origin "$TAG" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Create the Git tag only after the release artefacts are ready.
Line 120 pushes the official v${VERSION} tag before any image, chart, binary, or GitHub Release step has succeeded. If a later job fails, you are left with a published release tag but an incomplete release, and a fresh rerun will then trip the existing-tag checks.
Because the build jobs do not check out the tag anyway, move tag creation to the end of the workflow or fold it into the final publication step.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 103-106: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 103-103: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yaml around lines 99 - 120, The tag job currently
creates and pushes the official v${VERSION} tag before the release artefacts are
fully published, so move tag creation out of the early “Create and push tag”
step and into the end of the workflow or the final publication job. Keep the
existing tag-exists check and git tag/git push logic, but only run it after the
image, chart, binary, and GitHub Release steps have all succeeded so the release
tag cannot be published ahead of an incomplete release.
| validate-release-yaml: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🌐 Web query:
latest stable commit SHA for actions/checkout@v4
💡 Result:
The latest stable release for actions/checkout@v4 is version v4.3.1 [1][2]. The commit SHA associated with the v4.3.1 tag is 34e114876b [2][3][4]. While there are newer major versions available (such as v6 and v7), v4.3.1 remains the latest release within the v4 release line [1][5][6]. It is recommended to use the tag or the full commit SHA when pinning actions for security and stability [7].
Citations:
- 1: https://github.com/actions/checkout/releases
- 2: https://redirect.github.com/actions/checkout/releases/tag/v4.3.1
- 3: actions/checkout@v4.3.0...v4.3.1
- 4: https://git.cxtech.cc/actions/checkout/compare/v4.1.1..v4.3.1
- 5: https://github.com/actions/checkout/releases/tag/v7.0.0
- 6: https://github.com/actions/checkout/releases/tag/v6.0.3
- 7: https://github.com/actions/checkout/blob/v4/CHANGELOG.md
🏁 Script executed:
#!/bin/bash
# Verify the snippet in the file matches the concern and check if a SHA-based usage is already present elsewhere
cat -n .github/workflows/version-gate.yaml | grep -A1 -B1 "checkout@"Repository: Kuadrant/dns-operator
Length of output: 226
🌐 Web query:
actions/checkout v4.3.1 commit SHA
💡 Result:
The commit SHA associated with the v4.3.1 release of the actions/checkout GitHub Action is 34e114876b5c3288d6bf963e6e7368d50f55963b [1][2][3]. It is officially referenced in the repository as 34e1148 [1][2].
Citations:
- 1: https://redirect.github.com/actions/checkout/releases/tag/v4.3.1
- 2: actions/checkout@v4.3.0...v4.3.1
- 3: https://git.cxtech.cc/actions/checkout/compare/v4.1.1..v4.3.1
Hard-pin the action reference to a specific commit SHA.
actions/checkout@v4 currently resolves to a floating tag. Pinning it to the full commit SHA (e.g. 34e114876b5c3288d6bf963e6e7368d50f55963b) prevents upstream tag retags from altering the release-gate behaviour without a repository diff, maintaining strict supply-chain control.
Recommended change
- - uses: actions/checkout@v4
+ - uses: actions/checkout@34e114876b5c3288d6bf963e6e7368d50f55963b📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@34e114876b5c3288d6bf963e6e7368d50f55963b |
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 17-17: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/version-gate.yaml at line 17, The workflow currently uses
the floating tag reference for actions/checkout in the version-gate job, so
hard-pin that action to a specific full commit SHA instead of v4. Update the
checkout step in version-gate to reference the exact commit for
actions/checkout, keeping the step name and usage unchanged so the release-gate
workflow remains stable and supply-chain controlled.
Source: Linters/SAST tools
| - name: Install yq | ||
| run: | | ||
| sudo wget -qO /usr/local/bin/yq \ | ||
| https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 | ||
| sudo chmod +x /usr/local/bin/yq |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
Pin yq to a specific version and verify checksum
Fetching yq from releases/latest introduces non-determinism and bypasses integrity checks. The installation should target a specific version (e.g. v4.53.3) and validate the SHA256 checksum against the official release assets.
Show diff
- name: Install yq
run: |
- sudo wget -qO /usr/local/bin/yq \
- https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
+ YQ_VERSION="v4.53.3"
+ wget -qO yq_linux_amd64 \
+ https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64
+ wget -qO checksums \
+ https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/checksums
+ grep "yq_linux_amd64" checksums | sha256sum -c -
sudo chmod +x /usr/local/bin/yq🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/version-gate.yaml around lines 19 - 23, The Install yq
step in the version-gate workflow is pulling from releases/latest without
integrity verification. Update that step to download a specific yq release
version instead of latest, and add a checksum verification step against the
official SHA256 for that same version before making it executable. Use the
existing “Install yq” step in version-gate.yaml as the place to pin the version
and validate the download.
| A `release.yaml` file at the repository root is the machine-readable source of truth for the component version. | ||
| A **version gate** CI check validates this file on pull requests to release branches. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Tighten the version-gate scope wording.
This reads as though every PR to a release branch is checked, but the workflow only fires when release.yaml changes. Please call out the path restriction so the docs match the actual gate.
Suggested wording
- A **version gate** CI check validates this file on pull requests to release branches.
+ A **version gate** CI check validates `release.yaml` on pull requests to `release-*` branches when that file changes.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| A `release.yaml` file at the repository root is the machine-readable source of truth for the component version. | |
| A **version gate** CI check validates this file on pull requests to release branches. | |
| A `release.yaml` file at the repository root is the machine-readable source of truth for the component version. | |
| A **version gate** CI check validates `release.yaml` on pull requests to `release-*` branches when that file changes. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/RELEASE.md` around lines 12 - 13, The version-gate description in
release docs is too broad and should explicitly mention the path restriction.
Update the wording around the release.yaml source of truth and the version gate
so it says the CI check only runs on pull requests to release branches when
release.yaml changes, matching the actual behavior.
Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
Summary
Replaces the existing ad-hoc release workflows with a structured two-phase release process as defined in the Two-Phase Release Workflow RFC. This introduces a machine-readable
release.yamlas the version source of truth, a pre-release workflow that prepares and opens a PR for review, and a consolidated release workflow that handles tagging, image builds, artifact packaging, and GitHub Release creation in a single run.Changes
New two-phase workflow
The release process is now split into two explicit phases with a human review gate between them:
pre-release.yaml): Aworkflow_dispatchworkflow that creates a release branch (if needed), updatesrelease.yamlwith the target version, runsmake prepare-release, and opens a pull request against the release branch for review.release.yaml): Aworkflow_dispatchworkflow that reads the version fromrelease.yaml, runs smoke tests (verify-manifests, verify-bundle, verify-helm-build, unit tests), creates a git tag, builds and pushes all container images (operator, bundle, catalog, CoreDNS), packages and signs the Helm chart, builds CLI binaries for all platforms, and creates the GitHub Release with all artifacts attached.Version gate
A new
version-gate.yamlCI check validatesrelease.yamlon pull requests to release branches. It verifies that the version is not0.0.0on non-main branches and that any declared dependencies have corresponding published releases.Shared scripts
Version parsing and validation logic is extracted into reusable shell scripts under
.github/scripts/:parse-version.shextracts and validates semver components fromrelease.yamlvalidate-release-yaml.shvalidates version constraints and dependency releasesConsolidated artifact builds
The release workflow now builds all release artifacts in a single coordinated run, including CoreDNS images and CLI binaries which were previously handled separately. CLI binaries are built directly with
go buildinstead of relying on a third-party GitHub Action.Removed workflows
Three workflows that were triggered by tag pushes or release events are removed, as their functionality is subsumed by the new consolidated release workflow:
build-images-for-tag-release.yamlrelease-helm-chart.yamlupload-cli.ymlUpdated documentation
docs/RELEASE.mdis rewritten to document the new two-phase process, including step-by-step instructions for minor and patch releases, a table of release artifacts, documentation ofrelease.yamlformat, and required GitHub secrets.Testing
Due to hardcoded routes in the existing workflows, a full end-to-end test in the Kuadrant org is not possible without merging. However, the workflows have been tested in a fork:
The failures in the release workflow run are caused by hardcoded values (registry org, repository owner checks) and are expected to pass when run in the Kuadrant org.
Summary by CodeRabbit