-
Notifications
You must be signed in to change notification settings - Fork 1
Implement RFC 0020: PR-based chart sync workflows #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| name: PR Chart Delete | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| chart: | ||
| description: 'Chart name' | ||
| required: true | ||
| type: string | ||
| version: | ||
| description: 'Chart version' | ||
| required: true | ||
| type: string | ||
| component_repo: | ||
| description: 'Source component repository (for PR title/body)' | ||
| required: false | ||
| type: string | ||
| default: 'kuadrant' | ||
|
|
||
| jobs: | ||
| create-chart-delete-pr: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| env: | ||
| CHART_NAME: ${{ github.event.inputs.chart }} | ||
| CHART_VERSION: ${{ github.event.inputs.version }} | ||
| COMPONENT_REPO: ${{ github.event.inputs.component_repo }} | ||
| BRANCH_NAME: "delete/${{ github.event.inputs.chart }}-${{ github.event.inputs.version }}" | ||
|
|
||
| steps: | ||
| - name: Set up Go 1.26.x | ||
| uses: actions/setup-go@7b8cf10d4e4a01d4992d18a89f4d7dc5a3e6d6f4 # v4 | ||
| with: | ||
| go-version: 1.26.x | ||
|
|
||
| - name: Checkout | ||
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Create branch for PR | ||
| run: | | ||
| git checkout -b "${{ env.BRANCH_NAME }}" | ||
|
|
||
| - name: Check if chart exists | ||
| id: chart-check | ||
| run: | | ||
| chart_file="charts/${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz" | ||
| prov_file="charts/${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz.prov" | ||
|
|
||
| if [[ -f "$chart_file" ]]; then | ||
| echo "chart_file=$chart_file" >> $GITHUB_OUTPUT | ||
| echo "prov_file=$prov_file" >> $GITHUB_OUTPUT | ||
| echo "Found chart: $chart_file" | ||
| if [[ -f "$prov_file" ]]; then | ||
| echo "Found provenance: $prov_file" | ||
| else | ||
| echo "Provenance file not found: $prov_file" | ||
| fi | ||
| else | ||
| echo "::error::Chart ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }} not found in repository" | ||
| echo "::error::Expected file: $chart_file" | ||
| echo "This might be due to a typo in chart name or version" | ||
| exit 1 | ||
| fi | ||
|
Comment on lines
+47
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Do not skip deletion when only provenance or index artefacts remain. The workflow reports “not found” whenever the archive is absent, even if its 🧰 Tools🪛 zizmor (1.26.1)[warning] 50-50: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [warning] 50-50: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [warning] 51-51: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) [warning] 51-51: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Delete chart package | ||
| run: | | ||
| echo "Deleting chart package and provenance file..." | ||
| make delete-chart \ | ||
| CHART_NAME="${{ env.CHART_NAME }}" \ | ||
| CHART_VERSION="${{ env.CHART_VERSION }}" | ||
|
|
||
| - name: Update local index | ||
| run: | | ||
| echo "Updating Helm repository index..." | ||
| make helm-index | ||
|
|
||
| - name: Check if changes exist | ||
| id: changes | ||
| run: | | ||
| if git diff --quiet; then | ||
| echo "::error::No changes detected after attempting to delete ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" | ||
| echo "::error::This indicates the deletion failed or chart was already removed" | ||
| echo "Check if the chart files exist and deletion command worked correctly" | ||
| exit 1 | ||
| else | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "Changes detected - proceeding with PR creation" | ||
| git status --porcelain | ||
|
Boomatang marked this conversation as resolved.
|
||
| fi | ||
|
|
||
| - name: Commit changes | ||
| if: steps.changes.outputs.has_changes == 'true' | ||
| run: | | ||
| git config --global user.name "kuadrant-bot" | ||
| git config --global user.email "kuadrant-bot@users.noreply.github.com" | ||
| git add charts/ | ||
| git commit -m "Remove ${{ env.CHART_NAME }} version ${{ env.CHART_VERSION }} | ||
|
|
||
| - Chart: ${{ env.CHART_NAME }} | ||
| - Version: ${{ env.CHART_VERSION }} | ||
| - Source: ${{ env.COMPONENT_REPO }} | ||
| - Removed files: | ||
| - ${{ steps.chart-check.outputs.chart_file }} | ||
| - ${{ steps.chart-check.outputs.prov_file }}" | ||
|
|
||
| - name: Push branch | ||
| if: steps.changes.outputs.has_changes == 'true' | ||
| run: | | ||
| git push origin "${{ env.BRANCH_NAME }}" | ||
|
|
||
| - name: Create Pull Request | ||
| if: steps.changes.outputs.has_changes == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| gh pr create \ | ||
| --title "Remove chart: ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" \ | ||
| --body "$(cat <<EOF | ||
| ## Chart Deletion | ||
|
|
||
| This PR removes a chart package from the repository. | ||
|
|
||
| - **Chart**: ${{ env.CHART_NAME }} | ||
| - **Version**: ${{ env.CHART_VERSION }} | ||
| - **Source Repository**: ${{ env.COMPONENT_REPO }} | ||
|
|
||
| ### Changes | ||
| - Removed chart package: \`${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz\` | ||
| - Removed provenance file: \`${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz.prov\` | ||
| - Updated Helm repository index | ||
|
|
||
| ### Validation | ||
| This PR will be validated by CI to ensure: | ||
| - Helm index consistency after deletion | ||
| - No broken references remain | ||
| - Deletion is clean and complete | ||
|
|
||
| ### Warning | ||
| This action will permanently remove the chart from the public repository. | ||
| Ensure this deletion is intentional and authorized. | ||
|
|
||
| --- | ||
| *This PR was created automatically by the chart deletion workflow.* | ||
| EOF | ||
| )" \ | ||
| --head "${{ env.BRANCH_NAME }}" \ | ||
| --base main | ||
|
|
||
| - name: Enable auto-merge | ||
| if: steps.changes.outputs.has_changes == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[0].number') | ||
| gh pr merge $PR_NUMBER --auto --squash | ||
|
|
||
|
|
||
| - name: Output auto-merge details | ||
| if: steps.changes.outputs.has_changes == 'true' | ||
| run: | | ||
| echo "Created deletion PR for ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" | ||
| echo "Branch: ${{ env.BRANCH_NAME }}" | ||
| echo "Auto-merge enabled - PR will merge automatically after CI validation passes" | ||
|
|
||
| - name: No changes detected | ||
| if: steps.changes.outputs.has_changes == 'false' | ||
| run: | | ||
| echo "::error::No changes detected after attempting to delete ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" | ||
| echo "::error::This indicates the deletion failed or chart was already removed" | ||
| echo "Check if the chart files exist and deletion command worked correctly" | ||
| exit 1 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| name: PR Chart Sync | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
gh label list --repo "$(gh repo view --json nameWithOwner -q .nameWithOwner)" | grep -iE 'chart-sync|chart-delete|automated'Repository: Kuadrant/helm-charts Length of output: 158 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '--- workflow label usage ---\n'
grep -nE 'chart-sync|chart-delete|automated|gh pr create|--label' .github/workflows/pr-chart-sync.yaml .github/workflows/pr-chart-delete.yaml || true
printf '\n--- label definitions in repo files ---\n'
rg -n --hidden --glob '!.git' --glob '!node_modules' --glob '!dist' --glob '!build' '^(chart-sync|chart-delete|automated)$|name:\s*(chart-sync|chart-delete|automated)\b|labels:' .Repository: Kuadrant/helm-charts Length of output: 249 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- relevant workflow lines ---'
sed -n '90,145p' .github/workflows/pr-chart-sync.yaml
printf '\n'
sed -n '108,165p' .github/workflows/pr-chart-delete.yaml
echo '\n--- repo label definitions ---'
fd -a -t f -I 'labels.*' .
rg -n --hidden --glob '!.git' --glob '!node_modules' --glob '!dist' --glob '!build' 'chart-sync|chart-delete|automated' .Repository: Kuadrant/helm-charts Length of output: 5154 Add the missing PR labels
🤖 Prompt for AI Agents |
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| browser_download_url: | ||
| description: 'Browser download URL for the chart package' | ||
| required: true | ||
| type: string | ||
| chart: | ||
| description: 'Chart name' | ||
| required: true | ||
| type: string | ||
| version: | ||
| description: 'Chart version' | ||
| required: true | ||
| type: string | ||
| component_repo: | ||
| description: 'Source component repository (for PR title/body)' | ||
| required: false | ||
| type: string | ||
| default: 'kuadrant' | ||
|
|
||
| jobs: | ||
| create-chart-pr: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| env: | ||
| BROWSER_DOWNLOAD_URL: ${{ github.event.inputs.browser_download_url }} | ||
| CHART_NAME: ${{ github.event.inputs.chart }} | ||
| CHART_VERSION: ${{ github.event.inputs.version }} | ||
| COMPONENT_REPO: ${{ github.event.inputs.component_repo }} | ||
| BRANCH_NAME: "sync/${{ github.event.inputs.chart }}-${{ github.event.inputs.version }}" | ||
|
Comment on lines
+29
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Centralise validation of dispatch-controlled chart identifiers. Both privileged workflows derive shell commands, paths and branch names from unchecked dispatch inputs.
📍 Affects 2 files
🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| steps: | ||
| - name: Set up Go 1.26.x | ||
| uses: actions/setup-go@7b8cf10d4e4a01d4992d18a89f4d7dc5a3e6d6f4 # v4 | ||
| with: | ||
| go-version: 1.26.x | ||
| id: go | ||
|
|
||
| - name: Checkout | ||
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Create branch for PR | ||
| run: | | ||
| git checkout -b "${{ env.BRANCH_NAME }}" | ||
|
|
||
|
Comment on lines
+50
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Prevent script injection by using native shell variables. Using GitHub Actions expressions (
🧰 Tools🪛 zizmor (1.26.1)[warning] 51-51: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 📍 Affects 1 file
Source: Linters/SAST tools |
||
| - name: Get chart package | ||
| working-directory: ${{ github.workspace }} | ||
| run: | | ||
| make get-chart \ | ||
| BROWSER_DOWNLOAD_URL="${{ env.BROWSER_DOWNLOAD_URL }}" \ | ||
| CHART_NAME="${{ env.CHART_NAME }}" \ | ||
| CHART_VERSION="${{ env.CHART_VERSION }}" | ||
|
|
||
| - name: Check if changes exist | ||
| run: | | ||
| # Add files to staging to see changes | ||
| git add charts/ | ||
| if git diff --staged --quiet; then | ||
| echo "::error::No changes detected for ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" | ||
| echo "::error::Chart may already exist in the repository" | ||
| echo "Workflow expected to make changes but none were detected" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Update local index | ||
| run: | | ||
| make helm-index | ||
|
|
||
| - name: Validate chart package | ||
| run: | | ||
| make validate-chart \ | ||
| CHART_NAME="${{ env.CHART_NAME }}" \ | ||
| CHART_VERSION="${{ env.CHART_VERSION }}" | ||
|
|
||
| - name: Commit changes | ||
| run: | | ||
| git config --global user.name "kuadrant-bot" | ||
| git config --global user.email "kuadrant-bot@users.noreply.github.com" | ||
| git add charts/ | ||
| git commit -m "Add ${{ env.CHART_NAME }} version ${{ env.CHART_VERSION }} | ||
|
|
||
| - Chart: ${{ env.CHART_NAME }} | ||
| - Version: ${{ env.CHART_VERSION }} | ||
| - Source: ${{ env.COMPONENT_REPO }} | ||
| - Download URL: ${{ env.BROWSER_DOWNLOAD_URL }}" | ||
|
|
||
| - name: Push branch | ||
| run: | | ||
| git push origin "${{ env.BRANCH_NAME }}" | ||
|
|
||
| - name: Create Pull Request | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| gh pr create \ | ||
| --title "Sync chart: ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" \ | ||
| --body "$(cat <<EOF | ||
| ## Chart Sync | ||
|
|
||
| This PR synchronizes a new chart package from the component release workflow. | ||
|
|
||
| - **Chart**: ${{ env.CHART_NAME }} | ||
| - **Version**: ${{ env.CHART_VERSION }} | ||
| - **Source Repository**: ${{ env.COMPONENT_REPO }} | ||
| - **Download URL**: ${{ env.BROWSER_DOWNLOAD_URL }} | ||
|
|
||
| ### Changes | ||
| - Added chart package: \`${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz\` | ||
| - Added provenance file: \`${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}.tgz.prov\` | ||
| - Updated Helm repository index | ||
|
|
||
| ### Validation | ||
| This PR will be validated by CI to ensure: | ||
| - Chart package is well-formed | ||
| - Helm index is consistent | ||
| - Chart name and version match expectations | ||
| - Provenance signature is valid | ||
|
|
||
| --- | ||
| *This PR was created automatically by the chart sync workflow.* | ||
| EOF | ||
| )" \ | ||
| --head "${{ env.BRANCH_NAME }}" \ | ||
| --base main | ||
|
|
||
| - name: Enable auto-merge | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| PR_NUMBER=$(gh pr list --head "${{ env.BRANCH_NAME }}" --json number --jq '.[0].number') | ||
| gh pr merge $PR_NUMBER --auto --squash | ||
|
|
||
|
|
||
| - name: Output auto-merge details | ||
| run: | | ||
| echo "Created PR for ${{ env.CHART_NAME }} v${{ env.CHART_VERSION }}" | ||
| echo "Branch: ${{ env.BRANCH_NAME }}" | ||
| echo "Auto-merge enabled - PR will merge automatically after CI validation passes" | ||
|
|
||
There was a problem hiding this comment.
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
Unvalidated dispatch inputs still interpolated via
${{ }}throughout the job — duplicate of prior finding.CHART_NAME/CHART_VERSION/COMPONENT_REPOcome straight fromworkflow_dispatchinputs with no format check, and every downstreamrun:step (lines 45, 50-51, 73-74, 101-108, 121-132, 150, 160, 166-167, 173, 180) re-expands them via${{ env.X }}rather than reading the already-exported shell variable. GitHub performs literal text substitution for${{ }}before the shell parses the script, so a value containing a quote/backtick can inject arbitrary commands that run with the privilegedKUADRANT_DEV_PAT. It also enables path traversal (e.g.CHART_NAME=../../secret) into thecharts/$CHART_NAME-$CHART_VERSION.tgzpath built at line 50.Add a validation step (regex-check
chart/versionfor a safe charset) before any shell use, and switch therun:steps to reference$CHART_NAME,$CHART_VERSION, etc. (they're already exported viaenv:) instead of${{ env.X }}.🤖 Prompt for AI Agents