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
31 changes: 31 additions & 0 deletions .github/scripts/parse-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail

RELEASE_YAML="${1:-release.yaml}"

if [[ ! -f "$RELEASE_YAML" ]]; then
echo "::error::File not found: $RELEASE_YAML"
exit 1
fi

VERSION=$(yq '.authorino.version' "$RELEASE_YAML")
if [[ -z "$VERSION" || "$VERSION" == "null" ]]; then
echo "::error::No version found in $RELEASE_YAML under authorino.version"
exit 1
fi

if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid semver: $VERSION"
exit 1
fi

MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3 | cut -d- -f1)
RELEASE_BRANCH="release-${MAJOR}.${MINOR}"

echo "version=$VERSION" >> "${GITHUB_OUTPUT:-/dev/stdout}"
echo "major=$MAJOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
echo "minor=$MINOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
echo "patch=$PATCH" >> "${GITHUB_OUTPUT:-/dev/stdout}"
echo "release-branch=$RELEASE_BRANCH" >> "${GITHUB_OUTPUT:-/dev/stdout}"
31 changes: 31 additions & 0 deletions .github/scripts/validate-release-yaml.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail

BRANCH="${1:?Branch name required}"
ORG="${2:-Kuadrant}"
RELEASE_YAML="${3:-release.yaml}"

if [[ ! -f "$RELEASE_YAML" ]]; then
echo "::error::File not found: $RELEASE_YAML"
exit 1
fi

VERSION=$(yq '.authorino.version' "$RELEASE_YAML")

if [[ "$BRANCH" != "main" && "$VERSION" == "0.0.0" ]]; then
echo "::error::release.yaml version is 0.0.0 on branch '$BRANCH' -- must specify a release version on non-main branches"
exit 1
fi

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
if ! gh release view "v${dep_version}" --repo "${ORG}/${dep}" &>/dev/null; then
Comment on lines +20 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and read the validate-release-yaml.sh file
git ls-files | grep -i "validate-release-yaml"

Repository: Kuadrant/authorino

Length of output: 197


🏁 Script executed:

# Read the file to see the current state
cat -n .github/scripts/validate-release-yaml.sh | head -40

Repository: Kuadrant/authorino

Length of output: 1386


🏁 Script executed:

# Test yq behaviour with keys containing hyphens
# Create a test YAML to verify the concern
cat > /tmp/test-release.yaml <<'EOF'
dependencies:
  my-service: "1.0.0"
  another-component: "2.0.0"
  simple: "3.0.0"
EOF

# Test current approach (without quotes)
echo "=== Testing current approach (unquoted key) ==="
yq '.dependencies | keys | .[]' /tmp/test-release.yaml

echo ""
echo "=== Testing current approach with unquoted variable ==="
dep="my-service"
yq ".dependencies.${dep}" /tmp/test-release.yaml 2>&1 || echo "FAILED"

echo ""
echo "=== Testing proposed fix with bracket notation ==="
yq -r ".dependencies[\"${dep}\"]" /tmp/test-release.yaml

Repository: Kuadrant/authorino

Length of output: 435


🏁 Script executed:

# Check if there are any RELEASE_YAML files in the repo and their content
find . -name "*release*.yaml" -o -name "*release*.yml" | head -10

Repository: Kuadrant/authorino

Length of output: 241


🌐 Web query:

yq key quoting hyphenated keys bracket notation syntax

💡 Result:

To access keys containing hyphens in yq, you must use bracket notation with quoted strings [1][2]. Because hyphenated keys can be misinterpreted by the parser as subtraction operations, wrapping the key name in quotes (either double or single) is necessary to ensure it is treated as a literal string [1][2]. The standard syntax for accessing such a key is: yq '.["your-hyphenated-key"]' file.yaml Alternatively, you can use the syntax: yq '."your-hyphenated-key"' file.yaml It is critical to use shell-level quoting (the outer single quotes) to prevent your shell from interpreting the brackets or quotes before they are passed to yq [1]. Common pitfalls: 1. Shell Interpretation: If you do not wrap the entire expression in single quotes (e.g., yq.["key-name"]), your shell may attempt to interpret the brackets or quotes, leading to errors. 2. Operator Confusion: If you omit quotes around the key name, yq may treat the hyphen as a subtraction operator rather than a character in the key name [1]. 3. Leading Dashes: If the key name itself starts with a hyphen, you may also need to use the flag terminator (--) to stop the command from misinterpreting the key as a command-line flag [3].

Citations:


🌐 Web query:

yq .dependencies.key-name vs .dependencies["key-name"] parsing difference

💡 Result:

In yq, the primary difference between dot notation (e.g.,.dependencies.key-name) and bracket notation (e.g.,.dependencies["key-name"]) is how they handle key names containing special characters, such as dots, hyphens, or spaces [1][2][3]. Dot notation is designed for simple, alphanumeric key names [4]. When a key contains special characters like a period, hyphen, or space, yq may misinterpret these characters as part of the expression's syntax—for example, treating a dot as a nested object separator rather than part of the key name [2][5][3]. Bracket notation with quotes (e.g.,.dependencies["key-name"]) acts as a robust mechanism to treat the contents within the brackets as a literal string [1][3]. This allows you to access keys that would otherwise be syntactically ambiguous or invalid in dot notation [2][6]. Key takeaways: 1. Dot notation: Suitable for standard, simple key names without special characters [4]. It cannot correctly reference keys containing dots (e.g.,.a.b.c interprets b.c as a nested structure) or other reserved symbols [2][5]. 2. Bracket notation: Required for keys containing dots, spaces, or leading dashes [1][2][3][7]. It is generally safer to use bracket notation whenever you are uncertain if a key name might conflict with yq expression syntax [6]. 3. Shell considerations: When using bracket notation in a terminal, it is important to wrap the entire expression in single quotes (e.g., '.dependencies["key-name"]') to prevent the shell from interpreting the double quotes or brackets prematurely [2][5][8]. For example, if you have a key named b.c, you must use.["b.c"] or."b.c" to access it, as.b.c would attempt to look for a key named b containing a sub-key named c [2][5].

Citations:


🏁 Script executed:

# Let me check the release.yaml file in the repo to see what dependencies actually exist
cat release.yaml 2>/dev/null | head -50

Repository: Kuadrant/authorino

Length of output: 186


🏁 Script executed:

# Also check if there are any dependencies with hyphens in their names
# by examining any release YAML files
if [ -f release.yaml ]; then
  echo "=== Content of release.yaml ===" 
  cat release.yaml
fi

Repository: Kuadrant/authorino

Length of output: 218


Use bracket notation with quoted keys when querying yq for dynamic dependency names.

Line 22 currently builds .dependencies.${dep} using dot notation, which fails when dependency names contain hyphens. The yq parser misinterprets hyphens as subtraction operators rather than literal characters. This causes dependency version checks to fail silently or be skipped entirely for dependencies like my-service.

🔧 Proposed fix
-DEPS=$(yq '.dependencies | keys | .[]' "$RELEASE_YAML" 2>/dev/null || true)
-for dep in $DEPS; do
-  dep_version=$(yq ".dependencies.${dep}" "$RELEASE_YAML")
+mapfile -t deps < <(yq -r '.dependencies // {} | keys[]' "$RELEASE_YAML")
+for dep in "${deps[@]}"; do
+  dep_version=$(yq -r ".dependencies[\"${dep}\"]" "$RELEASE_YAML")
🤖 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 20 - 24, The yq query
on the line that assigns dep_version uses dot notation with
`.dependencies.${dep}`, which fails when dependency names contain hyphens
because yq interprets hyphens as subtraction operators rather than literal
characters. Replace the dot notation syntax with bracket notation by changing
`.dependencies.${dep}` to `.dependencies["${dep}"]` to properly handle
dependency names with special characters like hyphens.

echo "::error::Dependency '${dep}' targets version '${dep_version}', but release v${dep_version} does not exist in ${ORG}/${dep}"
exit 1
fi
fi
done

echo "release.yaml validation passed"
23 changes: 19 additions & 4 deletions .github/workflows/build-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ on:
- 'main'
- 'master'
workflow_dispatch: { }
workflow_call:
inputs:
version:
description: "Release version (e.g. 0.26.0)"
type: string
required: true
ref:
description: "Git ref to build from (e.g. v0.26.0)"
type: string
required: true

env:
IMG_TAGS: ${{ github.sha }}
Expand All @@ -26,7 +36,10 @@ jobs:
- name: Set Authorino build info
id: build-info
run: |
if [[ ${GITHUB_REF_NAME/\//-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
if [[ -n "${{ inputs.version }}" ]]; then
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
echo "version_tag=v${{ inputs.version }}" >> $GITHUB_OUTPUT
elif [[ ${GITHUB_REF_NAME/\//-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
Comment on lines +39 to +42

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

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/build-images.yaml | sed -n '1,50p'

Repository: Kuadrant/authorino

Length of output: 2070


🏁 Script executed:

cat -n .github/workflows/build-images.yaml | sed -n '9,18p;75,76p;130,132p'

Repository: Kuadrant/authorino

Length of output: 837


🏁 Script executed:

# Check if there are any uses of inputs.version elsewhere in the workflow
rg 'inputs\.version' .github/workflows/build-images.yaml

Repository: Kuadrant/authorino

Length of output: 347


Harden workflow_call input handling before using it in bash.

Lines 39–41 interpolate ${{ inputs.version }} directly into shell code. If a caller passes a crafted value containing shell metacharacters (e.g. $(command)), the shell will expand it and execute arbitrary code, poisoning the workflow outputs. Pass the input via an environment variable instead to prevent expansion.

Suggested fix
       - name: Set Authorino build info
         id: build-info
+        env:
+          INPUT_VERSION: ${{ inputs.version }}
         run: |
-          if [[ -n "${{ inputs.version }}" ]]; then
-            echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
-            echo "version_tag=v${{ inputs.version }}" >> $GITHUB_OUTPUT
+          if [[ -n "$INPUT_VERSION" ]]; then
+            if ! [[ "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
+              echo "::error::Invalid version input: $INPUT_VERSION"
+              exit 1
+            fi
+            printf 'version=%s\n' "$INPUT_VERSION" >> "$GITHUB_OUTPUT"
+            printf 'version_tag=v%s\n' "$INPUT_VERSION" >> "$GITHUB_OUTPUT"
           elif [[ ${GITHUB_REF_NAME/\/,-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; 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.

Suggested change
if [[ -n "${{ inputs.version }}" ]]; then
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
echo "version_tag=v${{ inputs.version }}" >> $GITHUB_OUTPUT
elif [[ ${GITHUB_REF_NAME/\//-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
- name: Set Authorino build info
id: build-info
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
if [[ -n "$INPUT_VERSION" ]]; then
if ! [[ "$INPUT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid version input: $INPUT_VERSION"
exit 1
fi
printf 'version=%s\n' "$INPUT_VERSION" >> "$GITHUB_OUTPUT"
printf 'version_tag=v%s\n' "$INPUT_VERSION" >> "$GITHUB_OUTPUT"
elif [[ ${GITHUB_REF_NAME/\/,-} =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
🧰 Tools
🪛 zizmor (1.26.1)

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

(template-injection)


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

(template-injection)


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

(template-injection)

🤖 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-images.yaml around lines 39 - 42, The conditional
block starting at line 39 directly interpolates the workflow input `${{
inputs.version }}` into shell code, which creates a shell injection
vulnerability if a caller passes values containing shell metacharacters like
`$(command)`. Instead of directly embedding the input in the bash conditional
and echo commands, set the input value as an environment variable first, then
reference that variable in the conditional check and the subsequent echo
statements that write to GITHUB_OUTPUT. This prevents the shell from
interpreting any special characters in the input value.

Source: Linters/SAST tools

tag=${GITHUB_REF_NAME/\//-}
echo "version=${tag#v}" >> $GITHUB_OUTPUT
echo "version_tag=${tag}" >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -59,6 +72,8 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || '' }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to registry
Expand Down Expand Up @@ -112,9 +127,9 @@ jobs:
with:
images: ${{ env.IMG_REGISTRY_HOST }}/${{ env.IMG_REGISTRY_ORG }}/authorino
tags: |
type=raw,value=${{ github.ref_name }},enable={{is_not_default_branch}}
type=raw,value=${{ github.sha }},enable={{is_default_branch}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=${{ needs.prepare.outputs.version_tag }}
type=raw,value=${{ github.sha }},enable=${{ needs.prepare.outputs.version_tag == 'latest' }}
type=raw,value=latest,enable=${{ needs.prepare.outputs.version_tag == 'latest' }}
- name: Login to registry
if: ${{ !env.ACT }}
uses: docker/login-action@v3
Expand Down
139 changes: 139 additions & 0 deletions .github/workflows/pre-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Pre-release

on:
workflow_dispatch:
inputs:
version:
description: "Release version (semver, e.g. 1.5.0)"
required: true
type: string
source-branch:
description: "Branch to base the pre-release changes on (default: main)"
required: false
type: string
default: "main"

permissions:
contents: write
pull-requests: write

jobs:
setup:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.validate.outputs.version }}
release-branch: ${{ steps.validate.outputs.release-branch }}
steps:
- uses: actions/checkout@v4

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

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/pre-release.yaml | sed -n '20,115p'

Repository: Kuadrant/authorino

Length of output: 4142


Pin all action references to immutable commit SHAs.

Lines 27, 62, 82, and 108 use mutable version tags (@v4/@v5), leaving the workflow vulnerable to upstream tag retargeting. Replace with specific commit SHAs (e.g., actions/checkout@e2f20f853a2a19803ed141a6f266e17681910f6d).

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 27-31: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 27-27: 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/pre-release.yaml at line 27, The workflow file uses
mutable version tags (such as `@v4` and `@v5`) for GitHub Actions references on
lines 27, 62, 82, and 108, which creates security risks since these tags can be
retargeted upstream. Replace each mutable version tag with a specific immutable
commit SHA. For the actions/checkout action on line 27 and any other action
references throughout the file, determine the correct commit SHA for each action
version (for example, `@v4` should be replaced with the full commit SHA like
`@e2f20f853a2a19803ed141a6f266e17681910f6d`) and update all four occurrences to
use the pinned commit hash instead of the version tag.

Source: Linters/SAST tools

with:
ref: ${{ inputs.source-branch }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Validate version format
id: validate
run: |
VERSION="${{ inputs.version }}"
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "::error::Invalid semver version: $VERSION"
exit 1
fi
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
RELEASE_BRANCH="release-${MAJOR}.${MINOR}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "release-branch=$RELEASE_BRANCH" >> "$GITHUB_OUTPUT"

- name: Create or verify release branch
run: |
RELEASE_BRANCH="${{ steps.validate.outputs.release-branch }}"
if git ls-remote --exit-code origin "refs/heads/${RELEASE_BRANCH}" >/dev/null 2>&1; then
echo "Release branch '${RELEASE_BRANCH}' already exists"
else
echo "Creating release branch '${RELEASE_BRANCH}' from '${{ inputs.source-branch }}'"
git checkout -b "${RELEASE_BRANCH}"
git push origin "${RELEASE_BRANCH}"
fi

prepare-release:
needs: setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.setup.outputs.release-branch }}
fetch-depth: 0

- name: Create pre-release branch
run: |
PRE_RELEASE_BRANCH="pre-release-v${{ needs.setup.outputs.version }}"
if git ls-remote --exit-code origin "refs/heads/${PRE_RELEASE_BRANCH}" >/dev/null 2>&1; then
echo "::error::Pre-release branch '${PRE_RELEASE_BRANCH}' already exists. Delete it first or use a different version."
exit 1
fi
git checkout -b "${PRE_RELEASE_BRANCH}"

- name: Update release.yaml
run: |
VERSION="${{ needs.setup.outputs.version }}"
yq -i ".authorino.version = \"${VERSION}\"" release.yaml

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Run code generation
run: |
make generate
make manifests

- name: Commit and push changes
run: |
VERSION="${{ needs.setup.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
if git diff --cached --quiet; then
echo "No changes to commit"
else
git commit -m "chore: prepare release v${VERSION}"
fi
git push origin "pre-release-v${VERSION}"

open-pr:
needs: [setup, prepare-release]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Open pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ needs.setup.outputs.version }}"
RELEASE_BRANCH="${{ needs.setup.outputs.release-branch }}"

gh pr create \
--base "${RELEASE_BRANCH}" \
--head "pre-release-v${VERSION}" \
--title "Release v${VERSION}" \
--body "$(cat <<EOF
## Release v${VERSION}

This PR prepares the release of v${VERSION}.

### Pre-release changes
- Updated \`release.yaml\` version to \`${VERSION}\`
- Ran \`make generate\` and \`make manifests\`

### Checklist
- [ ] Version numbers are correct
- [ ] All pre-release modifications look correct
- [ ] CI checks pass
- [ ] Version gate check passes

### Next steps
After merging this PR, run the **Release** workflow with branch \`${RELEASE_BRANCH}\`.
EOF
)"
133 changes: 133 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Release

on:
workflow_dispatch:
inputs:
release-branch:
description: "Release branch (e.g. release-1.5)"
required: true
type: string

permissions:
contents: write

Comment on lines +11 to +13

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

Reduce workflow token scope to least privilege.

contents: write at workflow scope grants write access to jobs that do not need it. Scope write permission only to jobs that create tags/releases.

Suggested fix
 permissions:
-  contents: write
+  contents: read

 jobs:
+  tag:
+    permissions:
+      contents: write
+    needs: [read-version, smoke-tests]
+    runs-on: ubuntu-latest
+    steps:
+      ...
+
+  create-release:
+    permissions:
+      contents: write
+    needs: [read-version, build-image]
+    runs-on: ubuntu-latest
+    steps:
+      ...
🧰 Tools
🪛 zizmor (1.26.1)

[error] 12-12: 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 11 - 13, The `contents: write`
permission is currently set at the workflow level, granting write access to all
jobs. Move this permission to only the specific job(s) that create tags or
releases by removing `contents: write` from the workflow-level permissions block
and adding it as a job-level permission to only the job(s) that perform release
operations. This ensures other jobs in the workflow operate with minimal
necessary privileges.

Source: Linters/SAST tools

jobs:
read-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.parse.outputs.version }}
major: ${{ steps.parse.outputs.major }}
minor: ${{ steps.parse.outputs.minor }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.release-branch }}
Comment on lines +22 to +24

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

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/release.yaml

Repository: Kuadrant/authorino

Length of output: 4881


Pin GitHub Actions to commit SHAs instead of mutable version tags.

Using @v4/@v5 allows silent upstream changes and weakens supply-chain security guarantees. Pin all GitHub Actions to their full commit SHAs: actions/checkout@<commit-sha> and actions/setup-go@<commit-sha>.

This applies to lines 22, 60, 65, 82, and 112 in this workflow file.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 22-24: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 22-22: 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 22 - 24, Replace all mutable
GitHub Actions version tags in the release.yaml workflow with pinned commit
SHAs. Specifically, replace the `@v4` tag in the actions/checkout action on line
22, and locate the other GitHub Actions usages at lines 60, 65, 82, and 112,
then replace their mutable version tags (such as `@v4` or `@v5`) with their full
commit SHAs. You can find the correct commit SHAs by looking up each action's
releases on GitHub or using the GitHub CLI. This ensures that the workflow uses
immutable action references and prevents silent upstream changes that could
affect supply-chain security.

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

- name: Parse version from release.yaml
id: parse
run: |
chmod +x .github/scripts/parse-version.sh
.github/scripts/parse-version.sh

- name: Validate branch matches version
run: |
EXPECTED_BRANCH="release-${{ steps.parse.outputs.major }}.${{ steps.parse.outputs.minor }}"
if [[ "${{ inputs.release-branch }}" != "$EXPECTED_BRANCH" ]]; then
echo "::error::Branch '${{ inputs.release-branch }}' does not match version ${{ steps.parse.outputs.version }} (expected branch: $EXPECTED_BRANCH)"
exit 1
Comment on lines +38 to +43

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

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the release.yaml file
git ls-files | grep -E 'release\.yaml|release\.yml'

Repository: Kuadrant/authorino

Length of output: 235


🏁 Script executed:

# Check the content around lines 38-43 of the release.yaml file
cat -n .github/workflows/release.yaml | sed -n '30,50p'

Repository: Kuadrant/authorino

Length of output: 1127


🌐 Web query:

GitHub Actions security best practices context interpolation shell script injection

💡 Result:

The primary risk of context interpolation in GitHub Actions arises because workflow expressions (the ${{ ... }} syntax) are evaluated by the GitHub Actions runner before the shell executes your script [1][2][3]. When you directly interpolate untrusted context values—such as github.event.issue.title or github.event.pull_request.head_ref—into a run step, you inadvertently allow an attacker to inject arbitrary shell commands [1][4][3]. To secure your workflows against this script injection vulnerability, follow these best practices: 1. Use Intermediate Environment Variables (Recommended) Never place ${{ ... }} expressions directly inside your shell command [5][6][3]. Instead, map the untrusted value to an environment variable in the env block of the step, and then reference that variable using the native shell syntax (e.g., $VAR or "$VAR") [7][5][3]. Vulnerable Example: run: echo "Processing PR: ${{ github.event.pull_request.title }}" Secure Example: env: PR_TITLE: ${{ github.event.pull_request.title }} run: echo "Processing PR: $PR_TITLE" 2. Avoid Re-interpolation Do not use ${{ env.VAR }} inside a run step to access an environment variable [5][6][3]. This re-introduces the interpolation vulnerability because the expression is evaluated before the shell executes the command [6][3]. Always use native shell syntax (e.g., $VAR) to access variables created in the env block [5][3]. 3. Use Actions for Complex Logic When possible, replace inline shell scripts with custom actions or existing community actions that process data as arguments rather than generating shell scripts [7][8]. Because arguments are passed directly to the action's code rather than being concatenated into a shell command string, this approach is inherently resistant to script injection [7][8]. 4. Treat All Contexts as Untrusted Any context that can be influenced by external users, such as PR titles, issue bodies, branch names, or author names, must be treated as untrusted input [1][4]. Be especially cautious with workflows triggered by events like pull_request, issue_comment, or workflow_run [8][3]. 5. Enable Security Scanning Use tools like CodeQL or ESLint plugins (e.g., eslint-plugin-github-actions) to automatically detect and flag unsafe interpolation of context values in your workflow YAML files [9][10]. Enabling code scanning helps prevent these vulnerabilities from being introduced in future changes [9].

Citations:


🏁 Script executed:

# Check the workflow trigger and input definitions
cat -n .github/workflows/release.yaml | sed -n '1,30p'

Repository: Kuadrant/authorino

Length of output: 1092


Pass inputs.release-branch via an environment variable to prevent shell injection.

Line 41–42 directly interpolates the workflow dispatch input into a bash script, which allows shell command injection if the input contains metacharacters. GitHub Actions evaluates ${{ ... }} expressions before the shell executes, making the input available for expansion. Pass the input through the env block and reference it with native shell syntax instead.

Suggested fix
       - name: Validate branch matches version
+        env:
+          INPUT_RELEASE_BRANCH: ${{ inputs.release-branch }}
         run: |
           EXPECTED_BRANCH="release-${{ steps.parse.outputs.major }}.${{ steps.parse.outputs.minor }}"
-          if [[ "${{ inputs.release-branch }}" != "$EXPECTED_BRANCH" ]]; then
-            echo "::error::Branch '${{ inputs.release-branch }}' does not match version ${{ steps.parse.outputs.version }} (expected branch: $EXPECTED_BRANCH)"
+          if [[ "$INPUT_RELEASE_BRANCH" != "$EXPECTED_BRANCH" ]]; then
+            echo "::error::Branch '$INPUT_RELEASE_BRANCH' does not match version ${{ steps.parse.outputs.version }} (expected branch: $EXPECTED_BRANCH)"
             exit 1
           fi
🧰 Tools
🪛 zizmor (1.26.1)

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

(template-injection)


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

(template-injection)


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

(template-injection)


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

(template-injection)


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

(template-injection)

🤖 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 38 - 43, The step "Validate
branch matches version" directly interpolates the workflow input
`inputs.release-branch` into the bash script, creating a shell injection
vulnerability. Move `inputs.release-branch` to an environment variable by adding
an `env` block to the step that sets a variable (e.g., `RELEASE_BRANCH: ${{
inputs.release-branch }}`), then update the bash script to reference this
environment variable using native shell syntax (e.g., `$RELEASE_BRANCH`) instead
of the direct `${{ inputs.release-branch }}` interpolation on lines 41-42.

Source: Linters/SAST tools

fi

- name: Check for existing release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.parse.outputs.version }}"
if gh release view "v${VERSION}" &>/dev/null; then
echo "::error::GitHub Release v${VERSION} already exists"
exit 1
fi

smoke-tests:
needs: read-version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.release-branch }}

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Lint
run: make lint

- name: Unit tests
run: make test

- name: CEL validation tests
run: make test-cel

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
run: |
VERSION="${{ needs.read-version.outputs.version }}"
TAG="v${VERSION}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "::error::Tag $TAG already exists"
exit 1
fi
Comment on lines +91 to +94

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Make tag creation idempotent for safe reruns.

If a previous run pushed the tag but failed later, reruns will always fail here and block recovery. Treat “tag already exists at HEAD” as success.

Suggested fix
           if git rev-parse "$TAG" >/dev/null 2>&1; then
-            echo "::error::Tag $TAG already exists"
-            exit 1
+            TAG_SHA="$(git rev-list -n1 "$TAG")"
+            HEAD_SHA="$(git rev-parse HEAD)"
+            if [[ "$TAG_SHA" != "$HEAD_SHA" ]]; then
+              echo "::error::Tag $TAG already exists and points to $TAG_SHA, not $HEAD_SHA"
+              exit 1
+            fi
+            echo "Tag $TAG already exists at HEAD; continuing"
+            exit 0
           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.

Suggested change
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "::error::Tag $TAG already exists"
exit 1
fi
if git rev-parse "$TAG" >/dev/null 2>&1; then
TAG_SHA="$(git rev-list -n1 "$TAG")"
HEAD_SHA="$(git rev-parse HEAD)"
if [[ "$TAG_SHA" != "$HEAD_SHA" ]]; then
echo "::error::Tag $TAG already exists and points to $TAG_SHA, not $HEAD_SHA"
exit 1
fi
echo "Tag $TAG already exists at HEAD; continuing"
exit 0
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 91 - 94, The tag existence check
in the release workflow is not idempotent - it fails unconditionally whenever
the tag already exists, blocking recovery from partial failures. Modify the git
tag validation logic to check if the tag exists at the current HEAD commit
rather than just checking if the tag exists. If the tag already points to HEAD,
allow the workflow to proceed as success. Only exit with an error if the tag
exists but points to a different commit, indicating a genuine conflict.

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"

build-image:
needs: [read-version, tag]
uses: ./.github/workflows/build-images.yaml
with:
version: ${{ needs.read-version.outputs.version }}
ref: v${{ needs.read-version.outputs.version }}
secrets: inherit

create-release:
needs: [read-version, build-image]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.release-branch }}
fetch-depth: 0

- name: Create GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ needs.read-version.outputs.version }}"
TAG="v${VERSION}"

PREV_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "")

NOTES_ARGS="--generate-notes"
if [[ -n "$PREV_TAG" ]]; then
NOTES_ARGS="$NOTES_ARGS --notes-start-tag $PREV_TAG"
fi

gh release create "$TAG" \
--title "Release $TAG" \
$NOTES_ARGS
Loading
Loading