phase 3: helm test, CI matrix, and OCI release workflow#3
Merged
Conversation
- templates/tests/test-connection.yaml: helm.sh/hook test pod that
curls the Service via wget and matches HTTP/.. 200. Uses distinct
labels (component=test) so it does NOT match the chart's
NetworkPolicy podSelector — without this the policy blocks the
test pod's egress to the Service.
- ci/{minimal,full,externalsecrets}-values.yaml: matrix files that
exercise default install, full optional-resource install, and
ESO-rendered (lint-only) install.
- .github/workflows/lint.yml: helm lint + helm template | kubeconform
+ kube-linter against every ci/*-values.yaml. Pinned tool versions.
- .github/workflows/smoke.yml: kind 1.28.13 matrix. Install path runs
helm install --wait, kubectl wait, in-cluster curl probe, and
helm test. Lint-only path runs helm lint + kubeconform with ESO
CRDs skipped. Diagnostics step on failure.
- .github/workflows/release.yml: triggers on tags v*. Verifies tag
matches Chart.yaml version, then helm package + helm push to
oci://ghcr.io/<owner>/charts. Owner lower-cased for OCI compliance.
- pdb.yaml: set unhealthyPodEvictionPolicy=AlwaysAllow (kube-linter
gate; safe default for stateless services).
- values.yaml: default soft pod-anti-affinity by hostname (replicas
spread across nodes when possible) — also satisfies kube-linter's
no-anti-affinity gate.
- test-connection pod: cpu/memory requests+limits (kube-linter gate).
Verified end-to-end on a local kind 1.28 cluster:
- helm install minimal-values, full-values: clean
- in-cluster curl returns "hello from helm-chart-template"
- helm test (default + full-values): Succeeded in 6s
- kube-linter clean across all 3 matrix files
- kubeconform clean across all 3 matrix files (ESO Skip on the
externalsecrets file as expected)
Major:
- values.yaml + _helpers.tpl + deployment.yaml: default
pod-anti-affinity now uses the chart's selectorLabels (via a new
http-echo.defaultAffinity helper) instead of a hardcoded
app.kubernetes.io/name. nameOverride now works correctly. values
default reverts to affinity: {} so an empty value triggers the
synthesized rule; a populated value replaces entirely.
- smoke.yml: dropped redundant in-cluster curl probe + redundant
kubectl wait. helm test already exercises connectivity from
inside the cluster and is the source of truth.
Minor:
- test-connection.yaml: wget gets -T 5 -t 2 so failures surface in
~15s instead of busybox's default ~2 min retry loop.
- pdb.yaml: wrap unhealthyPodEvictionPolicy in `with` so users who
set it to null don't render an empty value.
- smoke.yml: dropped the lint-only externalsecrets matrix entry
(lint.yml already covers it on every PR; removing the duplicate
saves CI minutes).
Nits:
- release.yml: dropped fetch-depth: 0 (helm package doesn't need
history); added set -euo pipefail to the GHCR login step for
consistency.
- ci/full-values.yaml + ci/externalsecrets-values.yaml: renamed the
CI test-fixture key from API_TOKEN to DEMO_VALUE so it doesn't
trip credential scanners; added a clarifying comment.
Verified locally:
- helm lint . clean across all 3 matrix files
- kubeconform clean across all 3
- kube-linter clean across all 3
- Default affinity renders synthesized rule with correct
selectorLabels
- nameOverride=foo: synthesized rule's selectorLabels follow (name: foo)
- User-supplied affinity replaces synthesized rule entirely
The previous hook-delete-policy was `before-hook-creation,hook-succeeded`, which deleted the test pod the moment it succeeded. `helm test --logs` then failed to read logs of a pod that no longer existed: Error: unable to get pod logs for http-echo-test-connection: pods "http-echo-test-connection" not found Drop `hook-succeeded` so the pod stays around after success. The next `helm test` invocation will still clean it up via `before-hook-creation`.
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.
Summary
templates/tests/test-connection.yaml—helm.sh/hook: testpod with non-overlapping labels (so the chart's NetworkPolicy doesn't block its egress to the Service).ci/{minimal,full,externalsecrets}-values.yaml— exercises default install, full optional-resource install, and ESO render (lint-only).lint.yml(helm lint + kubeconform + kube-linter),smoke.yml(kind 1.28 matrix, install + helm test + curl probe),release.yml(OCI publish to GHCR onv*tag).podDisruptionBudget.unhealthyPodEvictionPolicy: AlwaysAllowdefault; default soft pod-anti-affinity by hostname.Test plan
helm lint .clean against everyci/*-values.yaml.helm template . | kubeconform -strict -ignore-missing-schemas -skip ExternalSecret,SecretStore,ClusterSecretStore -kubernetes-version 1.28.0clean for every matrix file.helm template . | kube-linter lint -clean for every matrix file.helm testagainstminimal-values.yamlandfull-values.yaml.helm testsucceeds in ~6s.vX.Y.Ztag exercisesrelease.yml.