feat(stalwart): take our own published valkey chart as the subchart
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 14s
Publish Stalwart Helm Chart / Publish Stalwart Helm Chart (push) Successful in 14s
SonarQube Analysis / SonarQube Analysis (push) Failing after 13s

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
This commit was merged in pull request #77.
This commit is contained in:
jklein authored and Justin Klein committed 2026-10-02 20:59:17 +00:00
1 parent 780cb8eafd
commit 07c75e80c1
6 files changed
+226 -68

No files matched your search

+11 -1
View File
@@ -385,8 +385,18 @@
"startupProbe": {
"$ref": "#/definitions/probe"
},
"valkeySubchart": {
"description": "The dependency condition for the valkey subchart. A key of THIS chart, deliberately outside the 'valkey' subtree: everything under 'valkey:' is handed to the subchart as its values, and this repo's valkey chart has additionalProperties: false with no 'enabled' property, so 'valkey.enabled' is rejected by the subchart itself. Helm skips a disabled subchart's schema validation, so that error would only have surfaced for whoever first set it to true.",
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
}
}
},
"valkey": {
"description": "Values of the valkey subchart (the Valkey project's own chart), passed straight through. Open on purpose and at every level: this chart owns neither the keys nor their meaning, and a closed copy would reject whatever the subchart adds in its next release - the exact failure a schema exists to prevent, pointed at the wrong chart. This chart reads exactly one of them, 'enabled', which is the dependency condition. Two of upstream's defaults fall short of this repo's conventions and are documented in values.yaml rather than patched here.",
"description": "Values passed through to the valkey subchart - this repo's OWN valkey chart, resolved from the published index. Open on purpose and at every level: the subchart owns this schema (it ships its own, and a stricter one than this), and a closed copy here would reject whatever that chart adds in its next release while also duplicating a validation that already happens. This chart reads NONE of these keys; the dependency condition is valkeySubchart.enabled instead. Note the field shape that is easy to get wrong: secrets.authSecretRef points at an item whose single field 'auth-conf' holds the complete line 'requirepass <password>', not a bare password. values.yaml argues the cache-vs-queue choice.",
"type": "object"
}
},