Skip to content

Normalize the tenant apex and platform root host at the write site #3328

Open

Description

Problem

The tenant apex (namespace.cozystack.io/host) and the platform root host (_cluster.root-host) are free-form values with no lowercase validation anywhere. packages/apps/tenant/values.schema.json declares host as a bare {"type": "string"}, and TenantGatewaySpec.Apex in api/gateway/v1alpha1/tenantgateway_types.go carries no kubebuilder pattern. A mixed-case value therefore reaches the platform, and each consumer has to cope with it independently.

#3208 normalizes the reader side: the tenant hostname ValidatingAdmissionPolicies lowercase both operands of every comparison, so admission follows DNS case semantics. That fix stands on its own — the host label can be set out-of-band by a trusted caller, so the policies must stay defensive regardless of what any writer does. But the writer still emits the un-normalized value, and two consumers downstream do not cope with it.

What breaks on a mixed-case apex

gatewayv1.Hostname (gateway-api v1.4.1, apis/v1/shared_types.go) carries +kubebuilder:validation:Pattern=^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ — lowercase only. The TenantGateway reconciler builds listeners from the apex verbatim (Hostname("*." + tgw.Spec.Apex)), so a mixed-case apex makes the Gateway CREATE fail CRD validation and the tenant ends up with no Gateway at all.

The same reconciler dedups child apexes by exact string before adding them as SANs to the parent wildcard Certificate. Its own comment states the dedup is there because cert-manager rejects duplicates — and a pure case difference defeats it, in precisely the state a mixed-case apex produces.

Proposal

Normalize once, at the write site, so the label, _namespace.host, and TenantGateway.spec.apex all agree: lowercase $computedHost where the tenant namespace template writes the label (packages/apps/tenant/templates/namespace.yaml), and lowercase the root host where it is templated. Keep the reader-side normalization from #3208 as fail-closed defense — the two are complementary, not redundant.

Alternatively a validation pattern on tenant.spec.host and TenantGatewaySpec.Apex would reject the bad input at the edge instead of silently rewriting it. Worth picking deliberately: rejecting is louder, normalizing is friendlier to an operator who typed a capital letter.

Activity

  1. added
    kind/featureCategorizes issue or PR as related to a new feature
    area/networkingIssues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn)
    triage/needs-triageIndicates an issue needs triage by a maintainer
    on Jul 16, 2026
  2. github-actions commented on Sep 15, 2026

    @github-actions

    This issue has had no activity for 60 days and was marked lifecycle/stale.
    It will be closed in 14 days unless commented or labelled lifecycle/frozen.

  3. added
    lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale
    on Sep 15, 2026
  4. added
    triage/acceptedIndicates an issue is ready to be actively worked on
    priority/backlogGeneral backlog priority. Lower than priority/important-longterm
    and removed
    lifecycle/staleDenotes an issue or PR has remained open with no activity and has become stale
    triage/needs-triageIndicates an issue needs triage by a maintainer
    on Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/networkingIssues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn)kind/featureCategorizes issue or PR as related to a new featurepriority/backlogGeneral backlog priority. Lower than priority/important-longtermtriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions