feat(templates): collapse-aware single-source infra secrets + CI enforcement - #1470
Merged
Conversation
Apply the chart standard across all charts: chart-type annotations, values.schema.json for every chart, hardened container security contexts (allowPrivilegeEscalation, seccompProfile), emptied default credentials and encryption keys, helpers.tpl renamed to _helpers.tpl, secrets manifests normalized to secrets.yaml, and Chart.lock files tracked for reproducible dependency resolution. X-Lerian-Ref: 0x1
Add validate-helm-charts.go with a static contract check (--strict) and a render gate (--render-gate) backed by a standard baseline config and dummy render values for charts requiring production secrets. Wire the render gate into the release workflow and enforce the contract via a dedicated helm-chart-standard workflow. Track charts/*/Chart.lock in git and use octal literal notation in existing scripts. X-Lerian-Ref: 0x1
Document the chart contract enforced by CI and the render inventory describing how each chart is validated. Link both from the root README along with the local validation commands. X-Lerian-Ref: 0x1
Remove custom `*.enabled` templates for nested dependencies from `_helpers.tpl` in multiple charts (`plugin-access-manager`, `plugin-fees`, `reporter`) to rely on standard Helm dependency conditions natively. Remove hardcoded `erlangCookie` secret from the `matcher` chart values. Refactor the `helm-chart-standard` CI workflow to pass GitHub context and step outputs through environment variables instead of direct string interpolation in bash scripts, improving security and workflow stability. Update auto-generated `helm-render-inventory.md` to reflect the latest chart rendering statuses after these changes.
Document the single-source contract (Pattern A: app reads the Bitnami subchart Secret via secretKeyRef; Pattern B: non-Bitnami brokers read the app Secret via existingSecret) and the verified Bitnami Secret name/key table in the chart standard, including the `enabled` coercion gotcha and the valkey.io N/A note. Add a `dual-secret-infra-password` validator rule that flags an infra password (POSTGRES/MONGO/REDIS/DB_* PASSWORD) still gated by `required` in a Secret template while the matching bundled Bitnami subchart is declared as a dependency — the exact dual-secret regression the refactor removes. The rule ignores the post-refactor conditional-write form and external-only keys with no subchart. X-Lerian-Ref: 0x1
Read MONGO_PASSWORD from the Bitnami mongodb subchart Secret (<release>-mongodb, key mongodb-root-password) via a secretKeyRef env entry instead of keeping an operator-provided copy. Adds the reusable infraSecretRef helper, drops the review-era required gate, and guards the three cases (bundled subchart / external inline / existingSecret) so the external BYOC path is preserved. Slims the render fixture and updates the README contract. X-Lerian-Ref: 0x1
Apply the Bitnami secretKeyRef pattern to the single-subchart charts: - plugin-br-payments: POSTGRES_PASSWORD from <release>-postgresql/password. - plugin-br-pix-direct-jd: DATABASE_PASSWORD + POSTGRES_PASSWORD across the pix Deployment and job CronJob; external client/JD/Midaz secrets stay required. - underwriter: Postgres primary/replica + Valkey passwords; the external RABBITMQ_DEFAULT_PASS stays operator-provided. - plugin-access-manager: repoint the auth-backend, migrations and init-user workloads at the aliased <release>-auth-database/password Secret, drop DB_PASSWORD from the plugin-auth Secret, and remove the dead plaintext dataSourceName helper. Each replaces the review-era required gate with the three-way internal/external-inline/existingSecret guard and updates fixtures/READMEs. X-Lerian-Ref: 0x1
MongoDB (Pattern A): the manager, worker and KEDA ScaledJob read MONGO_PASSWORD from <release>-mongodb/mongodb-root-password via secretKeyRef; drop the required gate and range it out of both component Secrets. RabbitMQ (Pattern B): point the groundhog2k broker at the reporter-manager app Secret via authentication.existingSecret so the broker credentials live only in secrets.RABBITMQ_DEFAULT_PASS (which KEDA already reads), and add a stable, required-when-bundled RABBITMQ_ERLANG_COOKIE since existingSecret suppresses the inline cookie. This also resolves the latent broker/app user mismatch. Valkey (valkey.io) exposes no Secret-based auth and ships disabled, so it is documented as not single-sourceable. Removes the dead dataSourceName helper. X-Lerian-Ref: 0x1
- matcher: Postgres primary/replica + Valkey passwords via secretKeyRef. - midaz: ledger single-sources Postgres (onboarding/transaction + replicas) and Mongo (onboarding/transaction) plus Valkey; crm single-sources its Mongo password. The single midaz pg role and root mongo user mean several app env names map to the same subchart key. - plugin-br-bank-transfer: Postgres/Valkey via secretKeyRef; MongoDB is URI-only, so MONGO_URI is assembled on the deployment as mongodb://bank_transfer:$(MONGO_PASSWORD)@<release>-mongodb... with MONGO_PASSWORD sourced from <release>-mongodb/mongodb-passwords; the plaintext URI/password leave the Secret and the release-derived host fallback is preserved. RabbitMQ is intentionally left operator-provided in matcher and midaz: each ships files/rabbitmq/load_definitions.json with a baked password_hash the broker imports at boot, a second source Pattern B cannot reconcile. This is documented in each README as a tracked follow-up. X-Lerian-Ref: 0x1
- flowker: URI-only app, root mongo user. MONGO_PASSWORD is read from <release>-mongodb/mongodb-root-password and MONGO_URI is assembled on the deployment via $(MONGO_PASSWORD) expansion with a release-derived host; the required MONGO_URI gate and plaintext URI leave the Secret. Also fixes a live bug where the wait-for-mongodb init container referenced deleted MONGO_HOST/MONGO_PORT keys and rendered `nc -z "" `. - plugin-bc-correios: single-source POSTGRES_PASSWORD from <release>-postgresql/password (un-nesting env from the tracing conditional); valkey/CACHE_PASSWORD left untouched as it is not a live dual-secret, and RabbitMQ stays a documented follow-up. Regenerate the render inventory. X-Lerian-Ref: 0x1
Replace printf "%s-%s" .Release.Name derivations of Bitnami subchart Secret and Service names with common.names.dependency.fullname, which honors Bitnami release-name collapse (release name containing the subchart name yields an uncollapsed ref to a Secret that does not exist, so pods fail with CreateContainerConfigError) as well as nameOverride and fullnameOverride. Applies to 11 charts; matcher and plugin-br-payments also derive in-cluster hosts in configmap/NOTES. The _helpers.tpl files are committed whole and also carry: - plugin-access-manager: required gate on auth.secrets.DB_PASSWORD when auth-database is external/disabled (H2) and real fallbacks for the single-arg default no-op in the name helpers (L2) - midaz: new midaz.mongodbAuthRequired fail gate (H3) - reporter: rabbitmq existingSecret consistency fail gate (A1) - plugin-fees: dead dataSourceName helper removed (L10) and collapse-aware mongoHost helpers (companion of the infra-host fallback commit) X-Lerian-Ref: 0x1
Wire the new fail gates into their consumers so misconfiguration fails at render time instead of dangling secretKeyRefs at runtime: - midaz ledger and crm include midaz.mongodbAuthRequired: rendering with the bundled MongoDB and mongodb.auth.enabled=false now fails with guidance (Bitnami creates no Secret in that mode, while the deployments previously still referenced mongodb-root-password) - reporter manager and worker secrets include the rabbitmq existingSecret consistency gate: a fullname override that breaks the default reporter-manager reference now fails with guidance instead of leaving the broker pointing at a stale Secret name X-Lerian-Ref: 0x1
- plugin-br-bank-transfer: zero the committed RabbitMQ Erlang cookie (a real cluster-auth credential; the only groundhog2k chart not yet remediated) and drop the two never-consumed CI fixture keys - underwriter: suppress infra POSTGRES_PASSWORD/REDIS_PASSWORD in the app Secret when the bundled subchart provides them (matcher's gated pattern), avoiding the double-definition the standard forbids; add the missing CI render fixture - plugin-bc-correios: drop pre-install/pre-upgrade hook annotations from the app Secret so it follows the release lifecycle instead of being orphaned on uninstall - plugin-access-manager: delete orphaned common.authorizer.clientSecret - go-boilerplate-ddd: move MULTI_TENANT_REDIS_PASSWORD out of the ConfigMap into the Secret map - reporter: drop inert secrets.REDIS_PASSWORD (valkey auth disabled) and realign values-template with values (stale MONGO_PASSWORD out, required RABBITMQ_ERLANG_COOKIE in) X-Lerian-Ref: 0x1
KEDA cpu/memory scalers ignore authenticationRef; emit it only for trigger types that consume it. X-Lerian-Ref: 0x1
- plugin-br-pix-direct-jd: rename pix.useExistingSecrets to the singular useExistingSecret the templates actually read (the plural key was dead, silently ignoring the operator toggle) - README dependency notes corrected to match Chart.yaml reality: tracer (no bundled PostgreSQL; bootstrap Job only), flowker (no bundled PostgreSQL; audit DB is external), lerian-notification (no bundled dependencies), plugin-br-pix-indirect-btg, plugin-br-pix-switch - plugin-br-pix-indirect-btg: image tag default fallback on the three worker deployments, matching the pix sibling X-Lerian-Ref: 0x1
Pin floating minor ranges in Chart.yaml to the exact patch versions already resolved in each Chart.lock (postgresql 16.3.5, mongodb 16.4.12). A future helm dependency update can no longer silently re-resolve to a different patch whose generated-Secret contract the single-source pattern depends on; locks regenerated, vendored tgz versions unchanged. X-Lerian-Ref: 0x1
Replace the three copy-pasted generic schemas (additionalProperties true everywhere, zero required, component keys from unrelated charts) with real per-chart schemas produced by a committed generator. Root objects are closed (additionalProperties false) over each chart's actual top-level values keys plus global, so operator typos now fail helm schema validation at render time; third-party subchart blocks stay opaque. Regeneration is deterministic: cd .github/scripts && go run ./generate-values-schemas --root ../.. X-Lerian-Ref: 0x1
validate-helm-charts gains the checks that would have caught this branch's own findings: - render gate now also renders every chart under a release name equal to each Bitnami dependency name (the collapse scenario CI never exercised) and asserts no rendered secretKeyRef dangles, with a small documented allowlist for operator-provisioned Secrets - secret classifier is path-aware: generic carriers like value under erlangCookie/password parents now classify as credentials (the blind spot that let a real committed Erlang cookie pass CI), with cookie/erlang added to the token list - secret-in-configmap also scans ConfigMap templates, not only values - isPasswordKey tightened to word boundaries (no more compass/bypass) - migration-phase scaffolding (phaseOwner, Migration Queue) removed; the committed render-inventory snapshot is deleted in favor of on-demand generation Scripts restructured one-directory-per-tool so go vet ./... passes; two stale committed ELF build artifacts removed and gitignored; workflow and doc references updated to the new paths. X-Lerian-Ref: 0x1
- plugin-bc-correios: null the four hardcoded in-release host defaults so the template fallbacks become source of truth; the shipped CACHE_ADDR pointed at -valkey-master, a Service that does not exist (valkey names it -primary). Fix two fallbacks the literals were masking: OBJECT_STORAGE_ENDPOINT derives from bc-correios.fullname (the inline SeaweedFS Service name) instead of the release name, and RABBITMQ_HOST replicates groundhog2k's fullname collapse. The configmap also carries this chart's collapse-safe Bitnami derivations - plugin-fees: null the hardcoded MONGO_HOST FQDN and derive the bundled subchart Service via the collapse-aware mongoHost helpers (helpers landed with the name-derivation commit); explicit value still wins for external MongoDB; values-template and README aligned - plugin-br-pix-direct-jd: guard the pix and job app Secrets with useExistingSecret so no redundant Secret is emitted when an existing one is supplied (qrcode already had the guard) X-Lerian-Ref: 0x1
Sweep all chart READMEs, the canonical standard doc, and the root README for claims that went stale during the standardization revamp. - helm-chart-standard.md: replace the naive printf name-derivation prescription with common.names.dependency.fullname (alias rule, collapse rationale); add fail-loud gate, values.schema.json policy, expanded validation (collapse render gate + allowlist), and KEDA cpu/memory authenticationRef sections; correct the dependency pin table to the exact-but-non-uniform reality. - Chart READMEs: refresh image tag defaults, zero stale 'lerian' password defaults, rewrite single-source secret guidance, fix release-name assumptions where Secret refs are now collapse-aware, correct midaz RabbitMQ provenance (groundhog2k, not Bitnami), fix flowker MONGO_URI placement and removed-key examples, correct pix-switch component/image claims, refresh dependency versions. - Drop bank-transfer phantom secret key row (key exists nowhere in the chart); fix Valkey repository lines to the OCI registry; fix fees upgrade command OCI path; use <version> placeholders in pix-indirect-btg install examples; correct otel matrix version. - One values.yaml comment fix (bank-transfer MONGO_PASSWORD is only required for external MongoDB, not unconditionally). X-Lerian-Ref: 0x1
Migrate the last chart off duplicated infra credentials to the standard's Pattern A. Previously the bundled install rendered but the app received an empty DB/Mongo password while the subcharts auto-generated their own, failing auth at runtime. - Add collapse-aware infraSecretRef and host helpers: postgresql -> key 'password' (non-root auth.username pix_btg, enablePostgresUser false, standalone so replica reuses the primary Secret); mongodb -> 'mongodb-root-password' (app connects as rootUser pix_btg; the bootstrap job only serves global.externalMongoDefinitions, default off); valkey.io naming replicated locally (not Bitnami common). - Wire DB_PASSWORD/DB_REPLICA_PASSWORD/MONGO_PASSWORD as discrete secretKeyRef env entries on all four deployments, layered over envFrom; emit them in the app Secrets only on the external path. - Fail loud when postgresql/mongodb is external or disabled and no credential is supplied via component secrets, subchart auth.existingSecret, or component useExistingSecrets + existingSecretName (same trust model as the envFrom path). - Null hardcoded release-name + namespace host defaults (DB_HOST/DB_REPLICA_HOST/MONGO_HOST/REDIS_HOST) and derive them collapse-aware; the old REDIS_HOST '-valkey-master' suffix was wrong (valkey.io renders a single '<release>-valkey' Service). - REDIS_PASSWORD stays operator-provided: valkey.io exposes no Secret-based password to source from. - Update README to the single-source model. Verified: strict 0 violations; render-gate --all exit 0 incl. collapse renders (mongodb/postgresql/valkey); helm lint clean; scenario matrix bundled / external+inline / external+existingSecret / external+none (fails loud) / bundled+useExistingSecrets (subchart Secret still wins). X-Lerian-Ref: 0x1
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.
Pull Request Type
Summary
Repo-wide standardization revamp: brings all 20 charts onto a single, CI-enforced chart contract and fixes a class of latent infra-credential bugs that rendered cleanly but failed authentication at runtime.
Why
Charts derived bundled Bitnami subchart Secret/Service names with naive
printf "%s-%s" .Release.Name "<sub>". That ignores the Bitnami name collapse (release named after the subchart → Secret is just<subchart>, not<release>-<subchart>),nameOverride/fullnameOverride, andauth.existingSecret. Result: danglingsecretKeyRef→CreateContainerConfigError, or — worse — the app reading an empty password while the subchart auto-generated its own, an auth failure invisible until the first query. None of this was caught by CI, because the render gate used release name = chart name, which never collapses.What changed
Naming & secrets (the core fix)
common.names.dependency.fullname(collapse-aware, honors overrides andexistingSecret). 11 charts rewired in the final wave; aliased deps pass the alias (e.g. access-manager'sauth-database); groundhog2k/valkey.io subcharts replicate their own naming locally.secretKeyRef; operators supply infra creds only for external infra. No duplicated infra passwords in app-owned Secrets. A hardcoded default Erlang cookie (credential leak) was zeroed.failthe render with an actionable message instead of dangling (e.g.reporter.rabbitmqErlangCookieRequired,midaz.mongodbAuthRequired, access-manager DB_PASSWORD, plus a consistency gate for renamed existing Secrets).plugin-br-pix-indirect-btgwas the last chart off-standard and in the worst state (zeroed defaults rendering clean but breaking at runtime) — fully migrated, including a fixedREDIS_HOSTthat pointed at a non-existent-valkey-masterService.CI hardening
.github/scripts/<tool>/main.go; two committed ELF binaries removed;go vet ./...clean.erlangCookie.value), ConfigMap-template scanning, dual-secret rule.secretKeyRefassertion, with a documented allowlist (otel-api-key,kedaorg-certs). This is what makes the H1 class visible to CI.Schemas & deps
values.schema.jsonfor all charts via a deterministic generator: closed root (additionalProperties:falseover actual top-level keys +global), opaque third-party subchart blocks. Unknown top-level keys now fail lint/install.Docs
docs/helm-chart-standard.mdrewritten to prescribe the collapse-aware derivation (the old printf anti-pattern was documented as correct), fail-loud gates, schema policy, validation/collapse gate, KEDAauthenticationRefrule.Verification
validate-helm-charts --root .. --strict→ 0 violationsvalidate-helm-charts --root .. --render-gate --all→ exit 0, 20/20 charts incl. collapse rendershelm lint→ 20/20 cleango vet ./...→ cleanplugin-br-pix-indirect-btgmigration verified against a 7-case scenario matrix (bundled / external+inline / external+existingSecret / external+none→fails loud / bundled+useExistingSecrets→subchart Secret still wins / collapse renders)Checklist
Additional Notes
Targeting
mainper maintainer request (the template's default base isdevelop).Scope: 209 files, +6725/−1011, 21 commits. The diff is large but the changes are systematic — the same single-source pattern applied across 20 charts plus the CI that enforces it. Reviewing one fully-migrated chart (
reporterorplugin-br-pix-indirect-btg) againstdocs/helm-chart-standard.mdis the fastest way to validate the pattern; the render gate proves the rest.