Files
Aleksei Sviridkin b2ae6b773a fix(tenant): fail fast on an empty tenant apex and correct gateway docs (#4538)
Closes #4536

## What this PR does

Two fixes to how tenant charts handle the tenant apex host
(`_namespace.host`), from an audit of what happens when a tenant's
`host` is changed or left empty.

**1. Fail fast on an empty tenant apex (was: silent malformed
hostname).**
Charts that publish a service compose their hostname as
`<sub>.<_namespace.host>` (for example `harbor.<apex>`, `s3.<apex>`,
`grafana.<apex>`). When the injected apex was empty and no per-app
`host` override was set, they emitted a malformed trailing-dot hostname
(`harbor.`) into Ingresses, HTTPRoutes and Certificate dnsNames with no
error. Only the gateway path guarded against this.

A new library helper `cozy-lib.ns-host-required` now sources the apex at
each hostname-emitting site and fails the render with a clear message
when the apex is empty and no override is set. It is scoped to the
injected state, so standalone renders (`helm template` / `helm lint`
with no `_namespace`, or an empty `_namespace` map), no-exposure
tenants, and conditionally emitted resources (external=false, the
kubernetes no-etcd beacon path) are unaffected. The two post-delete
cleanup hooks are left unguarded so an empty apex cannot block
uninstall.

Charts covered: harbor, postgres (external), qdrant (external),
kubernetes (control-plane endpoint), vpn, seaweedfs, bootbox, monitoring
(grafana, alerta, grafana OIDC client), and system/bucket (which also
gains the `cozy-lib` library it was missing, both the local subchart
symlink and its package-source registration).

**2. Correct the tenant `gateway` parameter documentation.**
The `gateway` description (values.yaml, values.schema.json, README, the
Go type, the tenant-rd CRD, and an inline comment in namespace.yaml)
claimed the chart auto-enables a Gateway for tenants whose apex is
derived from the parent (empty `host`) and leaves it off for custom-apex
tenants. The resolver `tenant.gatewayEffective` never inspects `host`:
an unset `gateway` key always means the tenant owns no Gateway and
inherits from the nearest ancestor that owns one. The unit tests already
pin this behavior. The description is rewritten to match and
regenerated.

**Behavior change.** A tenant with an empty injected apex and no `host`
override that enables one of the covered components now fails its render
(the HelmRelease reports NotReady) instead of deploying a broken
hostname. In practice the apex is always injected (the root tenant has
`root-host`, children inherit it), so this only trips a genuinely
misconfigured tenant.

Tests: a new `cozy-lib.ns-host-required` unit test, plus per-chart guard
tests for harbor, qdrant, kubernetes, postgres, vpn, bootbox, seaweedfs,
monitoring and system/bucket. All affected chart suites pass.

### Screenshots

Not applicable (no UI change).

### Downstream repositories

I walked the trigger map against the diff. The only touchpoint is the
tenant `README.md` gateway description, which the website release bot
regenerates automatically from `README.md` on a stable tag (no manual
follow-up). The terraform provider is not affected: this is a
description-only change to the existing `gateway` field, with no field,
default or enum change, and the tenant-rd CRD schema reaches the
provider as opaque JSON. Boxes left for a maintainer to confirm.

- [ ] No downstream repository is affected by this change
- [ ] [cozystack/website](https://github.com/cozystack/website) -
follow-up:
- [ ]
[cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack)
- follow-up:
- [ ]
[cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack)
- follow-up:
- [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up:
- [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up:
- [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) -
follow-up:
- [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) -
follow-up:
- [ ]
[cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server)
- follow-up:
- [ ]
[cozystack/external-apps-example](https://github.com/cozystack/external-apps-example)
- follow-up:
- [ ] [cozystack/examples](https://github.com/cozystack/examples) -
follow-up:
- [ ] [cozystack/community](https://github.com/cozystack/community) -
follow-up:

### Release note

```release-note
fix(tenant): tenant charts now fail rendering with a clear error when a tenant's apex host is empty and no per-app host override is set, instead of silently emitting a malformed hostname; the tenant `gateway` parameter description is corrected to match actual behavior (an unset `gateway` never auto-enables a Gateway).
```


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Host-dependent services now show a clear rendering error when neither
a tenant host nor an app host is configured, instead of producing an
invalid hostname.
* Tenants without `gateway: true` use the nearest ancestor’s Gateway,
whether their host is inherited or custom. Enable `gateway: true` for a
tenant’s own Gateway, IP, and certificate; this is required to make a
custom apex publicly reachable.
* **Documentation**
* Clarified Gateway inheritance behavior and when a tenant needs its own
Gateway.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-28 21:32:36 +03:00
..