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
77 changes: 77 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
MCP_IMAGE_NAME: ${{ github.repository }}-mcp-server

jobs:
release:
name: Create Draft Release
runs-on: ubuntu-latest
steps:
- name: Validate tag format
run: |
TAG="${{ github.ref_name }}"
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid tag format: ${TAG}. Expected vMAJOR.MINOR.PATCH (e.g., v0.12.0)"
exit 1
fi
Comment on lines +21 to +27

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

Unsanitized ${{ github.ref_name }}/context values interpolated directly into run: scripts (template injection).

Lines 23, 37, 54, 66, 71-73 splice GitHub context expressions (github.ref_name, steps.info.outputs.*, github.repository) directly into shell script text rather than passing them through env:. Notably, the very step meant to validate the tag (line 21-27) itself performs this interpolation before any validation occurs, so a maliciously-crafted tag name (by anyone with tag-push access) could inject shell syntax before the format check ever runs. The standard mitigation is to pass these values via env: and reference them as "$VAR" inside the script, which makes the value pure data instead of script text.

🔒 Proposed fix (pattern to apply at each flagged step)
       - name: Validate tag format
+        env:
+          TAG: ${{ github.ref_name }}
         run: |
-          TAG="${{ github.ref_name }}"
           if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
             echo "::error::Invalid tag format: ${TAG}. Expected vMAJOR.MINOR.PATCH (e.g., v0.12.0)"
             exit 1
           fi

Apply the same env:-passing pattern to the "Determine release type" and "Summary" steps for github.ref_name, steps.info.outputs.type, and steps.info.outputs.minor.

📝 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
- name: Validate tag format
run: |
TAG="${{ github.ref_name }}"
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid tag format: ${TAG}. Expected vMAJOR.MINOR.PATCH (e.g., v0.12.0)"
exit 1
fi
- name: Validate tag format
env:
TAG: ${{ github.ref_name }}
run: |
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid tag format: ${TAG}. Expected vMAJOR.MINOR.PATCH (e.g., v0.12.0)"
exit 1
fi
🧰 Tools
🪛 zizmor (1.26.1)

[error] 23-23: 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.yml around lines 21 - 27, Update the release
workflow steps that use github.ref_name, steps.info.outputs.type,
steps.info.outputs.minor, or github.repository in run scripts, including
“Validate tag format,” “Determine release type,” and “Summary,” to pass each
value through the step’s env mapping and reference the resulting quoted
environment variables in shell commands. Ensure no GitHub context expressions
are interpolated directly into script text, while preserving the existing
validation and release-summary behavior.

Source: Linters/SAST tools


- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
Comment on lines +29 to +32

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l .github/workflows/release.yml
cat -n .github/workflows/release.yml | sed -n '1,220p'

Repository: redhat-data-and-ai/unstructured-data-controller

Length of output: 3223


Guard release tags before running hack/release.sh

Any push to v* can check out that tag’s commit and run hack/release.sh with contents: write and GH_TOKEN. Limit v* tag creation/update to trusted maintainers or require the tag to match protected release history before executing the script.

🧰 Tools
🪛 zizmor (1.26.1)

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

(artipacked)

🤖 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.yml around lines 29 - 32, Update the release
workflow before the hack/release.sh execution to guard v* tag pushes: allow only
trusted maintainers or validate that the tag matches protected release history,
and skip the release script otherwise. Preserve the existing checkout and
release behavior for authorized, validated tags.


- name: Determine release type
id: info
run: |
TAG="${{ github.ref_name }}"
PATCH_NUM="${TAG##*.}"
MINOR_VERSION="${TAG%.*}"
if [[ "$PATCH_NUM" == "0" ]]; then
echo "type=minor" >> "$GITHUB_OUTPUT"
else
echo "type=patch" >> "$GITHUB_OUTPUT"
fi
echo "minor_version=${MINOR_VERSION}" >> "$GITHUB_OUTPUT"

- name: Run release script (minor)
if: steps.info.outputs.type == 'minor'
env:
GH_TOKEN: ${{ github.token }}
run: |
chmod +x hack/release.sh
hack/release.sh minor --version "${{ github.ref_name }}" --force

- name: Run release script (patch)
if: steps.info.outputs.type == 'patch'
env:
GH_TOKEN: ${{ github.token }}
run: |
chmod +x hack/release.sh
hack/release.sh patch "${{ steps.info.outputs.minor_version }}" --version "${{ github.ref_name }}" --force

- name: Summary
run: |
TAG="${{ github.ref_name }}"
{
echo "## Draft Release ${TAG}"
echo ""
echo "- **Release**: https://github.com/${{ github.repository }}/releases/tag/${TAG}"
echo "- **Controller image**: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${TAG}\`"
echo "- **MCP server image**: \`${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }}:${TAG}\`"
if [[ "${{ steps.info.outputs.type }}" == "minor" ]]; then
echo "- **Release branch**: \`release-${{ steps.info.outputs.minor_version }}.x\`"
fi
echo ""
echo "> **Note:** This is a draft release. Review the release notes and publish when ready."
} >> "$GITHUB_STEP_SUMMARY"
Loading
Loading