Changelog
2026-09-09
Standard
- Post-install NOTES now list the configuration a release wired up: a
Configurationsection appears whenvariables,secrets,sealedSecrets, or anymounted*Filesare set, naming the ConfigMap, Secret, and SealedSecret each produces.variablesprint their values, truncated at 60 characters; they are non-secret by definition, that is whatsecretsis for.- Secrets and sealed secrets mask every value to a fixed
********, so nothing about the value, not even its length, is printed. Mounted-file blocks list paths only, since their values are whole file bodies. - Each block renders only when its values key is set, so a release without config is unchanged.
Tests
make testsnow fails when any test fails: the per-test sub-makes were joined with;, so only the last test's exit code counted and CI stayed green while thecronjobstest had been failing since 2026-08-25. The loops now chain with&&.- Golden manifests are regenerated with helm 4.3.0, the version the cloud-toolbox CI image ships: helm's rendering whitespace changed after 4.2.0, which broke 16 of the 33 standard tests on newer local helm versions. Goldens byte-match one helm version by design; run helm 4.3.0 locally, and regenerate with
make tests-updatewhenever the CI image's helm changes.
2026-08-25
Standard
- Every CronJob-spec and Job-spec field is now configurable per cron job: CronJob-level
timeZone,startingDeadlineSeconds,suspend,successfulJobsHistoryLimit, andfailedJobsHistoryLimit, and job-levelparallelism,completions,completionMode,activeDeadlineSeconds,backoffLimitPerIndex,maxFailedIndexes,podFailurePolicy,successPolicy,ttlSecondsAfterFinished, andpodReplacementPolicypass through to the renderedCronJob. The motivation istimeZone: without it a schedule runs in the kube-controller-manager's zone (UTC in practice), so30 2 * * *did not mean 02:30 local time. Documented in Cron jobs.- Each field renders only when you set it and no defaults were added, so existing manifests are unchanged.
- The API rejects a Job that sets both
backoffLimitandbackoffLimitPerIndex, so settingbackoffLimitPerIndexdropsbackoffLimit(including its0default) instead of rendering both. - The chart keeps an explicit allowlist rather than passing the spec through wholesale;
selector,manualSelector, andmanagedBystay unexposed.
2026-08-21
Standard
- Labels and annotations work on every resource and pod template, with one rule everywhere: plain
labels:/annotations:target the object's own metadata,podLabels:/podAnnotations:the pod template, each global and per resource, merged global < per-resource < chart-generated. Documented in Labels and Annotations.- Fixes two documented-but-unimplemented keys (
deployments.<name>.annotations,services.<name>.annotations) and closes the Service annotation gap that previously forcedextraManifestsfor external-dns and LoadBalancer config. - User labels never reach selectors or roll pods.
- Fixes two documented-but-unimplemented keys (
podAnnotationsnow reaches CronJob and Job pods:values.yamland the docs always claimed "Used by: Deployment, CronJob and Job", but only Deployment pod templates rendered it, so Velero backup-hook annotations set per the docs silently missed cronjob and job pods. Per-workloadpodAnnotationsalso now merge per key with the global map instead of replacing it wholesale; anyone relying on the replace behaviour gets the global keys back and can null individual keys instead.- SealedSecret scope is now overridable:
sealedsecrets.bitnami.com/cluster-wide: "true"was hardcoded; it is now a default the globalannotationsoverride per key, so namespace-wide scope no longer requires editing the template.
Tests
- Golden manifests regenerated for the template filename rename: the rename to plural template filenames changed every
# Source:comment and the alphabetical render order, but the goldens were not regenerated, so every chart's tests failed. Content unchanged.
2026-08-13
Standard
- Helm's
test-connectionpod now picks a stable port: the template chose the service port with an unsortedvalues | first, so Go's map iteration order decided it and a service with more than one port rendered a different target on each run. It now sorts, matching the fix the ingress and service templates got on 2026-06-02; this template was missed then.- Nothing in
charts/*/values.yamldefines a multi-port service, which is why the golden tests never caught it: the TU/e Dataverse installation adds an AJP port in its installation values, andhelm testthere hit the AJP port roughly half the time and failed. Theservicestest now covers a multi-port service.
- Nothing in
2026-08-11
Standard
resourcesnow falls back to pod and chart level, resolving container < pod < chart, matchingimage,command,args, andsecurityContext. It previously read the container block only, soresourcesset on a deployment, job, or cronJob was silently dropped, including for a cronJob defined without an explicitcontainersblock, where every other field falls through to the default container.- Reverted:
configuredefaults for init containers and sidecars. An earlier entry today described the opt-in behaviour from 2026-05-31 as a bug and madeconfigureresolve as chart defaults < pod < container for every container type. That was wrong: init containers and sidecars are opt-in by design, and the change silently gave them thevariablesConfigMap, thesecretsSecret, mounted files and PVCs. Declare what a container needs on the container itself, listing every key you want since the block is taken verbatim. - Values examples no longer suggest
kubernetes.io/ingress.class: the commentedingressandingressesexamples invalues.yamlrecommended the deprecated annotation alongsideclassName, and consumers copied it verbatim, so Kubernetes warnsannotation "kubernetes.io/ingress.class" is deprecated, please use 'spec.ingressClassName' insteadon every apply. The examples now showclassNameonly, which the template has always rendered asspec.ingressClassName. No rendered output changes; drop the annotation from your own values to clear the warning, and make sure a matchingIngressClassobject exists in the cluster (the annotation did not need one).
CI
- Pipeline includes follow
gitlab-pipelinesmainagain: the threeinclude:entries pinnedref: helm-diff, a branch that was merged upstream and deleted. GitLab could no longer resolve the includes, so every pipeline (onmainand on merge requests alike) was created and failed instantly with zero jobs and an emptyyaml_errorsfield, which made it look like an infrastructure fault rather than a config error. Now pinned tomain, matching every other Hosst project. tests:chartsbuilds subchart dependencies too: the job built dependencies for the chart under test only. A subchart packaged without its ownstandarddependency renders nothing inside its parent, soakeneo,peertubeandsupersetwere tested against output missing all of elasticsearch and valkey, silently and without error. The job now builds every chart first, and their goldens now carry the subchart resources the charts actually ship.- Golden tests pin the namespace:
make testandmake test-updatenow pass--namespace $(TEST_NAMESPACE)(defaultdefault). Without ithelm templatetook the namespace from the caller's kube-context, so any chart renderingmetadata.namespaceproduced a different golden locally than in CI, where the runner setshelm-charts. Thebookstackjob failed on exactly that while passing on every developer machine. tests:chartsbuilds chart dependencies: the job ranmake tests CHART=$CHARTwithouthelm dependency build, so all twelve wrapper charts failed onfound in Chart.yaml, but missing in charts/ directory: standard.make testsdoes not build dependencies andtests:standardnever noticed, since thestandardchart has none.
2026-06-18
Standard
- Config checksums hash data only: the
checksum/variables,checksum/secrets,checksum/sealedSecrets, andchecksum/filespod annotations now hash the relevant values maps directly (toYaml | sha256sum) instead of the whole rendered template file. Because the rendered files includestandard.labels(which carrieshelm.sh/chartandapp.kubernetes.io/version), the previous approach rolled pods on every chart/app version bump even when no config changed. Hashing only keys/values rolls pods on real data changes and is order-independent (toYamlsorts map keys). - The Deployment pod template uses selector labels only: it now carries
standard.selectorLabels(name/instance/deployment) instead of the fullstandard.labels. Sincepod-template-hashis derived from the pod template, keeping the mutablehelm.sh/chartandapp.kubernetes.io/versionlabels out of it stops version/chart bumps from rolling pods, completing the data-only-checksum change above. The selector is unchanged (it already usedselectorLabels), and resource metadata still carries the full labels. deployment.rolloutOnVersionChange(opt-in): set per deployment to put the fullstandard.labelsback on the pod template, so a chart or app version bump rolls the pods (and the chart/version labels are readable on each pod). Defaults tofalse, preserving the selector-labels-only behavior above.- Golden manifests excluded from whitespace hooks: the
end-of-file-fixer,mixed-line-ending, andtrailing-whitespacepre-commit hooks now skipcharts/*/tests/**/manifests.yaml, which must byte-matchhelm templateoutput (the emptydefaultsrender is a single newline the hooks were stripping to an empty file).
2026-06-05
CI
- One
tests/<chart>job per chart added to the pipeline, using thecloud-toolbox:helmimage; each runshelm dependency buildfollowed bymake tests. Onmainall chart tests always run; on branches only charts with changed files are tested (wrapper chart jobs also trigger oncharts/standard/**/*changes). Jobs are grouped undertests/in the pipeline UI and start immediately without waiting for prior stages (needs: []).
2026-06-04
Standard
All generated PersistentVolumeClaims now carry
helm.sh/resource-policy: keep, preventing silent data loss onhelm uninstallor resource rename. Setkeep: falseon any PVC entry to opt out and allow Helm to delete it on uninstall. Anannotationsfield is also supported to merge additional annotations onto the PVC.Improved deployment NOTES: post-install/upgrade output now shows a
Hostnames:list with scheme and TLS detection, conditionalJobs:andCronjobs:sections, and ready-to-run namespaced commands for logs, pod status, shell access, rollback, and retrieving deployed values.
2026-06-02
Standard
Ingress TLS smart defaults:
tls:now accepts four forms.tls:(null) ortls: trueauto-derives hosts fromingress.hostsand setssecretNameto<fullname>-tls; the key alone is enough to get cert-manager to pick up the ingress. List mode and dict mode each merge entries with the same defaults, so omittedhostsandsecretNamefields are filled in automatically.tls: false,tls: [], andtls: {}explicitly suppress the TLS block (clear convention).Ingress service lookup nil guard: rendering an ingress with no services defined no longer panics with "invalid value; expected string".
app.kubernetes.io/namenow reflects the application, not the chart: when using thestandardchart directly withoutnameOverride, thenamelabel uses the Helm release name instead of the meaningless valuestandard. SetnameOverride: backend(or your app name) invalues.yamlto get a stable application identity across all environments.nameOverrideenables per-branch uniqueness in shared namespaces: it affects both theapp.kubernetes.io/namelabel and the resource name suffix. WithnameOverride: backendand releasefeat-xyz, resources are namedfeat-xyz-backend: unique per branch, stable app identity. In production where release equals the app name, deduplication produces justbackend.The Ingress service fallback is now deterministic: when no service matches the ingress name, the fallback always selects the alphabetically first service rather than relying on Go map iteration order.
2026-06-01
Standard
volumes:now supports the same dict/list duality asenv,envFrom, andvolumeMounts: dict keys are injected as thenamefield; list mode passes through unchanged. Previously, a dict value produced invalid Kubernetes YAML (a map instead of a sequence). Default changed from{}to[].test-connectionrespectsenabled: false: the Helm test pod was generated for every service regardless ofenabled: false. It now skips disabled services.New
extraManifestskey: render arbitrary Kubernetes resources alongside the chart's own output. Dict mode (recommended) automatically injectsmetadata.name,metadata.namespace, and standard labels, using the same naming rules as other resources, with user-provided metadata winning over auto-injected values. List mode passes resources through raw withtplrendering for full control. Useful for NetworkPolicies, ExternalSecrets, ClusterRoles, BackendConfigs, or anything the chart does not natively support.
2026-05-31
Standard
initContainersandsidecarContainersno longer auto-mount configuration: both container types use an emptyconfigure: {}by default, so variables, secrets, files, and PVCs are not mounted unless explicitly enabled on the container. Regular containers continue to inherit the pod/global configure. Use Jobs withhelm.sh/hookfor tasks like DB migrations that need app config; they run once per Helm operation rather than on every pod restart.volumeMountsdict key as name: whenvolumeMountsis specified as a dict, the key is now injected as thenamefield (matching the behaviour ofenvandenvFrom). List-stylevolumeMountscontinues to pass through unchanged.configure.env: renamed from the undocumentedconfigure.environmentand now implemented. Setconfigure.env: falseon a container to suppress the globalenvlist from being applied. Container- and pod-levelenvare always respected regardless of this flag.Ingress port name: the backend port name in generated Ingress rules is now resolved directly from the service port map keys instead of relying on a side-effect mutation from
service.yaml. No change in rendered output.volumeMountsguard: thevolumeMounts:section no longer renders when all auto-mount flags (configure.files,configure.secretFiles) are disabled and no explicit mounts are defined, preventing an emptyvolumeMounts: nullkey in the container spec.deployment,cronJob, andjobentries with a null value (e.g.deployments: { app: }) no longer crash: the null-guard merge now runs before theenabledcheck in all three templates.standard.fullname: the chart namestandardis now treated as a transparent wrapper. Resources no longer get a-standardsuffix when the chart is used directly; the release name is used as the full name instead. All dependent charts that setchartNameare unaffected.New
ingress:single-ingress shorthand: setingress.hosts,ingress.className,ingress.annotations, andingress.tlsdirectly, injected intoingressesusing the release name as key.New
service:single-service shorthand: setservice.portsdirectly, injected intoservicesusing the release name as key.New
deployment:single-deployment shorthand: setdeployment.containers,deployment.replicaCount, etc. directly, injected intodeploymentsusing the release name as key.
2026-04-15
Standard
- HPA support reworked onto
autoscaling/v2(deployments[].autoscaling): thescaleTargetRefis automatically populated from the deployment context. Defaults:minReplicas: 1,maxReplicas: 10. Addedenabledflag to disable the HPA while keeping the config. Supports fullmetricslist (passed through), shorthandtargetCPUUtilizationPercentage/targetMemoryUtilizationPercentage, andbehavior(scaleUp/scaleDown policies).