Validate Helm Charts / Detect changed charts (pull_request) Successful in 7s
Validate Helm Charts / Resource quantities (pull_request) Successful in 12s
Validate Helm Charts / Build stalwart (pull_request) Successful in 17s
Validate Helm Charts / Trivy config stalwart (pull_request) Successful in 17s
Install-test / Install-test stalwart (pull_request) Successful in 1m36s
Validate Helm Charts / Install-test (pull_request) Successful in 1m36s
Replaces the dependency on upstream's valkey chart with this repo's own, resolved from the published index: version: "1.0.0+up9.1.2.alpine" repository: "https://git.jk-dev.de/api/packages/jlab-cluster/helm" The condition is "valkeySubchart.enabled", NOT "valkey.enabled", and that is forced rather than stylistic. Everything under "valkey:" is handed to the subchart as its values and validated against ITS schema, and our valkey chart ships additionalProperties: false with no "enabled" property - so "valkey.enabled" is rejected by the subchart: valkey: - at '': additional properties 'enabled' not allowed Measured. And because Helm skips a DISABLED subchart's schema validation, that error would have surfaced only for whoever first set it to true: every render, lint and install-test in CI would have stayed green. Adding "enabled" to valkey/values.schema.json was rejected as the repair - that chart does not read the key, and it would have needed its own PR and a publish first. The host helper was also wrong for our chart and is fixed: our Service is "<release>-valkey-service", not upstream's bare "<release>-valkey". The values block is rewritten for our chart's schema, with the pair chosen rather than inherited: CACHE (persistence off + allkeys-lru), because everything Stalwart keeps in the in-memory store - rate limiters, auth tokens, sessions, auto-ban entries, coordination pub/sub - is reconstructible, and the node-id lease lives in the data store. The cost is named where it is set: with allkeys-lru the rate limiters and the auto-ban FAIL OPEN under memory pressure, so the answer is to size memory, not to switch to noeviction (which would make writes error and take out authentication instead). secrets.authSecretRef wants an item whose single field "auth-conf" holds the complete "requirepass <pw>" line, not a bare password. Chart.yaml's comments are corrected where they became false: nothing is "consumed as it comes" any more and there is no shortfall of someone else's to document. The Renovate reasoning stays and is now backed by measurement. New trap, in Chart.yaml and in three places in the wiki: NEVER change valkey/ and a chart depending on it in the same PR. The dependency resolves from the published index, so a combined PR lints, packages, renders AND install-tests against the OLD subchart - green on an artifact that is not the one in the diff. Two consecutive PRs. Two things measured, not assumed, because either could have broken the update path with no symptom but "no updates ever": - helm dependency update AND build resolve the exact build-metadata version from the URL alone with an EMPTY HELM_REPOSITORY_CONFIG - a fresh runner's state - so the anonymous index needs no credential and ci/helm-dependencies.sh is untouched; - Renovate 44.132.2 dry run with the dependency pinned low: manager helmv3 matched the file, took registryUrls from Chart.yaml and offered newVersion "1.0.0+up9.1.2.alpine", versioning "helm". The self-hosted index and the "+up..." suffix are both handled. README: the claim "no registry address appears in this repository" is narrowed to what still holds - the publish target and its credentials come from 1Password and are not in the repo. The read path is now in Chart.yaml by necessity, carries no credential, and the host was always in CLAUDE.md. Done here rather than later so the paperless PR finds it already corrected. Re-verified after the change: helm lint --strict (0 failed), helm package (the subchart is embedded in the .tgz), helm template with the subchart OFF and ON (ON was previously impossible), against CI test-values, the rendered config.json, ci/run-quantity-render-test.sh (0 failed), NOTES.txt through the scratch-ConfigMap trick, and the fail paths including the reworded abort. The rendered subchart Service name matches what the helper emits, the cache pairing really renders (maxmemory-policy allkeys-lru, appendonly no, save "", emptyDir) and no PVC appears. Part of #65
130 lines
7.3 KiB
YAML
130 lines
7.3 KiB
YAML
apiVersion: v2
|
|
name: stalwart
|
|
description: A Helm chart to deploy a cluster-capable Stalwart mail server (SMTP, IMAP, JMAP, ManageSieve) on Kubernetes
|
|
icon: https://avatars.githubusercontent.com/u/76623657
|
|
|
|
type: application
|
|
|
|
# appVersion is the exact image tag, and the "v" is part of it - so it is part
|
|
# of appVersion and of the "+up" suffix. Precedent: calibre-web-automated
|
|
# (+upv4.0.6), matrix-synapse (+upv1.159.0), ytdlp-web-player (+upv1.2.0).
|
|
#
|
|
# The glibc image, not "-alpine". Both flavours are published for every release
|
|
# from the same source and carry the same uid/gid 2000 and the same two volumes;
|
|
# the choice is a deployment decision, and keeping it out of the tag is what
|
|
# lets renovate.json5 anchor the version with a plain three-part regex instead
|
|
# of maintaining a compatibility suffix. The moving tags "latest", "v0.16" and
|
|
# their -alpine twins are excluded by that same anchor: measured on 2026-10-02
|
|
# all three of latest / v0.16 / v0.16.24 resolved to one digest pushed seconds
|
|
# apart, so either floating name would change the running image with no commit
|
|
# in this repository and nothing to report it.
|
|
version: 1.0.0+upv0.16.24
|
|
appVersion: "v0.16.24"
|
|
|
|
maintainers:
|
|
- name: jklein
|
|
|
|
# The second chart in this repo with a dependency (after ytdlp-web-player).
|
|
# README, "Chart dependencies", holds the bar it has to clear and the price;
|
|
# both are restated here because the price is paid by whoever reads this file
|
|
# next, not by whoever added the line.
|
|
#
|
|
# WHY ONE HERE. Stalwart's in-memory store is not a cache that can be dropped:
|
|
# from v0.16 it also carries the cluster coordinator ("the Default variant
|
|
# reuses the Redis connection already configured on the in-memory store"), so a
|
|
# multi-node install does not work without it. Redis/Valkey is admissible as
|
|
# the in-memory store ONLY - never as the data or blob store. Offering it inside
|
|
# the chart means the wiring (host, port, egress rule) is in one place instead
|
|
# of split across two releases that have to agree.
|
|
#
|
|
# WHY IT IS OFF BY DEFAULT: an installation that already runs a Valkey points
|
|
# externalServices.valkey.host at it and this dependency renders nothing. The
|
|
# subchart is the path for an installation that has none.
|
|
#
|
|
# THE SUBCHART IS OUR OWN valkey CHART, resolved from the published index -
|
|
# NOT upstream's. So guideline 14.2 ("we consume their chart as it comes") does
|
|
# not apply here and there is nothing of someone else's to leave unpatched: the
|
|
# subchart follows this repo's conventions because it IS this repo's chart. What
|
|
# does apply is everything about the subchart being invisible downstream, plus
|
|
# one hazard that a self-referencing dependency adds and an external one does
|
|
# not - see the PR-ordering warning below.
|
|
dependencies:
|
|
- name: valkey
|
|
# KEEP THIS VERSION MOVING - it is the only path a Valkey update has.
|
|
#
|
|
# A subchart is invisible to everything downstream that watches Helm release
|
|
# versions: what this file declares is baked into our packaged .tgz, and
|
|
# Fleet only ever sees the version of "stalwart". So a new valkey chart - a
|
|
# security fix included - reaches a cluster ONLY when this line is raised
|
|
# and a new stalwart version is published. Nothing reports the gap.
|
|
#
|
|
# Renovate's BUILT-IN helmv3 manager reads this block and opens the PR (no
|
|
# customManagers entry exists or would help - repository and version sit
|
|
# together in one file, which is the case that manager is for), and
|
|
# ci/renovate-bump-chart.sh bumps this chart's patch version, which is what
|
|
# actually ships it. That chain is the whole safety net; switched off, this
|
|
# line needs a human on a calendar instead.
|
|
#
|
|
# MEASURED, not assumed, because the registry is self-hosted and the version
|
|
# carries build metadata - two things that could each have broken the chain
|
|
# silently. Renovate 44.132.2, dry run on 2026-10-02 with this dependency
|
|
# pinned at a lower version: manager helmv3 matched the file, took
|
|
# registryUrls from the line below, and offered
|
|
# newVersion: "1.0.0+up9.1.2.alpine", versioning: "helm"
|
|
# with the release timestamp read from our index. So both the self-hosted
|
|
# index and the "+up..." suffix are handled.
|
|
#
|
|
# Independent of appVersion: raising it is a patch or minor bump of this
|
|
# chart and is never tied to the Stalwart image.
|
|
version: "1.0.0+up9.1.2.alpine"
|
|
# Our own published index, and the READ path only. It is anonymously
|
|
# readable - measured 2026-10-02: GET .../index.yaml returns 200 without
|
|
# credentials - so ci/helm-dependencies.sh needs no secret and was not
|
|
# touched. Verified with an empty HELM_REPOSITORY_CONFIG, i.e. the state a
|
|
# fresh runner is in: helm reports "Getting updates for unmanaged Helm
|
|
# repositories" and resolves the exact build-metadata version from the URL
|
|
# alone, with no "helm repo add" anywhere. Both "helm dependency update" and
|
|
# "helm dependency build" were tried.
|
|
#
|
|
# The PUBLISH target and its credentials still live in 1Password and appear
|
|
# nowhere in this repository - see README, "CI/CD".
|
|
repository: "https://git.jk-dev.de/api/packages/jlab-cluster/helm"
|
|
# Off by default, so a plain install renders none of its objects.
|
|
#
|
|
# NOT "valkey.enabled", AND THAT IS NOT A STYLE CHOICE. Everything under the
|
|
# "valkey:" key is passed to the subchart as its values, and our valkey
|
|
# chart ships a values.schema.json with additionalProperties: false and no
|
|
# "enabled" property - so "valkey.enabled" is rejected by the SUBCHART:
|
|
# Error: values don't meet the specifications of the schema(s) in the
|
|
# following chart(s): valkey: - at '': additional properties 'enabled'
|
|
# not allowed
|
|
# Measured. Worse, Helm skips a disabled subchart's schema validation, so
|
|
# the error appears only for whoever first sets it to true - the default
|
|
# path renders clean.
|
|
#
|
|
# The condition is therefore a key of OUR OWN, outside the subchart's value
|
|
# subtree, which is also the honest shape: "enabled" is not a valkey value.
|
|
# It only ever looked like one because upstream's schema was permissive.
|
|
# The alternative - adding "enabled" to valkey/values.schema.json - would
|
|
# have to be its own PR and be published first (see the warning below), for
|
|
# a key that chart does not read.
|
|
condition: valkeySubchart.enabled
|
|
#
|
|
# !!! NEVER CHANGE valkey/ AND THIS CHART IN THE SAME PULL REQUEST !!!
|
|
#
|
|
# The hazard a self-referencing dependency adds. This dependency resolves out of
|
|
# the PUBLISHED index, not out of the working tree, and valkey/ is only
|
|
# published by a push to main that touches it. So in one PR carrying both:
|
|
#
|
|
# - every helm command here - lint, package, render, AND the install-test -
|
|
# pulls the OLD valkey .tgz, because the new one does not exist yet;
|
|
# - the PR therefore goes green against a version of the subchart that is not
|
|
# the one in the diff, and the diff to valkey/ is reviewed while nothing
|
|
# actually exercised it;
|
|
# - after the merge both charts publish, and the first install of the new
|
|
# stalwart is the first time the new valkey is used anywhere.
|
|
#
|
|
# Two consecutive pull requests instead: change valkey/, merge, let it publish,
|
|
# then raise the version here. The ordering is not a nicety - the green check on
|
|
# the combined PR is a statement about the wrong artifact.
|