Add two-phase release process with automated workflows#494
Conversation
|
Warning Review limit reached
More reviews will be available in 30 minutes and 3 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughThis PR adds release metadata parsing and validation, new pre-release and release workflows, reusable image-building support, and updated release documentation and crate publishing settings. ChangesRelease Automation Pipeline
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 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: 5
🧹 Nitpick comments (4)
.github/workflows/release.yaml (2)
32-36: ⚡ Quick winConsider using a yq GitHub Action or verifying the download checksum.
Downloading
yqdirectly from GitHub releases without checksum verification could expose the workflow to supply chain risks. This is the same pattern used inpre-release.yaml.🔒 Alternative approaches
Option 1: Use a community action
- uses: mikefarah/yq@v4.34.2Option 2: Verify checksum
- name: Install yq run: | sudo wget --quiet --output-document=/usr/local/bin/yq \ https://github.com/mikefarah/yq/releases/download/v4.34.2/yq_linux_amd64 echo "expected_sha256 /usr/local/bin/yq" | sha256sum --check 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/release.yaml around lines 32 - 36, The "Install yq" step currently downloads yq binary directly without verification; update that step (the step named "Install yq") to either use the official GitHub Action (replace the run block with uses: mikefarah/yq@v4.34.2) or, if keeping the direct download, add a checksum verification after download (compute and check the expected SHA256 for /usr/local/bin/yq before chmod +x) to ensure integrity and mitigate supply-chain risk.
159-162: 🏗️ Heavy liftConsider migrating to trusted publishing for crates.io.
Using
CARGO_REGISTRY_TOKENrequires managing a long-lived secret. Crates.io supports OIDC-based trusted publishing, which eliminates the need for secrets and provides better security through short-lived tokens.See: https://doc.rust-lang.org/cargo/reference/publishing.html#trusted-publishing
🤖 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 159 - 162, The current workflow step "Publish to crates.io" uses a long‑lived secret via the CARGO_REGISTRY_TOKEN env variable and runs `cargo publish --package limitador`; replace this with OIDC trusted publishing by removing the CARGO_REGISTRY_TOKEN usage and updating the step to request short‑lived tokens via GitHub Actions OIDC (enable id-token and use the cargo/registry publish pattern supported by crates.io), adjust the step named "Publish to crates.io" to request id-token: write permissions and perform `cargo publish --package limitador` without reading CARGO_REGISTRY_TOKEN, and ensure the workflow uses the recommended OIDC configuration per the crates.io trusted publishing docs..github/workflows/build-image.yaml (1)
112-119: 💤 Low valueConsider making the tag selection logic more explicit.
The current implementation checks
inputs.tag == ''to determine whether to use the provided tag or generate one based on the trigger. Whilst this works (optional string inputs default to empty string), the logic could be clearer by checking the event type explicitly.♻️ Alternative approach
tags: | # When called from release workflow, use the provided tag - type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != '' }} + type=raw,value=${{ inputs.tag }},enable=${{ github.event_name == 'workflow_call' && inputs.tag != '' }} # SHA tag for main branch - type=raw,value=${{ github.sha }},enable=${{ inputs.tag == '' && github.ref_name == env.MAIN_BRANCH_NAME }} + type=raw,value=${{ github.sha }},enable=${{ github.event_name != 'workflow_call' && github.ref_name == env.MAIN_BRANCH_NAME }} # set latest tag for main branch - type=raw,value=latest,enable=${{ inputs.tag == '' && github.ref_name == env.MAIN_BRANCH_NAME }} + type=raw,value=latest,enable=${{ github.event_name != 'workflow_call' && github.ref_name == env.MAIN_BRANCH_NAME }} # set ref name tag for non-main branches - type=raw,value=${{ github.ref_name }},enable=${{ inputs.tag == '' && github.ref_name != env.MAIN_BRANCH_NAME }} + type=raw,value=${{ github.ref_name }},enable=${{ github.event_name != 'workflow_call' && github.ref_name != env.MAIN_BRANCH_NAME }}🤖 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/build-image.yaml around lines 112 - 119, The tag selection block that currently relies on inputs.tag == '' is ambiguous; update the conditional logic to explicitly detect a provided release tag or a release event by using github.event_name and inputs.tag presence: when inputs.tag is non-empty (inputs.tag != '') use that value, else if github.event_name == 'release' use github.event.release.tag_name, else if github.ref_name == env.MAIN_BRANCH_NAME emit both github.sha and latest as before, else use github.ref_name for branch-based tags—apply these checks to the four type=raw entries (the tag selection lines) so the intent is explicit and correct..github/workflows/pre-release.yaml (1)
95-99: ⚡ Quick winConsider using a yq GitHub Action or verifying the download checksum.
Downloading
yqdirectly from GitHub releases without checksum verification could expose the workflow to supply chain risks if the release is compromised or the download is intercepted.🔒 Alternative approaches
Option 1: Use a community action
- uses: mikefarah/yq@v4.34.2Option 2: Verify checksum
- name: Install yq run: | sudo wget --quiet --output-document=/usr/local/bin/yq \ https://github.com/mikefarah/yq/releases/download/v4.34.2/yq_linux_amd64 echo "expected_sha256 /usr/local/bin/yq" | sha256sum --check 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/pre-release.yaml around lines 95 - 99, The workflow step named "Install yq" currently downloads yq_linux_amd64 directly; replace this with a safer approach by either using the official GitHub Action (mikefarah/yq@v4.34.2) instead of manual wget, or keep the manual install but add checksum verification before chmod (compute/verify the expected SHA256 for the v4.34.2 binary and run sha256sum --check on the downloaded file), and ensure the step logs which approach it used for traceability.
🤖 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/README.md:
- Around line 39-49: The fenced code block showing version/major/minor/patch
values is missing a language identifier causing markdownlint MD040; update the
opening fence from ``` to ```text to explicitly mark it as a text block so the
linter passes and the block renders correctly, i.e., modify the fence that
precedes the lines "version=2.5.0" ... "crate-patch=0" in the README.md snippet.
In @.github/scripts/validate-release-yaml.sh:
- Around line 13-35: The current checks in validate-release-yaml.sh only reject
"0.0.0" and "-dev" but allow null/empty or malformed versions; update the
validation for VERSION and CRATE_VERSION (the variables set from yq) to also
fail when the value is null/empty and to enforce a basic semver pattern (e.g.
major.minor.patch with optional prerelease/build parts) using a regex match;
modify the existing branch-release block that references VERSION and
CRATE_VERSION so it first checks for empty/null values and then applies the
semver regex before the existing "0.0.0" and "-dev" checks, making sure the
script exits with the same error pattern when the checks fail.
- Around line 38-41: The current lookup builds a dot-path via yq
".dependencies.${dep}" which fails for keys with characters like '-' — update
the dep_version lookup to use bracketed key indexing with yq and strenv: export
the loop variable into an environment variable (e.g., DEP="$dep") and call yq
with the expression ".dependencies[strenv(DEP)]" (using the same RELEASE_YAML
variable) so keys are matched exactly; adjust the dep_version assignment in the
for-loop that defines DEPS/dep to export DEP and use the bracketed strenv lookup
instead of the dot-path.
In @.github/workflows/build-image.yaml:
- Around line 11-14: The workflow input "tag" is incorrectly marked required:
true while downstream logic expects an optional value; update the "tag" input
definition (the input named tag) to not be required (set required: false) and
add a default: '' (empty string) so inputs.tag is defined when omitted, ensuring
the tag-generation logic that checks inputs.tag != '' works without validation
errors.
In @.github/workflows/version-gate.yaml:
- Line 18: Replace the floating ref for actions/checkout (currently
"actions/checkout@v6") with the specific v6 commit SHA and add the checkout
input persist-credentials: false; specifically update the checkout step that
references actions/checkout@v6 to use the exact commit SHA for v6 and include
persist-credentials: false under that step so the job does not retain Git
credentials and the action is pinned to a fixed commit.
---
Nitpick comments:
In @.github/workflows/build-image.yaml:
- Around line 112-119: The tag selection block that currently relies on
inputs.tag == '' is ambiguous; update the conditional logic to explicitly detect
a provided release tag or a release event by using github.event_name and
inputs.tag presence: when inputs.tag is non-empty (inputs.tag != '') use that
value, else if github.event_name == 'release' use github.event.release.tag_name,
else if github.ref_name == env.MAIN_BRANCH_NAME emit both github.sha and latest
as before, else use github.ref_name for branch-based tags—apply these checks to
the four type=raw entries (the tag selection lines) so the intent is explicit
and correct.
In @.github/workflows/pre-release.yaml:
- Around line 95-99: The workflow step named "Install yq" currently downloads
yq_linux_amd64 directly; replace this with a safer approach by either using the
official GitHub Action (mikefarah/yq@v4.34.2) instead of manual wget, or keep
the manual install but add checksum verification before chmod (compute/verify
the expected SHA256 for the v4.34.2 binary and run sha256sum --check on the
downloaded file), and ensure the step logs which approach it used for
traceability.
In @.github/workflows/release.yaml:
- Around line 32-36: The "Install yq" step currently downloads yq binary
directly without verification; update that step (the step named "Install yq") to
either use the official GitHub Action (replace the run block with uses:
mikefarah/yq@v4.34.2) or, if keeping the direct download, add a checksum
verification after download (compute and check the expected SHA256 for
/usr/local/bin/yq before chmod +x) to ensure integrity and mitigate supply-chain
risk.
- Around line 159-162: The current workflow step "Publish to crates.io" uses a
long‑lived secret via the CARGO_REGISTRY_TOKEN env variable and runs `cargo
publish --package limitador`; replace this with OIDC trusted publishing by
removing the CARGO_REGISTRY_TOKEN usage and updating the step to request
short‑lived tokens via GitHub Actions OIDC (enable id-token and use the
cargo/registry publish pattern supported by crates.io), adjust the step named
"Publish to crates.io" to request id-token: write permissions and perform `cargo
publish --package limitador` without reading CARGO_REGISTRY_TOKEN, and ensure
the workflow uses the recommended OIDC configuration per the crates.io trusted
publishing docs.
🪄 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: 92ad8861-8318-4ba7-8b9b-a88d49a4b3c6
📒 Files selected for processing (10)
.github/scripts/README.md.github/scripts/parse-version.sh.github/scripts/validate-release-yaml.sh.github/workflows/build-image.yaml.github/workflows/pre-release.yaml.github/workflows/release.yaml.github/workflows/version-gate.yamlRELEASE.mdlimitador-server/Cargo.tomlrelease.yaml
| ``` | ||
| version=2.5.0 | ||
| major=2 | ||
| minor=5 | ||
| patch=0 | ||
| release-branch=release-2.5 | ||
| crate-version=0.13.0 | ||
| crate-major=0 | ||
| crate-minor=13 | ||
| crate-patch=0 | ||
| ``` |
There was a problem hiding this comment.
Specify the fenced-code language for the expected output block.
Line 39 opens a fence without a language identifier, which will keep markdownlint MD040 failing.
Suggested patch
-```
+```text
version=2.5.0
major=2
minor=5
@@
crate-minor=13
crate-patch=0</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>
[warning] 39-39: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
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/scripts/README.md around lines 39 - 49, The fenced code block
showing version/major/minor/patch values is missing a language identifier
causing markdownlint MD040; update the opening fence from totext to
explicitly mark it as a text block so the linter passes and the block renders
correctly, i.e., modify the fence that precedes the lines "version=2.5.0" ...
"crate-patch=0" in the README.md snippet.
</details>
<!-- fingerprinting:phantom:poseidon:hawk -->
<!-- cr-comment:v1:7b90f9e6996194495610fec1 -->
_Source: Linters/SAST tools_
<!-- This is an auto-generated comment by CodeRabbit -->
| VERSION=$(yq '.limitador.version' "$RELEASE_YAML") | ||
| CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML") | ||
|
|
||
| if [[ "$BRANCH" =~ ^release- ]]; then | ||
| if [[ "$VERSION" == "0.0.0" ]]; then | ||
| echo "::error::release.yaml version is 0.0.0 on branch '$BRANCH' -- must specify a release version on release branches" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "$VERSION" == *-dev* ]]; then | ||
| echo "::error::release.yaml version '${VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "$CRATE_VERSION" == "0.0.0" ]]; then | ||
| echo "::error::release.yaml crate-version is 0.0.0 on branch '$BRANCH' -- must specify a crate version on release branches" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "$CRATE_VERSION" == *-dev* ]]; then | ||
| echo "::error::release.yaml crate-version '${CRATE_VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
Enforce required/non-null semver checks in the gate, not only sentinel/dev checks.
Line 16-Line 35 rejects 0.0.0 and -dev, but null or malformed values can still pass this workflow and only fail later.
Suggested patch
VERSION=$(yq '.limitador.version' "$RELEASE_YAML")
CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML")
+
+if [[ -z "$VERSION" || "$VERSION" == "null" ]]; then
+ echo "::error::No version found in $RELEASE_YAML under limitador.version"
+ exit 1
+fi
+if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
+ echo "::error::Invalid semver for version: $VERSION"
+ exit 1
+fi
+
+if [[ -z "$CRATE_VERSION" || "$CRATE_VERSION" == "null" ]]; then
+ echo "::error::No crate-version found in $RELEASE_YAML under limitador.crate-version"
+ exit 1
+fi
+if ! [[ "$CRATE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
+ echo "::error::Invalid semver for crate-version: $CRATE_VERSION"
+ exit 1
+fi📝 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.
| VERSION=$(yq '.limitador.version' "$RELEASE_YAML") | |
| CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML") | |
| if [[ "$BRANCH" =~ ^release- ]]; then | |
| if [[ "$VERSION" == "0.0.0" ]]; then | |
| echo "::error::release.yaml version is 0.0.0 on branch '$BRANCH' -- must specify a release version on release branches" | |
| exit 1 | |
| fi | |
| if [[ "$VERSION" == *-dev* ]]; then | |
| echo "::error::release.yaml version '${VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == "0.0.0" ]]; then | |
| echo "::error::release.yaml crate-version is 0.0.0 on branch '$BRANCH' -- must specify a crate version on release branches" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == *-dev* ]]; then | |
| echo "::error::release.yaml crate-version '${CRATE_VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | |
| exit 1 | |
| fi | |
| VERSION=$(yq '.limitador.version' "$RELEASE_YAML") | |
| CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML") | |
| if [[ -z "$VERSION" || "$VERSION" == "null" ]]; then | |
| echo "::error::No version found in $RELEASE_YAML under limitador.version" | |
| exit 1 | |
| fi | |
| if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| echo "::error::Invalid semver for version: $VERSION" | |
| exit 1 | |
| fi | |
| if [[ -z "$CRATE_VERSION" || "$CRATE_VERSION" == "null" ]]; then | |
| echo "::error::No crate-version found in $RELEASE_YAML under limitador.crate-version" | |
| exit 1 | |
| fi | |
| if ! [[ "$CRATE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then | |
| echo "::error::Invalid semver for crate-version: $CRATE_VERSION" | |
| exit 1 | |
| fi | |
| if [[ "$BRANCH" =~ ^release- ]]; then | |
| if [[ "$VERSION" == "0.0.0" ]]; then | |
| echo "::error::release.yaml version is 0.0.0 on branch '$BRANCH' -- must specify a release version on release branches" | |
| exit 1 | |
| fi | |
| if [[ "$VERSION" == *-dev* ]]; then | |
| echo "::error::release.yaml version '${VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == "0.0.0" ]]; then | |
| echo "::error::release.yaml crate-version is 0.0.0 on branch '$BRANCH' -- must specify a crate version on release branches" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == *-dev* ]]; then | |
| echo "::error::release.yaml crate-version '${CRATE_VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'" | |
| exit 1 | |
| fi |
🤖 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/scripts/validate-release-yaml.sh around lines 13 - 35, The current
checks in validate-release-yaml.sh only reject "0.0.0" and "-dev" but allow
null/empty or malformed versions; update the validation for VERSION and
CRATE_VERSION (the variables set from yq) to also fail when the value is
null/empty and to enforce a basic semver pattern (e.g. major.minor.patch with
optional prerelease/build parts) using a regex match; modify the existing
branch-release block that references VERSION and CRATE_VERSION so it first
checks for empty/null values and then applies the semver regex before the
existing "0.0.0" and "-dev" checks, making sure the script exits with the same
error pattern when the checks fail.
| DEPS=$(yq '.dependencies | keys | .[]' "$RELEASE_YAML" 2>/dev/null || true) | ||
| for dep in $DEPS; do | ||
| dep_version=$(yq ".dependencies.${dep}" "$RELEASE_YAML") | ||
| if [[ "$dep_version" != "0.0.0" && "$dep_version" != "null" && -n "$dep_version" ]]; then |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat > /tmp/release-deps.yaml <<'EOF'
dependencies:
some-repo: "1.2.3"
EOF
dep="some-repo"
echo "Current query:"
yq ".dependencies.${dep}" /tmp/release-deps.yaml || true
echo "Indexed query:"
DEP="$dep" yq '.dependencies[strenv(DEP)]' /tmp/release-deps.yamlRepository: Kuadrant/limitador
Length of output: 196
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show the relevant portion of the script
sed -n '1,120p' .github/scripts/validate-release-yaml.shRepository: Kuadrant/limitador
Length of output: 1753
🌐 Web query:
mikefarah yq strenv(DEP) .dependencies[strenv(DEP)] syntax env var indexed key access
💡 Result:
To perform dynamic key access using an environment variable in mikefarah/yq, you must use the bracketed index syntax:.[env(VAR_NAME)] or.[strenv(VAR_NAME)] [1][2]. When you need to access a property dynamically, placing the environment variable operation inside square brackets tells yq to treat the result of that operation as a path or key [3]. Examples: 1. Dynamic lookup: To select a field where the key is stored in an environment variable named DEP: DEP="some_key" yq '.[env(DEP)]' file.yaml [1][2] 2. Updating a key: To assign a value to a dynamic key: DEP="new_key" yq -i '.[env(DEP)] = "new_value"' file.yaml [2] Important Notes: - env(VAR) vs strenv(VAR): env parses the variable value as a YAML node (which can be a map, array, etc.), while strenv(VAR) forces the variable to be treated strictly as a string [1][4]. - Nested Paths: Dynamic key lookup using env/strenv works for a single level [5]. If you need to access a nested path stored in a single environment variable (e.g., NODE="a.b"), you cannot simply use.[env(NODE)]. Instead, you must split the path and reduce it [5]: NODE="a.b" yq '(strenv(NODE) | split(".") |.[]) as $i ireduce (.;.[$i])' file.yaml [5] - Complex Paths: If your environment variable contains a full dot-notation path (e.g.,.key1.key2), use eval with strenv to force evaluation [6]: export KEY=.key1.key2; yq -n 'eval(strenv(KEY))="value"' [6]
Citations:
- 1: https://mikefarah.gitbook.io/yq/operators/env-variable-operators
- 2: Update/Rename Key using Environment Variables mikefarah/yq#1134
- 3: Unable to work with vars in bash script mikefarah/yq#1122
- 4: https://github.com/mikefarah/yq/blob/v4.53.2/pkg/yqlib/doc/operators/env-variable-operators.md
- 5: Dynamic key lookup with environment variable not working for nested items mikefarah/yq#922
- 6: https://stackoverflow.com/questions/73680695/environment-variable-as-key-in-yq4
Fix yq dependency version lookup to use bracketed key indexing
Line 40 builds a dot-path via yq ".dependencies.${dep}", which breaks for dependency names that aren’t safe dot-notation keys (e.g., containing -). Use bracket indexing with strenv(DEP) for exact key lookup.
Suggested patch
for dep in $DEPS; do
- dep_version=$(yq ".dependencies.${dep}" "$RELEASE_YAML")
+ dep_version=$(DEP="$dep" yq '.dependencies[strenv(DEP)]' "$RELEASE_YAML")
if [[ "$dep_version" != "0.0.0" && "$dep_version" != "null" && -n "$dep_version" ]]; then📝 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.
| DEPS=$(yq '.dependencies | keys | .[]' "$RELEASE_YAML" 2>/dev/null || true) | |
| for dep in $DEPS; do | |
| dep_version=$(yq ".dependencies.${dep}" "$RELEASE_YAML") | |
| if [[ "$dep_version" != "0.0.0" && "$dep_version" != "null" && -n "$dep_version" ]]; then | |
| DEPS=$(yq '.dependencies | keys | .[]' "$RELEASE_YAML" 2>/dev/null || true) | |
| for dep in $DEPS; do | |
| dep_version=$(DEP="$dep" yq '.dependencies[strenv(DEP)]' "$RELEASE_YAML") | |
| if [[ "$dep_version" != "0.0.0" && "$dep_version" != "null" && -n "$dep_version" ]]; then |
🤖 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/scripts/validate-release-yaml.sh around lines 38 - 41, The current
lookup builds a dot-path via yq ".dependencies.${dep}" which fails for keys with
characters like '-' — update the dep_version lookup to use bracketed key
indexing with yq and strenv: export the loop variable into an environment
variable (e.g., DEP="$dep") and call yq with the expression
".dependencies[strenv(DEP)]" (using the same RELEASE_YAML variable) so keys are
matched exactly; adjust the dep_version assignment in the for-loop that defines
DEPS/dep to export DEP and use the bracketed strenv lookup instead of the
dot-path.
| tag: | ||
| description: "Image tag to apply" | ||
| required: true | ||
| type: string |
There was a problem hiding this comment.
Tag input should be optional.
The tag input is marked as required: true, but the tag generation logic in lines 113-119 treats it as optional by checking inputs.tag != ''. When this workflow is triggered via workflow_dispatch or push events, inputs.tag will be undefined, causing the workflow to fail validation.
🐛 Proposed fix
tag:
description: "Image tag to apply"
- required: true
+ required: false
type: string🤖 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/build-image.yaml around lines 11 - 14, The workflow input
"tag" is incorrectly marked required: true while downstream logic expects an
optional value; update the "tag" input definition (the input named tag) to not
be required (set required: false) and add a default: '' (empty string) so
inputs.tag is defined when omitted, ensuring the tag-generation logic that
checks inputs.tag != '' works without validation errors.
| validate-release-yaml: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
if [ ! -f "$file" ]; then
echo "Missing file: $file" >&2
exit 1
fi
# Show the full workflow with line numbers (keep output small)
nl -ba "$file" | sed -n '1,160p'Repository: Kuadrant/limitador
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
nl -ba "$file" | sed -n '1,220p'Repository: Kuadrant/limitador
Length of output: 105
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
nl -ba "$file" | sed -n '1,220p'Repository: Kuadrant/limitador
Length of output: 105
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
# Confirm file exists and show around the referenced line using cat -n
echo "== head =="
head -n 60 "$file" | cat -n
echo "== around line 18 =="
sed -n '1,120p' "$file" | cat -n | sed -n '10,40p'
echo "== actions/checkout occurrences =="
rg -n "uses:\s*actions/checkout@" "$file" || true
echo "== persist-credentials occurrences =="
rg -n "persist-credentials" "$file" || trueRepository: Kuadrant/limitador
Length of output: 2117
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
echo "== uses: in workflow =="
rg -n "uses:\s*" "$file"
echo "== validate script header =="
sed -n '1,200p' .github/scripts/validate-release-yaml.sh | cat -n
echo "== validate script checkout/git usage =="
rg -n "git |checkout|token|GH_TOKEN|GITHUB_TOKEN|persist-credentials" .github/scripts/validate-release-yaml.sh || trueRepository: Kuadrant/limitador
Length of output: 2227
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file=".github/workflows/version-gate.yaml"
echo "== uses: in workflow =="
rg -n "uses:\s*" "$file" || true
echo "== validate script (first 200 lines) =="
sed -n '1,200p' .github/scripts/validate-release-yaml.sh | cat -n
echo "== validate script token/git usage =="
rg -n "GH_TOKEN|GITHUB_TOKEN|git |checkout|persist-credentials" .github/scripts/validate-release-yaml.sh || trueRepository: Kuadrant/limitador
Length of output: 2235
Pin actions/checkout to a full commit SHA (and disable credential persistence).
Line 18 uses a floating ref (actions/checkout@v6), which weakens supply-chain guarantees; pin to the v6 commit SHA. Also set persist-credentials: false since this job doesn’t require git credentials and only uses GH_TOKEN for gh API calls.
Suggested patch
- - uses: actions/checkout@v6
+ - uses: actions/checkout@<full_commit_sha_for_v6>
+ with:
+ persist-credentials: false🧰 Tools
🪛 zizmor (1.25.2)
[warning] 18-18: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 18-18: 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 18, Replace the floating ref for
actions/checkout (currently "actions/checkout@v6") with the specific v6 commit
SHA and add the checkout input persist-credentials: false; specifically update
the checkout step that references actions/checkout@v6 to use the exact commit
SHA for v6 and include persist-credentials: false under that step so the job
does not retain Git credentials and the action is pinned to a fixed commit.
Source: Linters/SAST tools
38fcfc8 to
32ba36f
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (1)
.github/workflows/pre-release.yaml (1)
149-151: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueSet
persist-credentials: falseon checkout-only jobs.The
open-prjob (and the post-release checkout at lines 192-195) authenticate viaGH_TOKENforghand never push with git, so persisting git credentials in the checkout is unnecessary. Disabling it addresses the zizmorartipackedfinding without affecting the push-based jobs (setup,prepare-release).🔒 Proposed change
- uses: actions/checkout@v6 + with: + persist-credentials: false🤖 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/pre-release.yaml around lines 149 - 151, The checkout step in the open-pr workflow job and the later post-release checkout should not persist git credentials because those jobs only use GH_TOKEN with gh and never push via git. Update the actions/checkout usage in the checkout-only paths to set persist-credentials to false, while leaving the push-based jobs such as setup and prepare-release unchanged; use the checkout step in the pre-release workflow as the target reference.Source: Linters/SAST tools
🤖 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/workflows/release.yaml:
- Around line 20-30: The release workflow is re-checking out a mutable branch in
multiple jobs, so the release steps can drift across different commits. In the
read-version job, capture the checked-out commit SHA after actions/checkout and
expose it as an output, then update the downstream checkout steps in the
affected jobs to use that fixed SHA instead of inputs.release-branch. Keep the
version parsing, crate publish, image build, and release note generation aligned
by referencing the captured SHA from read-version and using it in the relevant
checkout/ref fields.
- Around line 135-143: The release workflow tag/publish step is not resumable
because it blindly fails on existing tags and duplicate crate versions. Update
the logic around the tag loop and crate publish/release steps to treat
already-existing artefacts as success only if they match the intended
commit/version, and to fail only when an existing tag/version points to a
different commit or release state. Use the existing release shell block in the
workflow and the tag names/version variables to locate the checks, and apply the
same resumable handling to the related steps referenced by the duplicate
comment.
- Around line 12-13: Workflow-wide contents: write is too broad; scope write
access only to the publish/tagging jobs in the release workflow. Update the
checkout steps in the read/test/publish jobs so they do not persist credentials
by default, and only enable repository write credentials where the job actually
needs to push tags or releases. Use the release workflow job names and their
checkout steps to apply the hardening consistently.
- Around line 44-56: The release workflow validation in the version-check step
only rejects the 0.0.0 sentinel, so `-dev` prerelease values can still reach
tagging and publishing. Update the validation in the version validation block
that reads `steps.parse.outputs.version` and `steps.parse.outputs.crate-version`
to also reject any `-dev` suffix, or reuse the existing release validator logic
here so both `VERSION` and `CRATE_VERSION` are blocked before any release side
effects.
- Line 28: The release workflow still references external actions by tag instead
of immutable commit SHAs, which is unsafe for a job with publish secrets and
write permissions. Update each external action usage in release.yaml, including
actions/checkout, actions-rust-lang/setup-rust-toolchain, Swatinem/rust-cache,
abelfodil/protoc-action, and supercharge/redis-github-action, to pin them to
their full commit SHA refs so the release job uses fixed, reviewable versions.
- Around line 164-170: The build-images job is currently inheriting all secrets
through the reusable workflow call, which is too broad; update the release
workflow to pass only the registry credentials needed by the reusable
build-image.yaml workflow. Replace the broad secret inheritance in build-images
with explicit secret mapping for IMG_REGISTRY_USERNAME and IMG_REGISTRY_TOKEN so
the reusable workflow only receives those two values.
- Around line 81-117: Add a manifest/version consistency check to the release
workflow so it cannot proceed when release metadata and crate versions diverge.
Update the smoke-tests job in release.yaml to compare the version read from
read-version with the versions in limitador/Cargo.toml and the server manifest
before the Publish dry-run step. Make the check fail fast if any manifest
disagrees, using the existing release metadata and cargo-published crate as the
comparison points.
---
Nitpick comments:
In @.github/workflows/pre-release.yaml:
- Around line 149-151: The checkout step in the open-pr workflow job and the
later post-release checkout should not persist git credentials because those
jobs only use GH_TOKEN with gh and never push via git. Update the
actions/checkout usage in the checkout-only paths to set persist-credentials to
false, while leaving the push-based jobs such as setup and prepare-release
unchanged; use the checkout step in the pre-release workflow as the target
reference.
🪄 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: 03785948-6dab-4da6-b75b-c5d1452ab1ab
📒 Files selected for processing (11)
.github/scripts/README.md.github/scripts/parse-version.sh.github/scripts/validate-release-yaml.sh.github/workflows/build-image.yaml.github/workflows/pre-release.yaml.github/workflows/release.yaml.github/workflows/version-gate.yamlREADME.mdRELEASE.mdlimitador-server/Cargo.tomlrelease.yaml
✅ Files skipped from review due to trivial changes (2)
- README.md
- limitador-server/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (2)
- release.yaml
- .github/scripts/validate-release-yaml.sh
| permissions: | ||
| contents: write |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Scope write credentials to the jobs that need them.
contents: write is currently granted workflow-wide, and checkout persists credentials by default. That gives read/test/publish steps unnecessary repository write credentials while they run branch-controlled code.
Suggested hardening
permissions:
- contents: write
+ contents: read
@@
tag:
needs: [read-version, smoke-tests]
runs-on: ubuntu-latest
+ permissions:
+ contents: write
@@
create-release:
needs: [read-version, publish-crate, build-images]
runs-on: ubuntu-latest
+ permissions:
+ contents: writeFor checkout steps that do not push tags, also add:
- uses: actions/checkout@v6
with:
ref: ${{ needs.read-version.outputs.commit-sha }}
+ persist-credentials: falseAlso applies to: 28-30, 85-87, 149-151, 176-178
🧰 Tools
🪛 zizmor (1.26.1)
[error] 13-13: overly broad permissions (excessive-permissions): contents: write is overly broad at the workflow level
(excessive-permissions)
🤖 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 12 - 13, Workflow-wide contents:
write is too broad; scope write access only to the publish/tagging jobs in the
release workflow. Update the checkout steps in the read/test/publish jobs so
they do not persist credentials by default, and only enable repository write
credentials where the job actually needs to push tags or releases. Use the
release workflow job names and their checkout steps to apply the hardening
consistently.
Source: Linters/SAST tools
| read-version: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| version: ${{ steps.parse.outputs.version }} | ||
| crate-version: ${{ steps.parse.outputs.crate-version }} | ||
| major: ${{ steps.parse.outputs.major }} | ||
| minor: ${{ steps.parse.outputs.minor }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ inputs.release-branch }} |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Pin the release run to one commit SHA.
Each job re-checks out the mutable release branch. If the branch advances after read-version, the parsed versions, tags, crate publish, image build, and release notes can refer to different commits. Capture the checked-out SHA once and use it downstream.
Suggested fix
outputs:
version: ${{ steps.parse.outputs.version }}
crate-version: ${{ steps.parse.outputs.crate-version }}
major: ${{ steps.parse.outputs.major }}
minor: ${{ steps.parse.outputs.minor }}
+ commit-sha: ${{ steps.release-rev.outputs.commit-sha }}
@@
- uses: actions/checkout@v6
with:
ref: ${{ inputs.release-branch }}
+
+ - name: Capture release commit
+ id: release-rev
+ run: echo "commit-sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
@@
- ref: ${{ inputs.release-branch }}
+ ref: ${{ needs.read-version.outputs.commit-sha }}
@@
- ref: ${{ inputs.release-branch }}
+ ref: ${{ needs.read-version.outputs.commit-sha }}Also applies to: 85-87, 122-125, 149-151, 168-169, 176-178
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 28-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 28-28: 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 20 - 30, The release workflow is
re-checking out a mutable branch in multiple jobs, so the release steps can
drift across different commits. In the read-version job, capture the checked-out
commit SHA after actions/checkout and expose it as an output, then update the
downstream checkout steps in the affected jobs to use that fixed SHA instead of
inputs.release-branch. Keep the version parsing, crate publish, image build, and
release note generation aligned by referencing the captured SHA from
read-version and using it in the relevant checkout/ref fields.
| major: ${{ steps.parse.outputs.major }} | ||
| minor: ${{ steps.parse.outputs.minor }} | ||
| steps: | ||
| - uses: actions/checkout@v6 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Lists external action refs in this workflow. Expect each to be pinned to a full 40-character SHA.
rg -n 'uses:\s+[^./][^@\s]+@[^#\s]+' .github/workflows/release.yamlRepository: Kuadrant/limitador
Length of output: 647
Pin the workflow’s external actions to full commit SHAs. .github/workflows/release.yaml still uses tag-based refs for every external action (actions/checkout, actions-rust-lang/setup-rust-toolchain, Swatinem/rust-cache, abelfodil/protoc-action, supercharge/redis-github-action). This release job has publishing secrets and write permissions, so immutable SHAs are required.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 28-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 28-28: 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 at line 28, The release workflow still
references external actions by tag instead of immutable commit SHAs, which is
unsafe for a job with publish secrets and write permissions. Update each
external action usage in release.yaml, including actions/checkout,
actions-rust-lang/setup-rust-toolchain, Swatinem/rust-cache,
abelfodil/protoc-action, and supercharge/redis-github-action, to pin them to
their full commit SHA refs so the release job uses fixed, reviewable versions.
Source: Linters/SAST tools
| - name: Validate versions are not sentinel | ||
| env: | ||
| VERSION: ${{ steps.parse.outputs.version }} | ||
| CRATE_VERSION: ${{ steps.parse.outputs.crate-version }} | ||
| run: | | ||
| if [[ "$VERSION" == "0.0.0" ]]; then | ||
| echo "::error::Version is 0.0.0 -- has the pre-release PR been merged?" | ||
| exit 1 | ||
| fi | ||
| if [[ "$CRATE_VERSION" == "0.0.0" ]]; then | ||
| echo "::error::Crate version is 0.0.0 -- has the pre-release PR been merged?" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Block -dev versions before release side effects.
parse-version.sh accepts prerelease suffixes, and the branch check still passes for values like 2.5.0-dev. This workflow can therefore tag and publish a dev version unless it reuses the release validator or rejects -dev here.
Suggested fix
- - name: Validate versions are not sentinel
+ - name: Validate versions are releasable
@@
- if [[ "$VERSION" == "0.0.0" ]]; then
- echo "::error::Version is 0.0.0 -- has the pre-release PR been merged?"
+ if [[ "$VERSION" == "0.0.0" || "$VERSION" == *-dev* ]]; then
+ echo "::error::Version '${VERSION}' is not releasable -- has the pre-release PR been merged?"
exit 1
fi
- if [[ "$CRATE_VERSION" == "0.0.0" ]]; then
- echo "::error::Crate version is 0.0.0 -- has the pre-release PR been merged?"
+ if [[ "$CRATE_VERSION" == "0.0.0" || "$CRATE_VERSION" == *-dev* ]]; then
+ echo "::error::Crate version '${CRATE_VERSION}' is not releasable -- has the pre-release PR been merged?"
exit 1
fi📝 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.
| - name: Validate versions are not sentinel | |
| env: | |
| VERSION: ${{ steps.parse.outputs.version }} | |
| CRATE_VERSION: ${{ steps.parse.outputs.crate-version }} | |
| run: | | |
| if [[ "$VERSION" == "0.0.0" ]]; then | |
| echo "::error::Version is 0.0.0 -- has the pre-release PR been merged?" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == "0.0.0" ]]; then | |
| echo "::error::Crate version is 0.0.0 -- has the pre-release PR been merged?" | |
| exit 1 | |
| fi | |
| - name: Validate versions are releasable | |
| env: | |
| VERSION: ${{ steps.parse.outputs.version }} | |
| CRATE_VERSION: ${{ steps.parse.outputs.crate-version }} | |
| run: | | |
| if [[ "$VERSION" == "0.0.0" || "$VERSION" == *-dev* ]]; then | |
| echo "::error::Version '${VERSION}' is not releasable -- has the pre-release PR been merged?" | |
| exit 1 | |
| fi | |
| if [[ "$CRATE_VERSION" == "0.0.0" || "$CRATE_VERSION" == *-dev* ]]; then | |
| echo "::error::Crate version '${CRATE_VERSION}' is not releasable -- has the pre-release PR been merged?" | |
| exit 1 | |
| fi |
🤖 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 44 - 56, The release workflow
validation in the version-check step only rejects the 0.0.0 sentinel, so `-dev`
prerelease values can still reach tagging and publishing. Update the validation
in the version validation block that reads `steps.parse.outputs.version` and
`steps.parse.outputs.crate-version` to also reject any `-dev` suffix, or reuse
the existing release validator logic here so both `VERSION` and `CRATE_VERSION`
are blocked before any release side effects.
| smoke-tests: | ||
| needs: read-version | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ inputs.release-branch }} | ||
|
|
||
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | ||
| with: | ||
| components: rustfmt, clippy | ||
|
|
||
| - uses: Swatinem/rust-cache@v2 | ||
|
|
||
| - uses: abelfodil/protoc-action@v1 | ||
| with: | ||
| protoc-version: "3.19.4" | ||
|
|
||
| - uses: supercharge/redis-github-action@1.8.1 | ||
| with: | ||
| redis-version: 7 | ||
|
|
||
| - name: Format check | ||
| run: cargo fmt --all -- --check | ||
|
|
||
| - name: Clippy | ||
| run: cargo clippy --locked --all-features --all-targets -- -D warnings | ||
|
|
||
| - name: Check | ||
| run: cargo check --locked --all-features | ||
|
|
||
| - name: Test | ||
| run: cargo test --locked --all-features | ||
|
|
||
| - name: Publish dry-run | ||
| run: cargo publish --dry-run --package limitador | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Expect the limitador Cargo.toml package version to match limitador.crate-version,
# and the server Cargo.toml version to match limitador.version.
sed -n '1,120p' release.yaml
rg -n '^(name|version)\s*=' Cargo.toml limitador-server/Cargo.tomlRepository: Kuadrant/limitador
Length of output: 337
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Repository files ==\n'
git ls-files | sed -n '1,200p'
printf '\n== release.yaml ==\n'
sed -n '1,120p' release.yaml
printf '\n== workflow relevant sections ==\n'
sed -n '1,240p' .github/workflows/release.yaml
printf '\n== Cargo manifests ==\n'
for f in Cargo.toml limitador/Cargo.toml limitador-server/Cargo.toml; do
if [[ -f "$f" ]]; then
echo "--- $f ---"
sed -n '1,120p' "$f"
fi
doneRepository: Kuadrant/limitador
Length of output: 23402
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Repository files ==\n'
git ls-files | sed -n '1,200p'
printf '\n== release.yaml ==\n'
sed -n '1,120p' release.yaml
printf '\n== workflow relevant sections ==\n'
sed -n '1,240p' .github/workflows/release.yaml
printf '\n== Cargo manifests ==\n'
for f in Cargo.toml limitador/Cargo.toml limitador-server/Cargo.toml; do
if [[ -f "$f" ]]; then
echo "--- $f ---"
sed -n '1,120p' "$f"
fi
doneRepository: Kuadrant/limitador
Length of output: 23402
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== validate-release-yaml.sh ==\n'
sed -n '1,220p' .github/scripts/validate-release-yaml.sh
printf '\n== parse-version.sh ==\n'
sed -n '1,220p' .github/scripts/parse-version.sh
printf '\n== version-gate workflow ==\n'
sed -n '1,220p' .github/workflows/version-gate.yaml
printf '\n== release notes / docs references to release.yaml ==\n'
rg -n "crate-version|release.yaml|cargo publish|publish --dry-run|manifest version|Cargo.toml" .github README.md RELEASE.md limitador-server/README.md -A2 -B2Repository: Kuadrant/limitador
Length of output: 29551
Add a manifest/version consistency check. The release workflow reads the release metadata from release.yaml, but cargo publish uses the version in limitador/Cargo.toml. A pre-publish check should compare release.yaml against the crate and server manifests so the workflow cannot tag/release one version and publish another.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 85-87: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 85-85: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 89-89: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 93-93: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 95-95: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 99-99: 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 81 - 117, Add a manifest/version
consistency check to the release workflow so it cannot proceed when release
metadata and crate versions diverge. Update the smoke-tests job in release.yaml
to compare the version read from read-version with the versions in
limitador/Cargo.toml and the server manifest before the Publish dry-run step.
Make the check fail fast if any manifest disagrees, using the existing release
metadata and cargo-published crate as the comparison points.
| for TAG in "v${VERSION}" "server-v${VERSION}" "crate-v${CRATE_VERSION}"; do | ||
| if git tag --list "$TAG" | grep --quiet .; then | ||
| echo "::error::Tag $TAG already exists" | ||
| exit 1 | ||
| fi | ||
| git tag --annotate "$TAG" --message "Release $TAG" | ||
| done | ||
|
|
||
| git push origin "v${VERSION}" "server-v${VERSION}" "crate-v${CRATE_VERSION}" |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Make release side effects resumable.
A full rerun after tags or the crate publish have already succeeded will fail on existing tags or duplicate crate versions. Treat existing artefacts as success only when they match the intended commit/version, and fail only on mismatches.
Also applies to: 159-162
🤖 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 135 - 143, The release workflow
tag/publish step is not resumable because it blindly fails on existing tags and
duplicate crate versions. Update the logic around the tag loop and crate
publish/release steps to treat already-existing artefacts as success only if
they match the intended commit/version, and to fail only when an existing
tag/version points to a different commit or release state. Use the existing
release shell block in the workflow and the tag names/version variables to
locate the checks, and apply the same resumable handling to the related steps
referenced by the duplicate comment.
| build-images: | ||
| needs: [read-version, tag] | ||
| uses: ./.github/workflows/build-image.yaml | ||
| with: | ||
| ref: ${{ inputs.release-branch }} | ||
| tag: v${{ needs.read-version.outputs.version }} | ||
| secrets: inherit |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the reusable workflow's actual secret usage, then replace `secrets: inherit`
# with an explicit secrets map containing only those names.
rg -n 'workflow_call:|secrets:|secrets\.' .github/workflows/build-image.yamlRepository: Kuadrant/limitador
Length of output: 411
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- .github/workflows/build-image.yaml (top/middle) ---'
sed -n '1,180p' .github/workflows/build-image.yaml
echo
echo '--- .github/workflows/release.yaml (build-images job) ---'
sed -n '150,185p' .github/workflows/release.yamlRepository: Kuadrant/limitador
Length of output: 6344
Pass only the registry credentials to the reusable workflow. secrets: inherit exposes every repo/release secret here; pass IMG_REGISTRY_USERNAME and IMG_REGISTRY_TOKEN explicitly instead.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 166-166: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow
(secrets-inherit)
🤖 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 164 - 170, The build-images job
is currently inheriting all secrets through the reusable workflow call, which is
too broad; update the release workflow to pass only the registry credentials
needed by the reusable build-image.yaml workflow. Replace the broad secret
inheritance in build-images with explicit secret mapping for
IMG_REGISTRY_USERNAME and IMG_REGISTRY_TOKEN so the reusable workflow only
receives those two values.
Source: Linters/SAST tools
32ba36f to
08a2ca3
Compare
Automates the release of limitador, including the manual steps from before. Also aligns the release process with the up-and-coming RFC. Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
a9b35eb to
afd9fe2
Compare
Summary
Replaces the manual, multi-step release process with an automated two-phase workflow driven by GitHub Actions and a
release.yamlversion manifest.workflow_dispatchworkflow creates a release branch, bumps versions inrelease.yamland bothCargo.tomlfiles, and opens a PR against the release branch. For minor releases it also opens a post-release PR tomainwith the next-devversions.workflow_dispatchworkflow reads versions fromrelease.yaml, runs smoke tests (fmt, clippy, full test suite, publish dry-run), creates annotated git tags, publishes the crate to crates.io, builds multi-arch container images, and creates the GitHub Release only after all artifacts succeed.release-*branches validates thatrelease.yamlcontains non-sentinel, non-dev versions and that any declared dependency releases exist.build-image.yamlworkflow now acceptsrefandtaginputs viaworkflow_call, allowing the release workflow to trigger image builds for a specific ref and tag while preserving the existing push-on-main behavior.publish = falsetolimitador-server/Cargo.tomlto prevent accidental publication of the server binary crate.release.yamlat the repo root as the single source of truth for version numbers, using0.0.0as the sentinel value onmain.parse-version.sh,validate-release-yaml.sh) with documentation covering usage and error cases.RELEASE.mdto document the new process including minor releases, patch releases, rollback procedures, and file inventory.Examples
Pre-release Workflow: https://github.com/Boomatang/limitador/actions/runs/28022410045
PR to release branch: Boomatang#5
PR to main (dev version bump): Boomatang#6
Release Workflow: https://github.com/Boomatang/limitador/actions/runs/28028029786
GitHub release: https://github.com/Boomatang/limitador/releases
Summary by CodeRabbit
Release Notes
New Features
Documentation
Chores