Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Publish Helm Chart

on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish (e.g. common-v0.1.1)"
required: true

concurrency:
group: publish-${{ github.event.release.tag_name || inputs.tag }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
Comment on lines +19 to +23
steps:
- name: Resolve tag
id: tag
run: |
TAG="${{ github.event.release.tag_name || inputs.tag }}"

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

Code injection vulnerability via template expansion in shell script.

Direct expansion of ${{ github.event.release.tag_name || inputs.tag }} into a bash assignment allows code injection before the validation regex runs. An attacker with write access could craft a tag like $(malicious-command) to execute arbitrary code.

Use an environment variable to prevent template expansion within the shell script.

🔒 Proposed fix to use environment variable
       - name: Resolve tag
         id: tag
+        env:
+          TAG: ${{ github.event.release.tag_name || inputs.tag }}
         run: |
-          TAG="${{ github.event.release.tag_name || inputs.tag }}"
           if [[ ! "$TAG" =~ ^([a-z0-9-]+)-v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
             echo "::error::Tag '$TAG' does not match expected format <component>-v<version>"

As per static analysis hints, this was flagged as template-injection by zizmor.

🧰 Tools
🪛 zizmor (1.25.2)

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

(template-injection)


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

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml at line 28, The TAG assignment uses direct
template expansion (TAG="${{ github.event.release.tag_name || inputs.tag }}")
which allows shell template injection; fix by moving the template result into
the workflow environment and then referencing that env var inside the shell step
(e.g., define env: TAG: ${{ github.event.release.tag_name || inputs.tag }} for
the job/step and in the run use a safe expansion like TAG="$TAG" or printf '%s'
"$TAG" so no template content is re-interpreted by the shell), ensure the value
is quoted and validated against your regex after assigning from the env var.

if [[ ! "$TAG" =~ ^([a-z0-9-]+)-v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then
echo "::error::Tag '$TAG' does not match expected format <component>-v<version>"
exit 1
fi
COMPONENT="${BASH_REMATCH[1]}"
VERSION="${BASH_REMATCH[2]}"
echo "ref=$TAG" >> "$GITHUB_OUTPUT"
echo "component=$COMPONENT" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "chart_path=charts/$COMPONENT" >> "$GITHUB_OUTPUT"

- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ steps.tag.outputs.ref }}
Comment on lines +40 to +43

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add persist-credentials: false to prevent credential leakage.

The checkout action persists credentials by default, which could be accessed by subsequent steps or malicious code in the repository. Since this workflow doesn't need to push commits, credentials should not be persisted.

🔒 Proposed fix to disable credential persistence
       - name: Checkout
         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
         with:
           ref: ${{ steps.tag.outputs.ref }}
+          persist-credentials: false

As per static analysis hints, this was flagged as artipacked by zizmor.

📝 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: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ steps.tag.outputs.ref }}
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ steps.tag.outputs.ref }}
persist-credentials: false
🧰 Tools
🪛 zizmor (1.25.2)

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

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish.yml around lines 40 - 43, The Checkout step
currently uses actions/checkout without disabling credential persistence; update
the step that uses actions/checkout@de0fac2e... (the "Checkout" step) to add
with: persist-credentials: false (alongside any existing with keys like ref) so
credentials are not persisted to later steps.


- name: Set up Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
with:
version: v4.1.4

- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin

- name: Package and push
run: |
helm dependency update "${{ steps.tag.outputs.chart_path }}"
helm package "${{ steps.tag.outputs.chart_path }}" --destination .
helm push "${{ steps.tag.outputs.component }}-${{ steps.tag.outputs.version }}.tgz" \
oci://ghcr.io/docspec/charts

- name: Logout from GHCR
if: always()
run: helm registry logout ghcr.io
41 changes: 0 additions & 41 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,9 @@ jobs:
permissions:
contents: write
pull-requests: write
outputs:
releases_created: ${{ steps.rp.outputs.releases_created }}
paths_released: ${{ steps.rp.outputs.paths_released }}
steps:
- name: Run release-please
id: rp
uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

publish:
needs: release-please
if: needs.release-please.outputs.releases_created == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.event.workflow_run.head_sha }}

- name: Set up Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
with:
version: v4.1.4

- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin

- name: Package and push released charts
run: |
PATHS_RELEASED='${{ needs.release-please.outputs.paths_released }}'
for chart_path in $(echo "$PATHS_RELEASED" | jq -r '.[]'); do
chart_name="$(basename "$chart_path")"
echo "Publishing $chart_name from $chart_path"
helm dependency update "$chart_path"
helm package "$chart_path" --destination .
helm push ${chart_name}-*.tgz oci://ghcr.io/docspec/charts
done

- name: Logout from GHCR
if: always()
run: helm registry logout ghcr.io