ci(charts): add template-only helm test pipeline - #297
Open
lemaitre-aneo wants to merge 4 commits into
Open
Conversation
lemaitre-aneo
force-pushed
the
fl/helm-tests
branch
2 times, most recently
from
August 3, 2026 09:05
638bb5b to
da7a16e
Compare
lemaitre-aneo
force-pushed
the
fl/helm-tests
branch
from
August 4, 2026 09:10
da7a16e to
8202cf3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The Helm charts have no working verification in CI. The linter workflow invokes
ctwith--chart-dirs charts/armonik, butctexpects parent directories, so it finds no chart there:list-changedreturns nothing, and both lint and install silently skip on every run. In practice no chart has ever been linted by this pipeline.The runners have no Kubernetes cluster available, so chart verification has to be template-only: no kind, no
ct install, no smoke deployment.Description
Adds a four-layer, template-only test pipeline. Every layer is a script that runs identically locally and in CI.
1. Vendoring / dependency freshness (
test/vendor.sh) adds the ten chart repositories and vendors each chart's dependencies from its committedChart.lock, then checks the lock files are unchanged. Vendored.tgzarchives are gitignored, so this also produces the artifact the other jobs consume.2. Chart lint, repaired. The
--chart-dirsbug is fixed by moving the configuration intoct.yaml, which now also wires uplintconf.yamlandchart-schema.yaml(both present in the repo but never referenced), disablescheck-version-increment(chart versions move in lockstep at 0.1.0), and carries the chart-repos list. The first real lint run surfaced pre-existing problems, fixed here: yamllint violations in four values files, andarmonik-dependencies/values.ymlbeing misnamed, which meant Helm never loaded it and helm-docs could not process the chart, leaving a README that was a stale copy of the ingress chart's.3. Unit tests (
test/unittest.sh, helm-unittest 1.1.2): suites undercharts/<chart>/tests/for activemq, control-plane, compute-plane, ingress and the umbrella, covering defaults, conditional paths, indexed auth/partition env generation, per-partition fan-out, TLS/mTLS, Gateway API, and the render-time guards. A separate never-deployed harness chart undertest/harness/pins thearmonik-commonlibrary contract (21 tests): merge-engine semantics (null-is-absent, empty-string-is-absent, tpl-render-on-merge, concatList, overwrite), the conf generators, projected-volume dedup and its shared-path guards, and the nil-safe index helper. A library chart cannot be unit-tested directly, hence the consumer harness.4. Render matrix + schema validation (
test/matrix.sh): 19 render cases across defaults and conditional paths, plus 5 cases asserting that the render-time guards fail with the expected message. Every successful render is schema-validated with kubeconform (strict, CRD catalog) and screened for unrendered{{leftovers.No reference outputs or snapshots are committed anywhere: assertions target specific keys, so the suite does not need re-recording on every unrelated change.
Fixture convention. Values files that render successfully live in
charts/<name>/ci/*-values.yaml, wherectpicks them up automatically and lints the chart once per fixture, so one file serves both layers. Fixtures that must not be linted (expected-failure inputs, kube-version variants) live intest/fixtures/<chart>/.Unrendered-template screening. A leftover
{{in rendered output usually means atplvalue that never got evaluated. Screening for it naively produces false positives, because upstream Grafana dashboards and Prometheus rules legitimately ship{{ }}that their own consumers evaluate later. Rather than exempting whole renders,test/check-unrendered.awkdecides per document: documents originating from third-party subcharts are skipped by provenance, ExternalSecret documents may carry the operator's own{{ .KEY }}target-template references, and the ArmoniK-owned dashboard ConfigMaps may carry Grafana's{{label}}legend syntax. Anything else fails the case, so ArmoniK-owned output stays strictly checked, umbrella included.Known-broken render paths keep their tests written but disabled, each skip naming the defect, so fixing the bug is a one-line enablement:
pdb.yamlcalls an undefined helper (armonik.compute.pdb.apiVersion; the library definesarmonik.pdb.apiVersion);control-plane.enabled=false: NOTES.txt dereferences the control-plane values unconditionally;global.environment.{name,description}but ships no defaults for them, so a bare render nil-pointers. Itsci/default-values.yamlsupplies the block until this is fixed.Tests for in-flight PRs, also written and skipped, with each skip naming the PR that unblocks it (14 tests): #294 (operator split) gets the operators guard, the ESO gate moving to
global.armonik.operators.externalSecrets, the partitions guard, KEDA gating via the operator flags, PodMonitor/ServiceMonitor gating on both planes, the cert-manager availability guards in ingress and activemq, and the relocated cert-manager wait job; #295 gets the two Grafanaroot_urlguards.test/matrix.shcarries the matching ready-to-swap case lines in comments, andcharts/armonik/ci/minimal-values.yamlalready declares the operator flags (inert until #294 lands). This keeps the merge-day work mechanical.Bugs found by the new checks and fixed here:
automountServiceAccountTokenkey in both plane init Job pod specs, rejected by strict schema validation (both occurrences settrue, so behaviour is unchanged);{{namespace}typo in a dashboardlegendFormat, which Grafana would have rendered as literal text.CI. A new workflow runs the three script layers: a vendoring job that publishes the archives, feeding parallel unit-test and render-matrix jobs; tool versions and action SHAs are pinned. The linter workflow is repaired: config-driven
ct, the kind andct installsteps removed since no cluster is available, andchart-testing-actionmoved to v2.8.0, whose bundled yamale is the first release that runs on Python 3.12+ (earlier versions crash inast.Numagainst the Python thatsetup-pythonresolves today).All test scripts are POSIX
sh, verified under dash..helmignoreentries keep the new test material out of packaged chart archives, and thecheck-yamlpre-commit hook now also excludes the harness chart's templates, which are Helm templates rather than YAML.charts/update-charts.shis deliberately untouched here; its flag interface is #296.Testing
The pipeline is the deliverable, so it was verified by construction and by deliberately breaking things.
Current state, locally and in CI:
ctlint clean over all 10 charts; 69 unit tests passing with 17 skipped (3 broken paths, 14 awaiting #294/#295); 24 matrix cases passing with 4 skipped; kubeconform clean.Each layer was checked to actually fail when it should. A wrong image tag turns the unit tests red; an invalid manifest field turns kubeconform red; a
Chart.yaml/lock mismatch turns vendoring red; a weakened guard message turns the matrix guard case red; an injected{{ .Values.oops }}turns the unrendered screening red. The screening rules were additionally exercised against synthetic documents covering each accept/reject decision: a leak in an owned document, a leak inside an ExternalSecret, Grafana syntax outside a dashboard, third-party content, and an owned chart nested under a dependency.That exercise also caught a bug in the screening itself: with
pipefailset,grep -qclosing the pipe early made the producer die on SIGPIPE and inverted the result on large renders, so a match read as no-match. Removingpipefail(the POSIX conversion) fixed it, and the umbrella typo above is what the now-working check found first.Impact
test/README.mddocuments the entrypoints and versions.armonik-dependencies/Chart.lockis refreshed to current upstream versions.Additional Information
Ordering with the in-flight PRs. #296 should merge first: until then the vendoring step runs the current
update-charts.sh, which re-resolves and rewritesChart.lockinstead of reproducing it, so the freshness check degrades into "update and diff" and will go red whenever an upstream chart publishes a new version inside the pinnedx.xrange. Once #296 provides the build mode, that step becomes a true freshness check. #294 and #295 then unblock the skipped tests; both touch files this branch also touches, so the merge is not conflict-free either way.Two observations from writing the fixtures, neither addressed here:
gateway.gatewayClassNamehas no chart default and renders a schema-invalid null Gateway when unset (the fixture supplies one, and a render-time failure would fit the fail-fast convention better), andmtls.trustedCommonNamesis currently consumed by no template.kubeconform runs with
-ignore-missing-schemas, so CRDs absent from the catalog pass silently; worth revisiting with a pinned schema directory if that proves too permissive.Checklist