Skip to content

Refactor release workflows with reusable GitHub Actions#55

Open
Boomatang wants to merge 2 commits into
mainfrom
workflow-update
Open

Refactor release workflows with reusable GitHub Actions#55
Boomatang wants to merge 2 commits into
mainfrom
workflow-update

Conversation

@Boomatang
Copy link
Copy Markdown
Member

@Boomatang Boomatang commented May 6, 2026

Summary

This PR refactors the release automation workflows by extracting inline bash scripts into reusable GitHub composite actions, improving maintainability and adding a new Sector-specific release workflow.

Changes

New Composite Actions

Created 12 reusable GitHub composite actions under .github/actions/:

  • validate-version: Validates semver format
  • create-release-branch: Creates or checks out release branches
  • update-makefile-version: Updates VERSION in Makefile
  • update-makefile-expiry: Updates QUAY_IMAGE_EXPIRY in Makefile
  • prepare-release-branch: Orchestrates version validation, branch creation, and Makefile updates
  • get-version-from-makefile: Extracts VERSION from Makefile
  • check-tag-exists: Validates git tag existence
  • create-and-push-tag: Creates and pushes git tags
  • detect-prerelease: Determines if version is a prerelease
  • prepare-release-tag: Orchestrates tag creation and metadata
  • generate-release-notes: Generates release notes using existing script
  • create-release: Creates GitHub releases

Workflow Updates

  • automated-release.yaml: Refactored to use new composite actions (reduced from ~74 to ~27 lines of workflow logic)
  • release.yaml: Refactored to use new composite actions (reduced from ~85 to ~27 lines of workflow logic)
  • sector-release.yaml: New workflow for Sector-specific automated releases with prepare and release jobs

Benefits

  • DRY Principle: Eliminated code duplication across workflows
  • Maintainability: Changes to release logic now require updates in one place
  • Testability: Composite actions can be tested independently
  • Reusability: Actions can be used across multiple workflows
  • Readability: Workflows are now more concise and easier to understand

Testing

  • Workflows maintain the same functionality as before
  • All existing release processes remain compatible

Summary by CodeRabbit

  • Chores
    • Implemented a suite of reusable GitHub Actions for version validation, tag checks/creation, release-branch preparation, release-note generation and release creation, plus Makefile version/expiry updates and prerelease detection.
    • Refactored automated release workflows to use these modular actions for improved maintainability and consistency.
    • Added a new sector-specific automated release workflow and updated the main release workflow to invoke the new actions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Warning

Rate limit exceeded

@Boomatang has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 24 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9fe33845-8a64-44ad-809e-b1af6133a210

📥 Commits

Reviewing files that changed from the base of the PR and between 3428cdf and 553411d.

📒 Files selected for processing (15)
  • .github/actions/check-tag-exists/action.yaml
  • .github/actions/create-and-push-tag/action.yaml
  • .github/actions/create-release-branch/action.yaml
  • .github/actions/create-release/action.yaml
  • .github/actions/detect-prerelease/action.yaml
  • .github/actions/generate-release-notes/action.yaml
  • .github/actions/get-version-from-makefile/action.yaml
  • .github/actions/prepare-release-branch/action.yaml
  • .github/actions/prepare-release-tag/action.yaml
  • .github/actions/update-makefile-expiry/action.yaml
  • .github/actions/update-makefile-version/action.yaml
  • .github/actions/validate-version/action.yaml
  • .github/workflows/automated-release.yaml
  • .github/workflows/release.yaml
  • .github/workflows/sector-release.yaml
📝 Walkthrough

Walkthrough

Adds a suite of new local composite GitHub Actions for release automation (version validation, Makefile updates, branch/tag creation, release notes), updates existing release workflows to use those actions, and adds a new sector-release workflow that composes the actions into a two-job release flow.

Changes

Release automation and workflow orchestration

Layer / File(s) Summary
Utilities / Validation & Extraction
.github/actions/validate-version/action.yaml, .github/actions/get-version-from-makefile/action.yaml, .github/actions/detect-prerelease/action.yaml
Actions to validate semver, extract VERSION and tag from Makefile, and detect prerelease versions.
Git operations
.github/actions/check-tag-exists/action.yaml, .github/actions/create-and-push-tag/action.yaml, .github/actions/create-release-branch/action.yaml
Actions to check tag existence and association with current commit, create and push annotated tags, and derive/create/check out release branches with optional push.
Makefile mutations
.github/actions/update-makefile-version/action.yaml, .github/actions/update-makefile-expiry/action.yaml
Actions to update Makefile variables VERSION and QUAY_IMAGE_EXPIRY via shell/sed steps.
Orchestration composite actions
.github/actions/prepare-release-tag/action.yaml, .github/actions/prepare-release-branch/action.yaml, .github/actions/generate-release-notes/action.yaml, .github/actions/create-release/action.yaml
Higher-level composites that sequence the utility and git operation actions: preparing tags/branches, generating release notes, and creating GitHub releases (invoking softprops action).
Workflow wiring / new workflow
.github/workflows/automated-release.yaml, .github/workflows/release.yaml, .github/workflows/sector-release.yaml
Workflows updated to call the new composites: automated-release now runs prepare-release-branch, release workflow sets checkout ref and fetch-depth and runs create-release, and a new sector-release workflow orchestrates prepare-release and release jobs using local actions.
sequenceDiagram
  autonumber
  actor User
  participant Workflow as GitHub Workflow
  participant Prep as prepare-release-branch (local action)
  participant TagPrep as prepare-release-tag (local action)
  participant Git as Git (checkout, tag, branch)
  participant Makefile as Makefile (repo)
  participant GH_API as GitHub API / softprops

  User->>Workflow: trigger (manual or push)
  Workflow->>Prep: run (version, push-branch, expiry)
  Prep->>Validate: validate-version
  Note right of Prep: validate-version, create-release-branch, update-makefile-version, update-makefile-expiry
  Prep->>Git: create/check branch & push (optional)
  Prep->>Makefile: update VERSION / expiry
  Workflow->>TagPrep: run create-release steps (tag, notes)
  TagPrep->>Git: check-tag-exists / create-and-push-tag
  TagPrep->>Makefile: read version
  TagPrep->>GH_API: create release (generate-release-notes -> GH API)
  GH_API-->>Workflow: release created
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through files with a careful twitch,
Composed actions, tags and branches stitched.
Makefile whispers the version true,
Tags pushed, notes brewed — a release anew.
Hip-hop hooray, the pipeline’s rich!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarises the primary change: refactoring release workflows by extracting inline bash into 12 reusable GitHub composite actions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch workflow-update

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Boomatang Boomatang moved this to Ready For Review in Kuadrant May 6, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release.yaml (1)

17-22: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The pull_request: closed case is handled correctly; workflow_dispatch case lacks a ref constraint.

For pull_request events where the PR was merged (checked by the merged == true condition), GitHub Actions correctly sets github.ref_name to the target branch name—in this case, the release branch that the PR was merged into. The checkout will work as intended.

However, for workflow_dispatch triggers, github.ref_name defaults to the branch the workflow file was dispatched from, which is typically the default branch, not a release-v* branch. The workflow will checkout and tag the wrong commit. To restrict dispatch to release branches, add an input parameter:

on:
  workflow_dispatch:
    inputs:
      release_branch:
        description: 'Release branch (release-v*)'
        required: true
        type: choice
        options:
          - release-v1.0
          - release-v1.1

Then use ref: ${{ inputs.release_branch }} in the checkout step (and fallback to github.ref_name for the pull_request case).

🤖 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 17 - 22, The workflow_dispatch
trigger lacks a constrained ref so the Checkout step (uses: actions/checkout@v4,
ref: ${{ github.ref_name }}) can checkout the wrong branch; add a required
workflow_dispatch input (e.g., inputs.release_branch) that restricts choices to
release-v* branches and update the Checkout step to use ref: ${{
inputs.release_branch }} with a fallback to github.ref_name for the
pull_request/merged path so dispatches must specify the release branch while PR
merges continue to use github.ref_name.
🧹 Nitpick comments (5)
.github/actions/detect-prerelease/action.yaml (1)

19-19: 💤 Low value

Prerelease regex is overly permissive.

-(alpha|beta|rc) will match anywhere in the version (e.g. 1.0.0-alphabet-build, 1.0.0+build-rc-meta). For semver-style prereleases you usually want the token to follow - immediately and be terminated by ., +, or end-of-string. Consider anchoring with a word boundary, e.g. -(alpha|beta|rc)(\.|\+|$).

🤖 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/actions/detect-prerelease/action.yaml at line 19, The prerelease
detection regex in the if conditional using the VERSION variable (if [[
"$VERSION" =~ -(alpha|beta|rc) ]]; then) is too permissive; update the pattern
to require the prerelease token to follow '-' and be terminated by a dot, plus,
or end-of-string (for example change the match to -(alpha|beta|rc)(\.|\+|$)) so
only proper semver-style prereleases are detected; locate and replace the regex
in the if [[ "$VERSION" =~ ... ]] conditional in action.yaml.
.github/actions/prepare-release-tag/action.yaml (1)

13-15: 💤 Low value

tag-created reports intent rather than outcome.

The output is computed solely from steps.check-tag.outputs.exists == 'false', so it is true whenever the tag was missing — even if the Create and push tag step subsequently failed or was skipped. If consumers rely on this to gate downstream behaviour (release creation, notifications), consider either giving the create step an id and basing the output on its outcome/conclusion, or renaming the output to tag-was-missing to reflect what is actually being measured.

🤖 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/actions/prepare-release-tag/action.yaml around lines 13 - 15, The
output `tag-created` currently reflects only `steps.check-tag.outputs.exists ==
'false'` (i.e. whether the tag was missing) rather than the actual creation
result; either change this to derive from the "Create and push tag" step's
result by giving that step an `id` (e.g. `create-tag`) and setting `tag-created`
to check `steps.create-tag.outcome` or `steps.create-tag.conclusion`, or rename
the output to `tag-was-missing` to accurately describe its current meaning
(`value: ${{ steps.check-tag.outputs.exists == 'false' }}`) and add a new
`tag-created` output based on the create step outcome if you need the true
outcome for downstream gates.
.github/workflows/sector-release.yaml (1)

38-46: ⚖️ Poor tradeoff

Consider moving the commit/push into the composite action.

The prepare-release-branch action creates the branch and rewrites the Makefile, but leaves the resulting working-tree changes uncommitted, forcing every consumer (this workflow today, potentially others later) to re-implement the same git config + git commit + git push boilerplate. Rolling that responsibility into the action — perhaps gated on the existing push-branch input — would make the behaviour symmetric with the automated-release.yaml flow (where peter-evans/create-pull-request handles the commit) and remove duplication.

🤖 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/sector-release.yaml around lines 38 - 46, Move the
commit/push boilerplate into the prepare-release-branch composite action so
consumers don't repeat it: update the composite action (prepare-release-branch)
to perform git config user.email and user.name, run git commit with the same
message format ("Prepare release ${{ github.event.inputs.version }}") and push
to the branch name produced as outputs.branch-name, and make this behavior
conditional on the composite's existing push-branch input (only commit & push
when push-branch is true); then remove the "Commit and push changes" step from
the workflow.
.github/actions/create-release/action.yaml (2)

15-26: ⚡ Quick win

Consider refactoring to use action outputs instead of relying on environment variables.

The Generate release notes step implicitly sets env.releaseBody via GITHUB_ENV in the bash script it runs (lines 31-33 of ./utils/release/github-release-changelog.sh). Whilst this currently works, the contract is not explicit in the action definition.

Refactor the generate-release-notes action to define an output and write to GITHUB_OUTPUT instead. This would allow the Create GitHub Release step to consume steps.notes.outputs.body, making the data flow explicit and far easier to audit.

🤖 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/actions/create-release/action.yaml around lines 15 - 26, Refactor
the generate-release-notes action (./.github/actions/generate-release-notes and
its script ./utils/release/github-release-changelog.sh) to emit the changelog
via a defined action output instead of writing to GITHUB_ENV: modify the script
to write the release body to GITHUB_OUTPUT (e.g., "body=<content>" >>
"$GITHUB_OUTPUT") and add an outputs entry in the action metadata so the action
exposes output "body"; then update the workflow steps (the "Generate release
notes" step and the "Create GitHub Release" step) to consume that output (use
steps.generate-release-notes.outputs.body for the softprops/action-gh-release
body and avoid relying on env.releaseBody).

21-30: ⚡ Quick win

Pin softprops/action-gh-release to a commit SHA.

Floating major tags (@v2) can be force-moved by the upstream maintainer, which is a supply-chain risk for a release-publishing action that runs with a privileged PAT. Pinning to a full commit SHA (with the version as a comment) is the GitHub-recommended hardening for third-party actions in release-critical paths.

🤖 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/actions/create-release/action.yaml around lines 21 - 30, Replace the
floating action reference softprops/action-gh-release@v2 with a pinned commit
SHA: update the uses: line in the Create GitHub Release step to use the full
commit SHA for softprops/action-gh-release (keeping “@v2” as a comment for
clarity), preserving all existing inputs (name, tag_name, body,
target_commitish, prerelease) and the GITHUB_TOKEN env mapping; ensure the SHA
points to a commit on the action repo and add a short inline comment noting the
original `@v2` version.
🤖 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/actions/check-tag-exists/action.yaml:
- Around line 18-19: The step currently assigns TAG="${{ inputs.tag }}" directly
into the bash script which allows script injection; change the action to pass
the tag via the env block (e.g., set env: TAG: ${{ inputs.tag }} and
CURRENT_SHA: ${{ github.sha }}) and then reference $TAG inside the run script so
the value is treated as data; update the action.yaml step that defines
TAG/CURRENT_SHA to use env instead of inline interpolation and ensure any use of
TAG in the run section is quoted (e.g., "$TAG") to avoid word-splitting.

In @.github/actions/create-and-push-tag/action.yaml:
- Around line 16-19: The step currently embeds the expression `${{ inputs.tag
}}` directly into the shell which can enable script injection; change the step
to set the input into an environment variable (e.g. create env: TAG: ${{
inputs.tag }}) and then reference that env var inside the shell script (use
"$TAG" for the tag and in the git tag/git push commands) so the value is treated
as data; update occurrences that set TAG and the lines running git tag -a and
git push to use the env-provided TAG.

In @.github/actions/create-release-branch/action.yaml:
- Around line 25-41: The workflow exposes a script-injection risk by
template-expanding inputs.version and inputs.push directly into the shell; move
both ${{ inputs.version }} and ${{ inputs.push }} into environment variables
(e.g., VERSION and PUSH) and use those env vars inside the script,
sanitize/strip dangerous chars if needed, and ensure all branch uses of
base_branch (the variable computed in the script) are quoted (e.g., where git
checkout, git checkout -b and git push reference $base_branch) to avoid
word-splitting or injection; update the logic that computes base_branch so it
reads from VERSION, and change the conditional that compares PUSH to "true" to
reference the PUSH env var.

In @.github/actions/create-release/action.yaml:
- Around line 3-7: The action lacks an inputs declaration for the release branch
(and optionally tag) referenced later; add an inputs entry named release-branch
(and optionally tag) to the inputs: block so callers can supply it, and update
usages that set target_commitish to read from inputs.release-branch (or fallback
to github.ref_name) in the action metadata; alternatively ensure the
prepare-release-tag step or the workflows (.github/workflows/release.yaml and
sector-release.yaml) pass the new inputs.release-branch value when invoking this
action so softprops/action-gh-release receives a non-empty target_commitish.

In @.github/actions/detect-prerelease/action.yaml:
- Around line 17-23: Avoid direct interpolation of ${{ inputs.version }} into
the run block: move the input into the action environment (set an env variable
like VERSION from inputs.version) and reference it in the script as a quoted
shell variable ("$VERSION") instead of embedding the template, and also quote
"$GITHUB_OUTPUT" when appending output; update the run block that currently sets
VERSION="${{ inputs.version }}" and writes to $GITHUB_OUTPUT to instead read
from the env VERSION and use quoted variables to prevent shell injection.

In @.github/actions/get-version-from-makefile/action.yaml:
- Around line 17-20: The current extraction of VERSION into the VERSION variable
is fragile: modify the command that sets VERSION so it only captures a single
value (e.g., use grep -m1 or awk to take the first matching line and strip the
prefix) and trim whitespace, then validate that VERSION is non-empty and fail
fast if it is (emit a clear error and exit non-zero) before writing to
$GITHUB_OUTPUT; ensure subsequent writes use the validated single-line VERSION
for both "version" and "tag" to avoid malformed/multi-line outputs.

In @.github/actions/update-makefile-expiry/action.yaml:
- Around line 14-15: Move the input expiry into an env variable instead of
expanding `${{ inputs.expiry }}` inline (set QUAY_IMAGE_EXPIRY via an env block)
and then reference that env var in the run step; also harden the sed
substitution in the run command that updates the Makefile by switching the
delimiter from `/` to a different safe delimiter such as `|` (i.e., perform sed
-i "s|^QUAY_IMAGE_EXPIRY ?= .*|QUAY_IMAGE_EXPIRY ?= $QUAY_IMAGE_EXPIRY|") so the
replacement is not broken by values containing `/` while still using the
QUAY_IMAGE_EXPIRY env variable for substitution.

In @.github/actions/update-makefile-version/action.yaml:
- Around line 13-14: Replace direct expansion of ${{ inputs.version }} with
assigning it to an intermediate environment variable (e.g., VERSION) before any
shell execution to avoid GitHub expression injection; then update the sed
invocation that edits the Makefile (the line that currently runs sed -i
"s/^VERSION ?= .*/VERSION ?= $VERSION/") to use a safer delimiter such as | and
ensure the replacement side treats the VERSION variable literally (i.e., use a
quoted shell variable replacement with proper escaping/quoting) so that slashes,
ampersands, and backslashes in VERSION cannot break or corrupt the sed
substitution.

In @.github/actions/validate-version/action.yaml:
- Around line 13-16: The workflow currently assigns VERSION using the template
expansion VERSION="${{ inputs.version }}" which evaluates before shell execution
and risks command injection; change the action to pass the input into the shell
via an environment variable instead (e.g., map the input to an env like
INPUT_VERSION or VERSION in the action.yml/step and then in the script use
VERSION="$VERSION" or read from $INPUT_VERSION), then run the semver regex check
against that environment variable (the symbols to update are the VERSION
assignment and the regex check) so no template expansion happens inside the
shell command.

In @.github/workflows/sector-release.yaml:
- Around line 38-45: The job fails when running the "Commit and push changes"
step because git commit . exits non-zero if there are no staged changes; update
that step (the run block that calls git commit . -s -m "Prepare release ${{
github.event.inputs.version }}") to first check for changes (e.g., by testing
git status --porcelain or git diff --quiet) and only run git commit when there
are staged changes, or alternatively use git commit --allow-empty to make the
commit idempotent; adjust the step that references
steps.prepare-branch.outputs.branch-name accordingly so the push still occurs in
either case.

---

Outside diff comments:
In @.github/workflows/release.yaml:
- Around line 17-22: The workflow_dispatch trigger lacks a constrained ref so
the Checkout step (uses: actions/checkout@v4, ref: ${{ github.ref_name }}) can
checkout the wrong branch; add a required workflow_dispatch input (e.g.,
inputs.release_branch) that restricts choices to release-v* branches and update
the Checkout step to use ref: ${{ inputs.release_branch }} with a fallback to
github.ref_name for the pull_request/merged path so dispatches must specify the
release branch while PR merges continue to use github.ref_name.

---

Nitpick comments:
In @.github/actions/create-release/action.yaml:
- Around line 15-26: Refactor the generate-release-notes action
(./.github/actions/generate-release-notes and its script
./utils/release/github-release-changelog.sh) to emit the changelog via a defined
action output instead of writing to GITHUB_ENV: modify the script to write the
release body to GITHUB_OUTPUT (e.g., "body=<content>" >> "$GITHUB_OUTPUT") and
add an outputs entry in the action metadata so the action exposes output "body";
then update the workflow steps (the "Generate release notes" step and the
"Create GitHub Release" step) to consume that output (use
steps.generate-release-notes.outputs.body for the softprops/action-gh-release
body and avoid relying on env.releaseBody).
- Around line 21-30: Replace the floating action reference
softprops/action-gh-release@v2 with a pinned commit SHA: update the uses: line
in the Create GitHub Release step to use the full commit SHA for
softprops/action-gh-release (keeping “@v2” as a comment for clarity), preserving
all existing inputs (name, tag_name, body, target_commitish, prerelease) and the
GITHUB_TOKEN env mapping; ensure the SHA points to a commit on the action repo
and add a short inline comment noting the original `@v2` version.

In @.github/actions/detect-prerelease/action.yaml:
- Line 19: The prerelease detection regex in the if conditional using the
VERSION variable (if [[ "$VERSION" =~ -(alpha|beta|rc) ]]; then) is too
permissive; update the pattern to require the prerelease token to follow '-' and
be terminated by a dot, plus, or end-of-string (for example change the match to
-(alpha|beta|rc)(\.|\+|$)) so only proper semver-style prereleases are detected;
locate and replace the regex in the if [[ "$VERSION" =~ ... ]] conditional in
action.yaml.

In @.github/actions/prepare-release-tag/action.yaml:
- Around line 13-15: The output `tag-created` currently reflects only
`steps.check-tag.outputs.exists == 'false'` (i.e. whether the tag was missing)
rather than the actual creation result; either change this to derive from the
"Create and push tag" step's result by giving that step an `id` (e.g.
`create-tag`) and setting `tag-created` to check `steps.create-tag.outcome` or
`steps.create-tag.conclusion`, or rename the output to `tag-was-missing` to
accurately describe its current meaning (`value: ${{
steps.check-tag.outputs.exists == 'false' }}`) and add a new `tag-created`
output based on the create step outcome if you need the true outcome for
downstream gates.

In @.github/workflows/sector-release.yaml:
- Around line 38-46: Move the commit/push boilerplate into the
prepare-release-branch composite action so consumers don't repeat it: update the
composite action (prepare-release-branch) to perform git config user.email and
user.name, run git commit with the same message format ("Prepare release ${{
github.event.inputs.version }}") and push to the branch name produced as
outputs.branch-name, and make this behavior conditional on the composite's
existing push-branch input (only commit & push when push-branch is true); then
remove the "Commit and push changes" step from the workflow.
🪄 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: a362c59f-b981-4e85-981e-45f48c65dfe1

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab4c10 and 3428cdf.

📒 Files selected for processing (15)
  • .github/actions/check-tag-exists/action.yaml
  • .github/actions/create-and-push-tag/action.yaml
  • .github/actions/create-release-branch/action.yaml
  • .github/actions/create-release/action.yaml
  • .github/actions/detect-prerelease/action.yaml
  • .github/actions/generate-release-notes/action.yaml
  • .github/actions/get-version-from-makefile/action.yaml
  • .github/actions/prepare-release-branch/action.yaml
  • .github/actions/prepare-release-tag/action.yaml
  • .github/actions/update-makefile-expiry/action.yaml
  • .github/actions/update-makefile-version/action.yaml
  • .github/actions/validate-version/action.yaml
  • .github/workflows/automated-release.yaml
  • .github/workflows/release.yaml
  • .github/workflows/sector-release.yaml

Comment thread .github/actions/check-tag-exists/action.yaml Outdated
Comment thread .github/actions/create-and-push-tag/action.yaml Outdated
Comment thread .github/actions/create-release-branch/action.yaml Outdated
Comment thread .github/actions/create-release/action.yaml
Comment thread .github/actions/detect-prerelease/action.yaml
Comment thread .github/actions/get-version-from-makefile/action.yaml Outdated
Comment on lines +14 to +15
QUAY_IMAGE_EXPIRY="${{ inputs.expiry }}"
sed -i "s/^QUAY_IMAGE_EXPIRY ?= .*/QUAY_IMAGE_EXPIRY ?= $QUAY_IMAGE_EXPIRY/" Makefile
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "action.yaml" -path "*update-makefile-expiry*" | head -5

Repository: Kuadrant/developer-portal-controller

Length of output: 133


🏁 Script executed:

cat -n .github/actions/update-makefile-expiry/action.yaml

Repository: Kuadrant/developer-portal-controller

Length of output: 780


🌐 Web query:

GitHub Actions inputs expansion security script injection env block vs run

💡 Result:

In GitHub Actions, expressions like ${{ inputs.myinput }} or ${{ github.event.pull_request.title }} undergo macro expansion before execution, creating security risks for script injection when used directly in run blocks versus env blocks. Vulnerable pattern in run block (direct expansion leads to command injection): - run: echo "Title: ${{ github.event.issue.title }}" If title is a"; ls;#, it expands to echo "Title: a"; ls;#", executing ls [1][2]. Safe pattern using env block: - env: TITLE: ${{ github.event.issue.title }} run: echo "Title: $TITLE" The untrusted value is set as an environment variable (no expansion in shell script generation), treated as literal string in shell. Shell expansion of $TITLE is safe as it's data, not code structure [3][1][4][5][2]. This applies to workflow inputs (inputs context) and github.event contexts, both potentially untrusted if caller-controlled. Official docs warn against direct use in run/script [1][6]. For reusable workflows (workflow_call), use inputs context safely via env [7]. Recommendation: Always route untrusted expressions (inputs, github.event fields like title/body) through env before run. Further sanitize in scripts if needed [3][8].

Citations:


🏁 Script executed:

# Check sed behavior with different delimiters and special characters
python3 << 'EOF'
import subprocess
import tempfile
import os

# Test case 1: sed with / delimiter and value containing /
test_cases = [
    ("never", "normal value", "/"),
    ("3w", "normal value", "/"),
    ("never/extra", "value with forward slash", "/"),
    ("never", "normal value", "|"),
]

for value, desc, delimiter in test_cases:
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as f:
        f.write("QUAY_IMAGE_EXPIRY ?= old_value\n")
        f.flush()
        fname = f.name
    
    try:
        if delimiter == "/":
            cmd = f'sed -i "s/^QUAY_IMAGE_EXPIRY ?= .*/QUAY_IMAGE_EXPIRY ?= {value}/" {fname}'
        else:
            cmd = f'sed -i "s|^QUAY_IMAGE_EXPIRY ?= .*|QUAY_IMAGE_EXPIRY ?= {value}|" {fname}'
        
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        with open(fname) as f:
            content = f.read()
        
        status = "✓ SUCCESS" if result.returncode == 0 else "✗ FAILED"
        print(f"{status}: value={value}, delimiter={delimiter}")
        print(f"  Description: {desc}")
        if result.returncode == 0:
            print(f"  Result: {content.strip()}")
        else:
            print(f"  Error: {result.stderr.strip()}")
    finally:
        os.unlink(fname)
    print()
EOF

Repository: Kuadrant/developer-portal-controller

Length of output: 525


Script injection and sed delimiter vulnerability.

Two issues:

  1. Script injection (Line 14): ${{ inputs.expiry }} expands directly in the run block before bash execution. Per GitHub Actions security documentation, this creates a script injection vector. Move the input to an env block to pass it safely as a literal string.

  2. sed delimiter fragility (Line 15): The sed command uses / as the delimiter. Testing confirms this fails if QUAY_IMAGE_EXPIRY contains / (e.g., with input never/extra, sed errors with "unknown option to 's'"). Although documented values (never, 3w) don't include /, there is no input validation. Switching to | as the delimiter makes the command robust for all cases.

🔒 Proposed fix
+      env:
+        INPUT_EXPIRY: ${{ inputs.expiry }}
       run: |
-        QUAY_IMAGE_EXPIRY="${{ inputs.expiry }}"
-        sed -i "s/^QUAY_IMAGE_EXPIRY ?= .*/QUAY_IMAGE_EXPIRY ?= $QUAY_IMAGE_EXPIRY/" Makefile
+        QUAY_IMAGE_EXPIRY="$INPUT_EXPIRY"
+        sed -i "s|^QUAY_IMAGE_EXPIRY ?= .*|QUAY_IMAGE_EXPIRY ?= $QUAY_IMAGE_EXPIRY|" Makefile
🤖 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/actions/update-makefile-expiry/action.yaml around lines 14 - 15,
Move the input expiry into an env variable instead of expanding `${{
inputs.expiry }}` inline (set QUAY_IMAGE_EXPIRY via an env block) and then
reference that env var in the run step; also harden the sed substitution in the
run command that updates the Makefile by switching the delimiter from `/` to a
different safe delimiter such as `|` (i.e., perform sed -i "s|^QUAY_IMAGE_EXPIRY
?= .*|QUAY_IMAGE_EXPIRY ?= $QUAY_IMAGE_EXPIRY|") so the replacement is not
broken by values containing `/` while still using the QUAY_IMAGE_EXPIRY env
variable for substitution.

Comment on lines +13 to +14
VERSION="${{ inputs.version }}"
sed -i "s/^VERSION ?= .*/VERSION ?= $VERSION/" Makefile
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, locate and read the target file
find . -type f -name "action.yaml" -path "*update-makefile-version*" | head -20

Repository: Kuadrant/developer-portal-controller

Length of output: 134


🏁 Script executed:

# Also search for update-makefile-expiry to compare
find . -type f -name "action.yaml" -path "*update-makefile-expiry*" | head -20

Repository: Kuadrant/developer-portal-controller

Length of output: 133


🏁 Script executed:

# List all action.yaml files to understand directory structure
find . -type f -name "action.yaml" | head -30

Repository: Kuadrant/developer-portal-controller

Length of output: 688


🏁 Script executed:

# Read the target file to verify the code at lines 13-14
cat -n ./.github/actions/update-makefile-version/action.yaml

Repository: Kuadrant/developer-portal-controller

Length of output: 654


🏁 Script executed:

# Read the reference file for comparison
cat -n ./.github/actions/update-makefile-expiry/action.yaml

Repository: Kuadrant/developer-portal-controller

Length of output: 780


🏁 Script executed:

# Check the validate-version action to see what validation it performs
cat -n ./.github/actions/validate-version/action.yaml

Repository: Kuadrant/developer-portal-controller

Length of output: 785


🏁 Script executed:

# Look at how validate-version is used in workflows
find . -type f \( -name "*.yml" -o -name "*.yaml" \) -path "*/.github/workflows/*" | head -20

Repository: Kuadrant/developer-portal-controller

Length of output: 355


🏁 Script executed:

# Search workflows to see how update-makefile-version is called
rg "update-makefile-version" ./.github/workflows/ -A 3 -B 3

Repository: Kuadrant/developer-portal-controller

Length of output: 62


🏁 Script executed:

# Check which workflows use update-makefile-version and validate-version
rg -l "update-makefile-version" ./.github/workflows/

Repository: Kuadrant/developer-portal-controller

Length of output: 62


🏁 Script executed:

# Broader search across entire repo
rg "update-makefile-version" . -l

Repository: Kuadrant/developer-portal-controller

Length of output: 62


🏁 Script executed:

# Check if any workflow files reference it indirectly or in comments
rg "update.*makefile.*version" . -i

Repository: Kuadrant/developer-portal-controller

Length of output: 62


🏁 Script executed:

# Also check for any documentation about these actions
find . -type f \( -name "README.md" -o -name "*.md" \) | xargs rg -l "makefile\|action" 2>/dev/null | head -10

Repository: Kuadrant/developer-portal-controller

Length of output: 62


🌐 Web query:

GitHub Actions script injection context variable expansion security

💡 Result:

In GitHub Actions, “script injection” happens when untrusted context data is expanded into code executed by the runner (most commonly inside a run:/script: block). GitHub explicitly warns that expression values inside ${ {... } } are evaluated and substituted before the temporary shell script is executed, which can make ${ {... } } a shell command injection sink if the value contains characters that alter the script’s structure. GitHub also notes that attackers can add malicious content to the github context and that those values should be treated as potentially untrusted input [1][2]. Key context variable expansion risks (and where to look) 1) Using ${ {... } } directly inside run/script blocks - GitHub describes an inline-script vulnerability pattern: run executes within a temporary shell script, and expressions inside ${ { } } are evaluated and substituted before execution, enabling injection (example uses an attacker-controlled pull request title to inject a command) [1][2]. - GitHub’s security hardening guidance says the recommended approach is to avoid inline script sinks and instead pass context values as action arguments, or use intermediate environment variables for inline scripts [2]. 2) Environment file injection via GITHUB_ENV (and related) - Writing untrusted data into the special environment files (especially GITHUB_ENV) can let an attacker inject additional environment variables via newline injection or delimiters, which can ultimately enable arbitrary code execution depending on what environment variables affect subsequent steps/processes [3][4]. - GitHub Security Lab advisories show real impact: if a workflow reads attacker-controlled content and appends it into $GITHUB_ENV, an attacker can set variables like LD_PRELOAD to affect subsequent processes and can lead to secret exfiltration and repository manipulation [5][6][7]. 3) “Contexts reference” is about availability/usage, not safety - Contexts (including github.* event fields) are intended to be used throughout workflows and are available for expressions/conditions, but that doesn’t make them safe for code execution sinks. Treat github.* fields as attacker-controlled when the workflow is triggered by events where attackers can influence those fields (e.g., PR titles/bodies/comments). GitHub’s script-injection guidance explicitly calls out github-context fields as potentially untrusted [1][8]. How to mitigate (grounded in GitHub guidance) A) Prefer actions over inline scripts - GitHub recommends using an action that processes the context value as an argument instead of generating shell scripts that interpolate expressions [2]. B) If you must use inline shell, use “intermediate environment variables” - GitHub recommends setting the expression to an intermediate environment variable first for inline scripts, so the expression result becomes a string variable rather than being injected into the generated shell script structure [2]. - GitHub’s blog post reiterates: when used in run/script, ${ { } } is usually very dangerous; putting ${ { } } in env: is safer because the value is stored in a variable instead [9]. C) Quote and treat as data, not code - Even when you use env: indirection, the value is still untrusted data and must be handled carefully (e.g., avoid eval-like behavior, ensure robust quoting and input validation). GitHub’s blog notes the env: approach doesn’t eliminate other classes of vulnerabilities; you still need to handle the untrusted value with care [9]. D) Never write untrusted input into GITHUB_ENV/GITHUB_PATH without strict sanitization - CodeQL’s query help states: defining env vars by writing to the file pointed to by GITHUB_ENV is vulnerable if an attacker can influence KEY=VALUE content, because they can inject additional variables by adding new lines/delimiters; it recommends not allowing untrusted data to influence environment variables and to validate/sanitize inputs [3][4]. - GitHub Security Lab advisories show that attacker-controlled files that are appended to GITHUB_ENV can let attackers inject arbitrary environment variables and impact subsequent command execution [5][7]. E) Reduce blast radius with least-privilege tokens - GitHub’s “secure use reference” recommends granting GITHUB_TOKEN the minimum required permissions (often defaulting to read-only for contents) to reduce impact if an injection occurs [10][11]. Practical checklist (quick) - Search your workflows for ${ {... } } inside run: and actions/github-script script: (those are common injection sinks) [1][2]. - For any workflow triggered by attacker-influenced sources (PR titles/bodies/comments, etc.), treat github.* values as untrusted input [1][8]. - For inline shell steps: move ${ {... } } into env: first, then reference via $VAR (do not interpolate into the shell script directly) [2][9]. - For any step writing to $GITHUB_ENV: ensure the content comes only from trusted sources; if it comes from artifacts/user input, validate/sanitize and prevent newline/KEY injection patterns [3][4][5][7]. - Apply least-privilege to GITHUB_TOKEN and keep secrets scope minimal [10][11].

Citations:


🏁 Script executed:

# Test sed vulnerability - does / character break the sed command?
python3 << 'EOF'
import subprocess
import tempfile
import os

# Create a temporary Makefile
with tempfile.TemporaryDirectory() as tmpdir:
    makefile_path = os.path.join(tmpdir, "Makefile")
    
    # Write a test Makefile
    with open(makefile_path, 'w') as f:
        f.write("VERSION ?= 1.0.0\n")
    
    test_cases = [
        ("1.2.3", "normal semver"),
        ("1.2.3-alpha", "semver with prerelease"),
        ("1/2/3", "version with slashes"),
        ("1.2.3&test", "version with ampersand"),
        ("1.2.3\\test", "version with backslash"),
    ]
    
    for version_str, description in test_cases:
        # Read original
        with open(makefile_path, 'r') as f:
            original = f.read()
        
        # Reset file
        with open(makefile_path, 'w') as f:
            f.write("VERSION ?= 1.0.0\n")
        
        # Try the vulnerable sed command
        cmd = f'sed -i "s/^VERSION ?= .*/VERSION ?= {version_str}/" {makefile_path}'
        result = subprocess.run(cmd, shell=True, cwd=tmpdir, capture_output=True, text=True)
        
        # Read result
        with open(makefile_path, 'r') as f:
            result_content = f.read()
        
        print(f"\n{description}: '{version_str}'")
        print(f"Command exit code: {result.returncode}")
        if result.stderr:
            print(f"Stderr: {result.stderr}")
        print(f"Result content:\n{result_content}")
        
        # Reset for next iteration
        with open(makefile_path, 'w') as f:
            f.write("VERSION ?= 1.0.0\n")

EOF

Repository: Kuadrant/developer-portal-controller

Length of output: 618


Script injection and sed delimiter vulnerability — fix before use.

  1. Script injection (Line 13): ${{ inputs.version }} expands directly into bash before execution. GitHub's security guidance explicitly identifies this as a vulnerable pattern. Use an intermediate environment variable instead.

  2. sed delimiter fragility (Line 14): / is the delimiter; a version string containing / breaks sed entirely (exit code 1), while & and \ cause silent corruption or misinterpretation. Use | as the delimiter.

Although validate-version constrains input to semver, update-makefile-version is a standalone action that can be called independently without validation.

Proposed fix
+      env:
+        INPUT_VERSION: ${{ inputs.version }}
       run: |
-        VERSION="${{ inputs.version }}"
-        sed -i "s/^VERSION ?= .*/VERSION ?= $VERSION/" Makefile
+        VERSION="$INPUT_VERSION"
+        sed -i "s|^VERSION ?= .*|VERSION ?= $VERSION|" Makefile
📝 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
VERSION="${{ inputs.version }}"
sed -i "s/^VERSION ?= .*/VERSION ?= $VERSION/" Makefile
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
VERSION="$INPUT_VERSION"
sed -i "s|^VERSION ?= .*|VERSION ?= $VERSION|" Makefile
🤖 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/actions/update-makefile-version/action.yaml around lines 13 - 14,
Replace direct expansion of ${{ inputs.version }} with assigning it to an
intermediate environment variable (e.g., VERSION) before any shell execution to
avoid GitHub expression injection; then update the sed invocation that edits the
Makefile (the line that currently runs sed -i "s/^VERSION ?= .*/VERSION ?=
$VERSION/") to use a safer delimiter such as | and ensure the replacement side
treats the VERSION variable literally (i.e., use a quoted shell variable
replacement with proper escaping/quoting) so that slashes, ampersands, and
backslashes in VERSION cannot break or corrupt the sed substitution.

Comment thread .github/actions/validate-version/action.yaml Outdated
Comment on lines +38 to +45
- name: Commit and push changes
shell: bash
run: |
git config --global user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
git config --global user.name "${{ github.actor}}"

git commit . -s -m "Prepare release ${{ github.event.inputs.version }}"
git push --set-upstream origin "${{ steps.prepare-branch.outputs.branch-name }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

git commit . will fail the job when there is nothing to commit.

If prepare-release-branch produces no diff (e.g. the branch already existed at the requested version, or Makefile values already match), git commit . -s -m "..." exits non-zero and the job fails. Guard with a check, or fall back to --allow-empty, so re-running the workflow is idempotent.

🛡️ Proposed fix
       - name: Commit and push changes
         shell: bash
         run: |
           git config --global user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
           git config --global user.name "${{ github.actor}}"

-          git commit . -s -m "Prepare release ${{ github.event.inputs.version }}"
-          git push --set-upstream origin "${{ steps.prepare-branch.outputs.branch-name }}"
+          if git diff --quiet && git diff --cached --quiet; then
+            echo "No changes to commit; pushing branch as-is."
+          else
+            git commit . -s -m "Prepare release ${{ github.event.inputs.version }}"
+          fi
+          git push --set-upstream origin "${{ steps.prepare-branch.outputs.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/sector-release.yaml around lines 38 - 45, The job fails
when running the "Commit and push changes" step because git commit . exits
non-zero if there are no staged changes; update that step (the run block that
calls git commit . -s -m "Prepare release ${{ github.event.inputs.version }}")
to first check for changes (e.g., by testing git status --porcelain or git diff
--quiet) and only run git commit when there are staged changes, or alternatively
use git commit --allow-empty to make the commit idempotent; adjust the step that
references steps.prepare-branch.outputs.branch-name accordingly so the push
still occurs in either case.

Boomatang added a commit that referenced this pull request May 6, 2026
This commit addresses critical security issues identified by coderabbitai
in PR #55 review comments.

Security Fixes:
- Fix script injection vulnerabilities in 8 composite actions by moving
  template expressions (${{ inputs.* }}) from bash script bodies to
  environment variables
- Add missing release-branch input declaration in create-release action
- Improve Makefile parsing robustness with validation and error handling

Changes:
1. Script Injection Prevention (Critical/Major):
   - check-tag-exists: Secure inputs.tag and github.sha
   - create-and-push-tag: Secure inputs.tag
   - create-release-branch: Secure inputs.version and inputs.push
   - detect-prerelease: Secure inputs.version
   - update-makefile-expiry: Secure inputs.expiry
   - update-makefile-version: Secure inputs.version
   - validate-version: Secure inputs.version
   - All bash variables properly quoted to prevent word-splitting

2. Missing Input Declaration (Critical):
   - create-release: Add release-branch input
   - release.yaml: Pass github.ref_name as release-branch
   - sector-release.yaml: Pass RELEASE_BRANCH output as release-branch

3. Fragile Parsing Fix (Minor):
   - get-version-from-makefile: Use grep -m1 to capture first match only
   - Add validation to ensure VERSION is non-empty
   - Add error handling with proper exit codes

All changes prevent potential command injection attacks where untrusted
input could be executed as shell commands through GitHub Actions template
expansion.

Reported-by: coderabbitai on PR #55

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Boomatang and others added 2 commits May 6, 2026 16:27
Create a workflow to be used with the sector release tool.
Main change is breaking the workflows up into reusable actions.

Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
This commit addresses critical security issues identified by coderabbitai
in PR #55 review comments.

Security Fixes:
- Fix script injection vulnerabilities in 8 composite actions by moving
  template expressions (${{ inputs.* }}) from bash script bodies to
  environment variables
- Add missing release-branch input declaration in create-release action
- Improve Makefile parsing robustness with validation and error handling

Changes:
1. Script Injection Prevention (Critical/Major):
   - check-tag-exists: Secure inputs.tag and github.sha
   - create-and-push-tag: Secure inputs.tag
   - create-release-branch: Secure inputs.version and inputs.push
   - detect-prerelease: Secure inputs.version
   - update-makefile-expiry: Secure inputs.expiry
   - update-makefile-version: Secure inputs.version
   - validate-version: Secure inputs.version
   - All bash variables properly quoted to prevent word-splitting

2. Missing Input Declaration (Critical):
   - create-release: Add release-branch input
   - release.yaml: Pass github.ref_name as release-branch
   - sector-release.yaml: Pass RELEASE_BRANCH output as release-branch

3. Fragile Parsing Fix (Minor):
   - get-version-from-makefile: Use grep -m1 to capture first match only
   - Add validation to ensure VERSION is non-empty
   - Add error handling with proper exit codes

All changes prevent potential command injection attacks where untrusted
input could be executed as shell commands through GitHub Actions template
expansion.

Reported-by: coderabbitai on PR #55

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready For Review

Development

Successfully merging this pull request may close these issues.

1 participant