fix(helm): normalize appVersion to strip leading v (#2050) (#2156)

* fix(helm): normalize appVersion to strip leading v (#2050)

Releases triggered on a tag like `v0.7.1-rc.1` end up writing
`appVersion: "v0.7.1-rc.1"` into Chart.yaml / the published
index.yaml, but the Docker image is pushed to GHCR without the leading
`v` (`ghcr.io/we-promise/sure:0.7.1-rc.1`). Flux CD / any consumer
that pulls the chart then fails with `ImagePullBackoff` against
`v0.7.1-rc.1` (a tag that doesn't exist).

`normalize_version` is already applied to `CHART_VERSION`; route the
two tag-derived `APP_VERSION` paths through the same helper so the
appVersion matches the published image tag.

Closes #2050

* chore(ci): bind helm-publish version inputs to step env (#2050)

@coderabbitai (zizmor) flagged that the version-resolve step expanded
${{ inputs.chart_version }} and ${{ inputs.app_version }} directly
into bash, which is a template-injection vector — a malicious caller
of this reusable workflow could inject shell via an input like
'; rm -rf … #'.

Bind both inputs to step env (CHART_VERSION_INPUT,
APP_VERSION_INPUT) and reference them as shell variables in the
conditionals. Behaviour is unchanged; the values just arrive through
the env table instead of the runner's template pass.

---------

Co-authored-by: jeffrey701 <jeffrey701@users.noreply.github.com>
This commit is contained in:
Jeff
2026-06-03 02:53:15 -07:00
committed by GitHub
parent 8ccc434b3d
commit 7017b6340e

View File

@@ -40,6 +40,12 @@ jobs:
- name: Resolve chart and app versions
id: version
shell: bash
# Bind workflow inputs to env so the values arrive as shell variables
# instead of being interpolated verbatim by the `${{ }}` runner pass.
# zizmor flags the direct expansion as a template-injection risk.
env:
CHART_VERSION_INPUT: ${{ inputs.chart_version }}
APP_VERSION_INPUT: ${{ inputs.app_version }}
run: |
set -euo pipefail
@@ -48,18 +54,24 @@ jobs:
echo "${raw#v}"
}
if [ -n "${{ inputs.chart_version }}" ]; then
CHART_VERSION="$(normalize_version "${{ inputs.chart_version }}")"
if [ -n "$CHART_VERSION_INPUT" ]; then
CHART_VERSION="$(normalize_version "$CHART_VERSION_INPUT")"
elif [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
CHART_VERSION="$(normalize_version "${GITHUB_REF_NAME}")"
else
CHART_VERSION="0.0.0-nightly.$(date -u +'%Y%m%d.%H%M%S')"
fi
if [ -n "${{ inputs.app_version }}" ]; then
APP_VERSION="${{ inputs.app_version }}"
# Normalize APP_VERSION the same way CHART_VERSION is — appVersion
# must match the OCI image tag in GHCR, which is published without a
# leading `v`. Without this, a release on tag `v0.7.1-rc.1` writes
# `appVersion: "v0.7.1-rc.1"` into Chart.yaml / index.yaml, and Helm
# then fails to pull `ghcr.io/we-promise/sure:v0.7.1-rc.1` (the real
# tag is `0.7.1-rc.1`). See #2050.
if [ -n "$APP_VERSION_INPUT" ]; then
APP_VERSION="$(normalize_version "$APP_VERSION_INPUT")"
elif [[ "${GITHUB_REF_TYPE}" == "tag" && "${GITHUB_REF_NAME}" == v* ]]; then
APP_VERSION="${GITHUB_REF_NAME}"
APP_VERSION="$(normalize_version "${GITHUB_REF_NAME}")"
else
APP_VERSION="${CHART_VERSION}"
fi