Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/helm-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ name: Helm chart static analysis
on:
push:
pull_request:
branches: [ main ]
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # ratchet:actions/checkout@v7
with:
fetch-depth: 0
Comment thread
azgabur marked this conversation as resolved.
- name: Install chart-testing
uses: helm/chart-testing-action@v2.7.0
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # ratchet:helm/chart-testing-action@v2.8.0
- name: Check if linting is required
id: list-changed
run: |
Expand Down
157 changes: 157 additions & 0 deletions .github/workflows/manual-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: Manual Helm chart release with frozen versions
on:
workflow_dispatch:
inputs:
kuadrantVersion:
description: 'Version with optional RC suffix and product. k=kuadrant r=RHCL (example: 1.0.0-k, 2.3.4-rc1-r)'
required: true
type: string
indexImage:
description: 'Kuadrant operator index image (example: quay.io/kuadrant/kuadrant-operator-catalog:v1.4.3)'
required: true
type: string
ocpVersion:
description: 'Openshift version to pin operator versions for. (example: v4.22)'
required: true
default: v4.22

env:
HELM_VERSION: ${{ inputs.kuadrantVersion }}-${{ inputs.ocpVersion }}

run-name: "Release of ${{ inputs.kuadrantVersion }}-${{ inputs.ocpVersion }}"

jobs:
release:
runs-on: ubuntu-latest
Comment thread
coderabbitai[bot] marked this conversation as resolved.
concurrency:
group: helm-gh-pages-publish
cancel-in-progress: false
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # ratchet:actions/checkout@v7
- name: Validate kuadrant version format
run: |
if ! [[ "${{ inputs.kuadrantVersion }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*-(k|r)$ ]]; then

@coderabbitai coderabbitai Bot Aug 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Do not render workflow inputs directly into shell source.

A quote or shell metacharacter in an input can alter the command before validation completes. Put inputs in environment variables, then use quoted shell variables. Use strenv(INDEX_IMAGE) for the yq assignment.

  • .github/workflows/manual-release.yml#L28-L28: validate "$KUADRANT_VERSION" instead of rendering inputs.kuadrantVersion.
  • .github/workflows/manual-release.yml#L34-L34: validate "$OCP_VERSION" instead of rendering inputs.ocpVersion.
  • .github/workflows/manual-release.yml#L73-L73: build CATALOG_IMAGE from "$OCP_VERSION".
  • .github/workflows/manual-release.yml#L94-L95: use strenv(INDEX_IMAGE) and printf with "$INDEX_IMAGE".
🧰 Tools
🪛 zizmor (1.29.0)

[error] 28-28: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

📍 Affects 1 file
  • .github/workflows/manual-release.yml#L28-L28 (this comment)
  • .github/workflows/manual-release.yml#L34-L34
  • .github/workflows/manual-release.yml#L73-L73
  • .github/workflows/manual-release.yml#L94-L95
🤖 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/manual-release.yml at line 28, Prevent workflow inputs
from being rendered directly into shell source: in
.github/workflows/manual-release.yml lines 28-28 and 34-34, expose the inputs
through environment variables and validate the quoted "$KUADRANT_VERSION" and
"$OCP_VERSION"; at lines 73-73, build CATALOG_IMAGE from "$OCP_VERSION"; at
lines 94-95, pass INDEX_IMAGE through the environment, use strenv(INDEX_IMAGE)
in yq, and use printf with the quoted "$INDEX_IMAGE".

Source: Linters/SAST tools

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every env var is quoted

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- workflow outline ---'
ast-grep outline .github/workflows/manual-release.yml --items all || true

printf '%s\n' '--- relevant lines ---'
nl -ba .github/workflows/manual-release.yml | sed -n '20,110p'

printf '%s\n' '--- direct workflow-input expressions in run blocks ---'
rg -n -C 3 '\$\{\{\s*inputs\.[A-Za-z0-9_]+\s*\}\}' .github/workflows/manual-release.yml

Length of output: 854


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- relevant workflow section ---'
sed -n '20,115p' .github/workflows/manual-release.yml

printf '%s\n' '--- direct workflow-input expressions ---'
grep -n -C 3 -E '\$\{\{[[:space:]]*inputs\.[[:alnum:]_]+[[:space:]]*\}\}' \
  .github/workflows/manual-release.yml || true

Length of output: 5879


@azgabur, the inputs are not environment variables at the reported locations. The workflow renders ${{ inputs.* }} directly into the Bash source.

For example, this is unsafe even though the expression appears between quotes:

if ! [[ "${{ inputs.kuadrantVersion }}" =~ ... ]]; then

GitHub expands the expression before Bash parses the command. An input containing " can terminate the quoted string and change the command.

The workflow must assign inputs through env: and then use quoted shell variables, for example "$KUADRANT_VERSION" and "$OCP_VERSION". The same requirement applies to INDEX_IMAGE; yq must receive it through strenv(INDEX_IMAGE).

The finding remains valid.

You are interacting with an AI system.

@fabikova fabikova Aug 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: (-rc[0-9]+)* , * allows more RC suffixes together. is it intended? Could you possibly change * to ??

echo "ERROR: Version must be in format X.Y.Z[-rcX]-(k|r) (e.g., 1.0.0-k, 2.3.4-rc1-r)"
exit 1
fi
- name: Validate ocp version format
run: |
if ! [[ "${{ inputs.ocpVersion }}" =~ ^v[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: Version must be in format vX.Y (e.g., v4.22)"
exit 1
fi

- name: Check tag does not already exist
run: |
if git ls-remote --exit-code --refs --tags origin "refs/tags/$HELM_VERSION" >/dev/null; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tag existence check is at the beginning, but the tag is created only at the end after publishing to gh-pages. If the run fails between these steps, on a re-run the tag check passes (the tag doesn't exist yet), but the chart is already on gh-pages, and helm repo index --merge might create a duplicate entry in index.yaml. is a re-run safe after a partial failure? shouldn't the check also verify the presence of the chart on gh-pages?

echo "ERROR: Tag $HELM_VERSION already exists"
exit 1
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Set up yq
run: sudo snap install yq

- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # ratchet:azure/setup-helm@v5
with:
version: v3.18.4

- name: Set up opm
run: |
OPM_VERSION=$(curl -s https://api.github.com/repos/operator-framework/operator-registry/releases/latest | jq -r '.tag_name')
curl -Lo opm "https://github.com/operator-framework/operator-registry/releases/download/${OPM_VERSION}/linux-amd64-opm"
chmod +x opm
sudo mv opm /usr/local/bin/
opm version
Comment on lines +51 to +65

@coderabbitai coderabbitai Bot Aug 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow files =="
git ls-files '.github/workflows/*' || true

echo
echo "== manual-release snippets =="
if [ -f .github/workflows/manual-release.yml ]; then
  cat -n .github/workflows/manual-release.yml | sed -n '1,130p'
fi

echo
echo "== yq/opm usage in workflows =="
rg -n "yq|opm|operator-registry|snap install|curl .*opm|versions" .github/workflows || true

Repository: Kuadrant/helm-charts-olm

Length of output: 8468


🌐 Web query:

snap install yq version channel snap install yq documentation

💡 Result:

To install the yq snap, you can use the standard snap install command for the latest stable version, or specify a particular channel to install a different version or track [1][2][3]. Standard Installation To install the latest stable release of yq, run the following command in your terminal: sudo snap install yq [1][4][5] Installing a Specific Version or Channel If you need to install a specific version or major release (such as v3), you can use the --channel flag [6][3]. For example, to install the v3 stable release, you would use: sudo snap install yq --channel=v3/stable [6][3] Key Documentation and Usage Notes The yq snap is distributed with strict confinement, which limits its ability to access files outside of specific system directories [2][6][7]. If you encounter issues reading files (such as root files or files in protected directories), you may need to adjust file permissions or move the target files to a location accessible by the snap [2][7]. You can view available channels, revisions, and more detailed package information by visiting the official yq page on the Snap Store [1]. [1][6][3]

Citations:


🌐 Web query:

GitHub operator-framework operator-registry releases github.com/operator-framework/operator-registry/releases/latest linux-amd64-opm binary checksum

💡 Result:

For the latest GitHub release of operator-framework/operator-registry, the linux-amd64 opm binary asset is provided together with a checksums.txt file. The latest release tag is v1.71.0, whose release assets include linux-amd64-opm and checksums.txt. [1] linux-amd64-opm binary (latest release): https://github.com/operator-framework/operator-registry/releases/tag/v1.71.0 (asset listed as “linux-amd64-opm”) [1] checksums.txt (latest release): https://github.com/operator-framework/operator-registry/releases/tag/v1.71.0 (asset listed as “checksums.txt”) [1] To retrieve the exact checksum value for the linux-amd64-opm binary, download checksums.txt from that same release and look up the linux-amd64-opm entry. [1] Example: 1) curl -fsSLO https://github.com/operator-framework/operator-registry/releases/download/v1.71.0/checksums.txt 2) grep -E '^.*linux-amd64-opm$' checksums.txt Note: the sources available here show that checksums.txt exists for the release and that both assets are present, but they do not include the checksum line contents themselves in the retrieved snippets. [1]

Citations:


Pin yq and opm to immutable releases before release processing.

snap install yq installs the current Snap release, and the opm setup resolves and downloads the current upstream release each run. Pin both tools to reviewed commit/tag references for release reproducibility, and verify downloaded binary checksums when downloading opm.

🤖 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/manual-release.yml around lines 46 - 60, Update the “Set
up yq” and “Set up opm” steps to use reviewed immutable version or commit
references instead of resolving latest releases at runtime. For opm, download
the pinned release asset and verify its checksum before installing it; retain
the existing executable installation and version validation flow.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latests should be fine. yq is used only for formating and opm to extract information. In the worst case something fails before releasing. Can be fixed than.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@azgabur, understood. The finding remains valid because this release workflow resolves unreviewed tool versions at release time. This conflicts with the PR objective to freeze tool versions.

A tool update can change generated values or fail after release processing starts. A checksum does not prevent this when the workflow selects a new upstream release first.

🐇


✏️ Learnings added
Learnt from: azgabur
Repo: Kuadrant/helm-charts-olm PR: 111
File: .github/workflows/manual-release.yml:51-65
Timestamp: 2026-08-12T08:09:21.469Z
Learning: In `.github/workflows/manual-release.yml`, maintainers consider mutable latest versions acceptable for `yq` because it only formats data and for `opm` because it only extracts operator information. They accept that a changed tool version can fail before a release and can be corrected later.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.


- name: Set up container registry config
run: |
sudo mkdir -p /etc/containers
echo 'unqualified-search-registries = ["registry.access.redhat.com", "docker.io"]' | sudo tee /etc/containers/registries.conf

- name: Log in to registry.redhat.io
run: podman login -u "${{ secrets.REDHAT_REGISTRY_USER }}" -p "${{ secrets.REDHAT_REGISTRY_PASSWORD }}" registry.redhat.io

- name: Get frozen versions
id: versions
env:
TMPDIR: ${{ runner.temp }}
run: |
export CATALOG_IMAGE="registry.redhat.io/redhat/redhat-operator-index:${{ inputs.ocpVersion }}"
./script/get-all-versions.sh > frozen-versions.yaml
echo "Frozen versions:\n\n"
cat frozen-versions.yaml

- name: Merge frozen versions with values files
run: |
yq eval-all '. as $item ireduce ({}; . * $item)' values.yaml frozen-versions.yaml > values-frozen.yaml
yq eval-all '. as $item ireduce ({}; . * $item)' values-tools.yaml frozen-versions.yaml > values-tools-frozen.yaml

echo "Merged values.yaml:"
cat values-frozen.yaml
echo ""
echo "Merged values-tools.yaml:"
cat values-tools-frozen.yaml

mv values-frozen.yaml values.yaml
mv values-tools-frozen.yaml values-tools.yaml

- name: Set index image
run: |
yq -i '.kuadrant.indexImage = "${{ inputs.indexImage }}"' values.yaml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indexImage doesn't have any validation. Both kuadrantVersion and ocpVersion are validated via regex, but indexImage is written directly into values.yaml as a string, and the workflow never pulls or renders it anywhere (freezing - redhat-operator-index, not this image). A wrong reference, a typo, or more realistically a stale tag like :v1.4.2 instead of :v1.4.3 would pass through the entire process, the chart would be published, and the error would only show at helm install time when olm fails to pull the CatalogSource image. Probability is low since the image is copy-pasted, but I think it would be quick check (regex format check, or skopeo inspect maybe?).

echo "Set indexImage to: ${{ inputs.indexImage }}"

if [[ "${{ inputs.kuadrantVersion }}" == *-k ]]; then
OPERATOR_NAME="kuadrant-operator"
else
OPERATOR_NAME="rhcl-operator"
fi
yq -i ".kuadrant.operatorName = \"$OPERATOR_NAME\"" values.yaml
echo "Set operatorName to: $OPERATOR_NAME"

- name: Update chart versions
run: |
for chart_dir in charts/*/; do
chart_file="${chart_dir}Chart.yaml"
if [[ -f "$chart_file" ]]; then
yq -i ".version = \"$HELM_VERSION\"" "$chart_file"
yq -i ".appVersion = \"$HELM_VERSION\"" "$chart_file"
echo "Updated $chart_file to version $HELM_VERSION"
fi
done

- name: Package Helm charts
run: |
mkdir .cr-release-packages
helm package ./charts/* -d .cr-release-packages

- name: Checkout gh-pages branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # ratchet:actions/checkout@v7
with:
ref: gh-pages
path: gh-pages

- name: Copy chart to gh-pages
run: |
cp .cr-release-packages/* gh-pages/

- name: Generate new index.yaml
run: |
cd gh-pages
helm repo index . --merge index.yaml

- name: Commit and push
run: |
cd gh-pages
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git add .
git commit -m "Release $HELM_VERSION with frozen versions (manual release)"
git push origin gh-pages

- name: Create Git tag
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
git tag -a "$HELM_VERSION" -m "Release $HELM_VERSION with frozen versions"
git push origin "$HELM_VERSION"
11 changes: 7 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
name: Helm chart releases
on:
push:
branches: [ main ]
branches: [main]
paths:
- 'charts/**'
- 'values-tools.yaml'
- 'values.yaml'
jobs:
release:
runs-on: ubuntu-latest
concurrency:
group: helm-gh-pages-publish
cancel-in-progress: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # ratchet:actions/checkout@v7
- name: Set up Helm
uses: azure/setup-helm@v3
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # ratchet:azure/setup-helm@v5
- name: Package Helm charts
run: |
mkdir .cr-release-packages
helm package ./charts/* -d .cr-release-packages
- name: Checkout gh-pages branch
uses: actions/checkout@v3
uses: actions/checkout@a37ce9120846195fa4ece8f58b268e6043cb2f26 # ratchet:actions/checkout@v3
with:
ref: gh-pages
path: gh-pages
Expand Down
4 changes: 2 additions & 2 deletions charts/kuadrant-instances/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"
appVersion: "0.0.0"

# dependencies:
# - name: kuadrant-operators
Expand Down
4 changes: 2 additions & 2 deletions charts/kuadrant-operators/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"
appVersion: "0.0.0"
4 changes: 2 additions & 2 deletions charts/tools-instances/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"
appVersion: "0.0.0"

dependencies:
- name: vault
Expand Down
4 changes: 2 additions & 2 deletions charts/tools-operators/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
version: 0.0.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: "1.0"
appVersion: "0.0.0"
Loading