Describe the bug
The CA-extraction controller publishes the trust anchor as <release>.tenant-ca. The dot keeps that name apart from every engine Secret <release><suffix> on the assumption that release names are dot-free. The apps API enforces that (release.prefix is ^[a-z0-9-]*$, application names are DNS-1035 labels). The controller, though, derives the release from the helm.toolkit.fluxcd.io/name label value (internal/controller/cacert/reconciler.go), and a label value may contain dots.
A hand-written HelmRelease named foo.tenant.tenant with an ordinary -ca suffix produces foo.tenant.tenant-ca, the canonical projection name of release foo.tenant. The adoption guard refuses to overwrite a Secret it does not own, so the outcome is a stuck projection, not a leak. The invariant is just not checked where the name is built.
Environment
- Cozystack main, 2026-09-04
To Reproduce
- Create a HelmRelease
foo.tenant.tenant in a tenant namespace whose chart writes a Secret <release>-ca
- Create a sentinel for release
foo.tenant in the same namespace
- The projection for
foo.tenant refuses its name because a foreign Secret occupies it
Expected behaviour
The controller refuses a derived release name containing a dot with its own Ready=False reason.
Actual behaviour
The dotted name is accepted. Tenants have no RBAC on HelmReleases, so this takes an operator, which bounds the severity.
Checklist
Describe the bug
The CA-extraction controller publishes the trust anchor as
<release>.tenant-ca. The dot keeps that name apart from every engine Secret<release><suffix>on the assumption that release names are dot-free. The apps API enforces that (release.prefixis^[a-z0-9-]*$, application names are DNS-1035 labels). The controller, though, derives the release from thehelm.toolkit.fluxcd.io/namelabel value (internal/controller/cacert/reconciler.go), and a label value may contain dots.A hand-written HelmRelease named
foo.tenant.tenantwith an ordinary-casuffix producesfoo.tenant.tenant-ca, the canonical projection name of releasefoo.tenant. The adoption guard refuses to overwrite a Secret it does not own, so the outcome is a stuck projection, not a leak. The invariant is just not checked where the name is built.Environment
To Reproduce
foo.tenant.tenantin a tenant namespace whose chart writes a Secret<release>-cafoo.tenantin the same namespacefoo.tenantrefuses its name because a foreign Secret occupies itExpected behaviour
The controller refuses a derived release name containing a dot with its own
Ready=Falsereason.Actual behaviour
The dotted name is accepted. Tenants have no RBAC on HelmReleases, so this takes an operator, which bounds the severity.
Checklist