[DEVEX-1535] Add helm-chart-lint + helm-goldens-check composite actions#127
Conversation
Adds two central composite actions referenced by the per-repo Helm chart
convention runbook.
helm-chart-lint enforces (per guideline §3.1):
- Values file names match the convention regex (values.yaml,
values-{local,stg,qa,prod,dev-ec2,qa-ec2,prod-ec2}.yaml, Chart.yaml,
values.schema.json).
- helm template ./deployments (no -f, no --set) renders cleanly.
- templates/env-file.yaml is forbidden — must be templates/env-configmap.yaml.
- No top-level `topo:` key in any values file.
- Mandatory `.app` namespace in values.yaml.
- No non-reserved top-level namespaces (catches .aws, .ec2, etc.).
- No `if .Values.<unapproved-key>` render gates (per-resource gates only).
helm-goldens-check v1 (per guideline §3.2):
- Layer 1 EKS-Helm path via `helm unittest <chart>` when tests/ exists.
- Layer 1 SetupPkg + Helm-EC2 paths via chart-committed regenerate hook
(golden/regenerate.sh) + post-hook `git diff` enforcement.
- Layer 2 cross-path baseline via chart-committed regenerate hook
(golden/regenerate-cross-path-baseline.sh) + post-hook diff.
- Skip flags for charts that have not yet committed tests/ or baseline.
Includes good-chart and bad-chart fixtures plus a smoke-test workflow that
proves the linter passes on convention-compliant charts and fails (with
expected violations) on unmigrated ones.
Refs: DEVEX-1535
Co-authored-by: Cursor <cursoragent@cursor.com>
PR SummaryLow Risk Overview
A new Reviewed by Cursor Bugbot for commit c4efbbe. Bugbot is set up for automated code reviews on this repo. Configure here. |
… RESERVED_KEYS Two BugBot findings on PR #127: 1. The `reserved-chart-control-keys` input is documented as "in addition to `app`", but the script treated the input as the complete allowed-key set. A caller overriding the input without restating `app` would get a self-contradicting failure (Rule 5 requires `app:`, Rule 6 then flags it as non-reserved). Prepend `app` unconditionally to RESERVED_KEYS — the prepend is idempotent vs. the default and matches the documented contract. 2. `grep -v '^$'` in two pipelines returns exit 1 when all input lines are empty. Combined with `set -euo pipefail`, that silently kills the script with no `::error::` annotation. Replace with `{ grep -v '^$' || true; }` so Rule 6 / Rule 7 fall through and fire loudly per key, which is the useful failure mode. Refs: DEVEX-1535 Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 558eeea. Configure here.
… real version Two BugBot findings on PR #127 commit 558eeea: 1. (Medium) Rule 7's regex only matched `{{ if .Values.X }}` and `{{ with .Values.X }}` — `{{- else if .Values.X }}` is a standard Go-template/Helm pattern that silently bypassed the check. Same gap in the inner extraction regex. Extend both regexes to also match an optional `else ` prefix so `else if` and `else with` are caught. 2. (High) `helm-unittest-version` default was `0.6.2` — that tag never existed (the 0.6.x series only released v0.6.0), and the value was missing the `v` prefix helm-unittest's git tags use. The bug was masked in CI because every existing goldens-check job used `skip-layer1: true`. Pin to `v1.0.3` (mature stable line, released 2025-10-05). Regression guards: * bad-chart fixture's env-file.yaml now contains an `else if .Values.aws` branch. The lint-bad-fixture CI job asserts the `.Values.aws` annotation appears in lint output — if the Rule 7 regex narrows again, CI fails. * good-chart fixture ships a minimal `tests/deployment_test.yaml`. A new goldens-installs-helm-unittest job runs the action with `skip-layer1: false`, exercising the full plugin install + run path. If the default version ever points at a non-existent tag again, `helm plugin install --version <X>` fails fast in CI. Refs: DEVEX-1535 Co-authored-by: Cursor <cursoragent@cursor.com>

Summary
Adds the two central composite actions the per-repo Helm chart convention runbook depends on. Each chart adopting the convention wires them into its PR-triggered CI workflow as the chart-lint + goldens-check merge gates.
This is prerequisite #2 of DEVEX-1535 (covers both prereqs 2a and 2b from the Story).
helm-chart-lint (§3.1)
.github/actions/helm-chart-lint/— POSIX shell +yq. Enforces all seven rules from the guideline:^(values\.yaml|values-(local|stg|qa|prod|dev-ec2|qa-ec2|prod-ec2)\.yaml|Chart\.yaml|values\.schema\.json)$helm template <chart>(no-f, no--set) renders cleanlytemplates/env-file.yamlforbidden — must betemplates/env-configmap.yamltopo:key in any values file.appnamespace invalues.yamlaws:,ec2:, etc. fail)if .Values.<unapproved-key>render gates in templatesThe reserved chart-control key list is configurable via the
reserved-chart-control-keysinput so charts with legitimately distinct chart-control keys can extend it locally.helm-goldens-check v1 (§3.2)
.github/actions/helm-goldens-check/— installs Helm + thehelm-unittestplugin and runs:helm unittest <chart-path>when<chart-path>/tests/exists. Snapshot diffing is handled by the plugin.<goldens-path>/regenerate.shhook; the action re-runsgit diffover<goldens-path>after the hook executes and fails on any change. Path-specific render logic stays with the chart (per guideline: "Layer 2 stays custom — no community tool spans those paths").<goldens-path>/regenerate-cross-path-baseline.sh. Action fails on any diff.skip-layer1andskip-cross-pathinputs let charts opt out during the migration window before they've committedtests/or a baseline.Why the goldens-check is a thin wrapper
The runbook generates per-chart goldens during Step 2 (
<slug><env>-<path>.env) and Step 8 (cross-path-baseline.txt) and commits them. The action's job is to enforce "diff against committed = empty", not to know how each chart renders its three paths (Pattern S vs R vs D, daemon-set flags, multi-Deployment slugs). Delegating to per-chart regenerate hooks keeps the central action stable while each chart owns its matrix.A v2 that drives an explicit
matrix.yamland renders all three paths centrally is a follow-up once a few charts have migrated and the shape stabilizes.Test plan
A new
Test helm-chart actionsworkflow exercises both actions on PR / push tomain:lint-good-fixture: lint passes against a convention-compliant fixture chartlint-bad-fixture: lint exits non-zero against an intentionally-unmigrated fixture chart (catches Rules 1, 3, 4, 5, 6, and 7 — verified locally)goldens-good-fixture: goldens-check passes against the good fixture with skip flags engagedshellcheckcleanactionlintLocally verified the linter against the radmin chart (unmigrated): catches every expected violation across all seven rules. Output shape uses
::error::annotations for GitHub UI surfacing.JIRA
DEVEX-1535
Made with Cursor