Files
helm-charts/.github/workflows/validate-charts.yml
T

162 lines
6.9 KiB
YAML

name: Validate Helm Charts
on:
pull_request:
jobs:
detect-changed-charts:
name: Detect changed charts
runs-on: ubuntu-latest
outputs:
charts: ${{ steps.detect.outputs.charts }}
any-chart-changed: ${{ steps.detect.outputs.any-chart-changed }}
scan-charts: ${{ steps.detect.outputs.scan-charts }}
any-scan: ${{ steps.detect.outputs.any-scan }}
steps:
- name: "Checkout Repository"
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: "Detect changed charts"
id: detect
run: |
CHANGED_FILES=$(git diff --name-only "origin/${{ github.base_ref }}...HEAD")
CHARTS="[]"
CHANGED_DIRS=$(echo "$CHANGED_FILES" | cut -d/ -f1 | sort -u)
for DIR in $CHANGED_DIRS; do
if [ -f "$DIR/Chart.yaml" ]; then
CHARTS=$(echo "$CHARTS" | jq -c --arg dir "$DIR" '. + [$dir]')
fi
done
echo "charts=$CHARTS" >> "$GITHUB_OUTPUT"
if [ "$CHARTS" = "[]" ]; then
echo "any-chart-changed=false" >> "$GITHUB_OUTPUT"
echo "No chart directories changed - nothing to build."
else
echo "any-chart-changed=true" >> "$GITHUB_OUTPUT"
echo "Changed charts: $CHARTS"
fi
# The Trivy scan normally follows the changed charts. But a PR that
# changes the scanner itself touches no chart at all, and would leave
# the change untested. In that case scan a fixed sample instead, one
# chart per interesting case: a documented deviation (samba), a fully
# hardened one (cyberchef), and one with two workloads
# (matrix-synapse).
SCAN_CHARTS="$CHARTS"
if [ "$CHARTS" = "[]" ] && echo "$CHANGED_FILES" | grep -qE '^(ci/(run-trivy-config\.sh|trivy/)|\.github/workflows/validate-charts\.yml)'; then
SCAN_CHARTS='["samba","cyberchef","matrix-synapse"]'
echo "Scanner changed without a chart change - scanning the sample: $SCAN_CHARTS"
fi
echo "scan-charts=$SCAN_CHARTS" >> "$GITHUB_OUTPUT"
if [ "$SCAN_CHARTS" = "[]" ]; then
echo "any-scan=false" >> "$GITHUB_OUTPUT"
else
echo "any-scan=true" >> "$GITHUB_OUTPUT"
fi
build-chart:
name: "Build ${{ matrix.chart }}"
needs: detect-changed-charts
if: needs.detect-changed-charts.outputs.any-chart-changed == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
chart: ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }}
steps:
- name: "Checkout Repository"
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: "Install Helm"
uses: azure/setup-helm@v4
- name: "Lint Helm Chart"
run: helm lint --strict "${{ matrix.chart }}"
- name: "Package Helm Chart"
run: helm package "${{ matrix.chart }}"
- name: "Check Chart Version was bumped"
# template-chart is a scaffold and never published, its version is meaningless
if: matrix.chart != 'template-chart'
run: |
BASE_VERSION=$(git show "origin/${{ github.base_ref }}:${{ matrix.chart }}/Chart.yaml" 2>/dev/null | grep '^version:' | awk '{print $2}' || true)
NEW_VERSION=$(grep '^version:' "${{ matrix.chart }}/Chart.yaml" | awk '{print $2}')
if [ -z "$BASE_VERSION" ]; then
echo "New chart (does not exist on ${{ github.base_ref }}), version: $NEW_VERSION"
elif [ "$BASE_VERSION" = "$NEW_VERSION" ]; then
echo "::error file=${{ matrix.chart }}/Chart.yaml::Chart '${{ matrix.chart }}' was modified but its version was not bumped (still $BASE_VERSION). Bump 'version:' in Chart.yaml, otherwise the publish on main will collide with the already published version."
exit 1
else
echo "Version bump OK: $BASE_VERSION -> $NEW_VERSION"
fi
trivy-config:
name: "Trivy config ${{ matrix.chart }}"
needs: detect-changed-charts
if: needs.detect-changed-charts.outputs.any-scan == 'true'
runs-on: ubuntu-latest
# Reporting only (issue #84): the scan renders each changed chart and lists
# what `trivy config` finds, but it never fails the job - see
# TRIVY_CONFIG_MODE below. Deliberately not a gate yet: the repo has several
# documented deviations, and a check that goes red on those every time is one
# people learn to scroll past. Depends only on detect-changed-charts, so it
# runs beside build-chart and adds no wall-clock time to the pipeline.
strategy:
fail-fast: false
matrix:
chart: ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }}
env:
TRIVY_VERSION: v0.74.0
# "report" always exits 0. Switch to "gate" to make a finding that no
# documented exception covers fail the job - the intended step once the
# seccomp gap (#84) is closed.
TRIVY_CONFIG_MODE: report
steps:
- name: "Checkout Repository"
uses: actions/checkout@v7
- name: "Install Helm"
uses: azure/setup-helm@v4
- name: "Install Trivy"
uses: aquasecurity/setup-trivy@v0.3.1
with:
version: ${{ env.TRIVY_VERSION }}
cache: true
# Findings land in the job summary, not only in the log: exceptions with
# their reasons come from ci/trivy/trivyignore.yaml, the trusted-registry
# list from ci/trivy/data/ksv0125.yaml.
- name: "Scan rendered manifests"
run: ci/run-trivy-config.sh "${{ matrix.chart }}"
install-test:
name: "Install-test ${{ matrix.chart }}"
needs: [detect-changed-charts, build-chart]
if: needs.detect-changed-charts.outputs.any-chart-changed == 'true'
runs-on: ubuntu-latest
# Stabilization phase (issue #22): the job reports failures but does not
# block the PR. Promote to a required check (drop continue-on-error) once
# it has proven stable across several chart PRs.
continue-on-error: true
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
chart: ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }}
env:
K3D_VERSION: v5.9.0
K3S_IMAGE: docker.io/rancher/k3s:v1.35.5-k3s1
steps:
- name: "Checkout Repository"
uses: actions/checkout@v7
- name: "Install Helm"
uses: azure/setup-helm@v4
- name: "Install k3d"
run: curl -sSfL https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG="$K3D_VERSION" bash
- name: "Create k3d cluster"
run: k3d cluster create install-test --image "$K3S_IMAGE" --wait --timeout 180s
# Excluded charts (see ci/excluded-charts.txt) are skipped inside the
# script with their documented reason.
- name: "Install chart and wait for readiness"
run: ci/run-install-test.sh "${{ matrix.chart }}"
- name: "Delete k3d cluster"
if: always()
run: k3d cluster delete install-test || true