Skip to content

fix(cozy-lib): make the cozyconfig helpers survive uninjected values - #3647

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/cozy-lib-nil-guards
Aug 8, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/cozy-lib-nil-guards

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

_cluster and _namespace reach a chart through valuesFrom on the cozystack-values Secret, so they are absent whenever a chart is rendered on its own: helm lint, a plain helm template, and any helm-unittest suite that does not set them. Twelve of the helpers in _cozyconfig.tpl read straight through the missing map and abort the render instead of returning the empty default they document.

Two spellings, one cause. index .Values._cluster "root-host" raises index of untyped nil; .Values._namespace.host raises nil pointer evaluating interface {}.host. In both, the trailing | default "" never runs, because it applies to the result and there is no result, only an error. That default covered a key missing from a map that exists, never a missing map.

The guard goes on the map, which is what cozy-lib.images-registry in this same file already did:

(index (.Values._cluster | default dict) "root-host") | default ""

index on an empty map returns nil harmlessly, so the trailing default applies as it always read, and with the map present | default dict returns it untouched.

This fixes no chart that is failing today. The charts that cannot render standalone read the injected values directly in their own templates rather than through these helpers, so a change to the library does not reach them; they are handled where they live. Worth being blunt about the same point from the other side: twelve of the thirteen helpers here currently have no callers anywhere in packages/. Only cozy-lib.images-registry is reached, from cozy-lib.image, and it was already guarded. The guard is still worth having on the rest, because they are the library's public surface, they are what a chart author copies when reaching for cluster configuration, and a broken spelling propagates by being read. cozy-lib.image is called from four templates, so these helpers do get adopted once they exist.

Rendered output does not change, and that is measured rather than argued. All 34 charts that symlink cozy-lib were rendered before and after, both with the injected values populated and with them set to empty maps, and every result is byte-identical. That check needs a control: the first comparison showed eight charts differing, which looks like a regression in a library change. Rendering the unchanged tree twice reproduces exactly those eight, because they generate passwords. Subtracting the control leaves zero real differences.

The suite lives in cozy-lib-tests, which is where library behaviour is pinned, since a library chart renders nothing of its own. One case covers the uninjected state, which needs no mocking because neither key appears in any values file, and one covers the injected state so the guard cannot quietly change what a populated map returns. The injected case pins scheduling and branding as whole YAML documents rather than by substring: those two had their bodies restructured rather than wrapped, and a substring assertion survives the loss of the toYaml that produces the document, because the key name also appears in Go's default map formatting. Against the unguarded helpers the first case fails with index of untyped nil.

Three things left deliberately undone, so they are not mistaken for oversights. The header comments in _cozyconfig.tpl say where these values come from but not what the helpers now do when they are absent, which is the contract this change creates and would be better stated next to the helpers than only in the suite. Chart.yaml in cozy-lib-tests still carries name: quota from when that chart covered one helper family, so the runner prints ### Chart [ quota ] for a suite that now covers three. And the mixed state, one map injected and the other not, has no case of its own; the two guards are independent so composition covers it, and a third case would pin nothing new.

Relates to #3646.

Screenshots

Downstream repositories

Release note

fix(cozy-lib): the cozyconfig helpers now return their documented empty defaults when the platform has not injected `_cluster` / `_namespace`, instead of aborting the render, so a chart using them can be rendered and unit-tested on its own

Summary by CodeRabbit

  • Bug Fixes

    • Improved configuration handling when cluster or namespace settings are missing, preventing template rendering errors.
    • Preserved existing configuration values for scheduling, branding, networking, registries, and component namespaces.
  • Tests

    • Added coverage for configurations with missing platform values.
    • Added validation that injected cluster and namespace settings render correctly.

`_cluster` and `_namespace` reach a chart through valuesFrom on the
cozystack-values Secret, so they are absent whenever a chart is rendered
on its own: `helm lint`, a plain `helm template`, and any helm-unittest
suite that does not set them. Twelve of the helpers in _cozyconfig.tpl
read straight through the missing map and abort the render rather than
returning their documented empty default.

Two spellings, one cause. `index .Values._cluster "root-host"` raises
`index of untyped nil`, and `.Values._namespace.host` raises
`nil pointer evaluating interface {}.host`. In both cases the trailing
`| default ""` never runs: it applies to the result, and there is no
result, only an error. That default covered a key missing from a map
that exists, never a missing map.

Guard the map instead, which is what `cozy-lib.images-registry` in this
same file already did:

    (index (.Values._cluster | default dict) "root-host") | default ""

`index` on an empty map returns nil harmlessly, so the trailing default
applies as it always read. With the map present, `| default dict`
returns it untouched.

This changes no rendered output. Every one of the 34 charts that symlink
cozy-lib was rendered before and after, both with the injected values
populated and with them set to empty maps, and every result is
byte-identical. Eight charts differ between any two runs because they
generate passwords; rendering the unchanged tree twice reproduces
exactly those eight, which is how they are excluded.

What this does not do is fix a chart that fails today. The charts that
cannot render standalone read the injected values directly in their own
templates rather than through these helpers, so they are unaffected by a
change to the library and are being addressed where they live.

Twelve of the thirteen helpers here have no callers anywhere in
packages/ at present; only `cozy-lib.images-registry` is reached, from
`cozy-lib.image`, and it was already guarded. The guard is still worth
having on the rest: they are the library's public surface, they are what
a chart author copies when reaching for cluster configuration, and the
broken spelling propagates by being read. `cozy-lib.image` is called
from four templates, so these helpers do get adopted once they exist.

Add a suite in cozy-lib-tests, which is where library behaviour is
pinned because a library chart renders nothing of its own. One case
covers the uninjected state, which needs no mocking since neither key is
in values.yaml, and one covers the injected state so the guard cannot
quietly change what a populated map returns. The injected case includes
`scheduling` and `branding` specifically: those two are the helpers
whose body was restructured rather than wrapped, so they are the ones
whose present-map behaviour most needs pinning. Against the unguarded
helpers the first case fails with `index of untyped nil`.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@github-actions github-actions Bot added area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files labels Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b98d86c-55c0-45c1-9cf4-d08c9cc3e024

📥 Commits

Reviewing files that changed from the base of the PR and between 605030b and 85fd592.

📒 Files selected for processing (3)
  • packages/library/cozy-lib/templates/_cozyconfig.tpl
  • packages/tests/cozy-lib-tests/templates/tests/cozyconfig.yaml
  • packages/tests/cozy-lib-tests/tests/cozyconfig_test.yaml

📝 Walkthrough

Walkthrough

Cozy configuration helpers now handle missing _cluster and _namespace maps by using empty defaults. New Helm tests verify empty fallbacks and preservation of injected values, including scheduling and branding output.

Changes

Cozy configuration hardening

Layer / File(s) Summary
Guard cluster and namespace lookups
packages/library/cozy-lib/templates/_cozyconfig.tpl
Helpers default missing _cluster and _namespace maps to empty dictionaries. Scheduling and branding render only when values exist.
Validate ConfigMap rendering
packages/tests/cozy-lib-tests/templates/tests/cozyconfig.yaml, packages/tests/cozy-lib-tests/tests/cozyconfig_test.yaml
A test ConfigMap exposes Cozy configuration helpers. Tests cover missing maps and populated cluster and namespace values.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • cozystack/cozystack#3636: Hardens other Helm templates against missing platform-injected _cluster values and adds standalone rendering tests.

Suggested reviewers: ivanhunters

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making cozyconfig helpers handle uninjected values safely.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cozy-lib-nil-guards

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 93ffb38 into main Aug 8, 2026
39 of 40 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/cozy-lib-nil-guards branch August 8, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/platform Issues or PRs related to platform infrastructure (bundle, flux, talos, installer) kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant