- Shipped
- September 24, 2026 at 8:02 AM UTC
- Author
- Kamo
- Commit
- c3a22c6
A session tab is Guacamole's document, so its own <link rel="icon" href="images/logo-64.png"> owns the tab, and a member opening their company's computer watches the icon turn into a third party's. Keeping the tab on Kamo's origin and framing the session would have kept the organization's icon; the gateway answers every computers.* route with X-Frame-Options: DENY, so that is not available. The gateway answers for those two files instead. WHOSE ICON IS DECIDED FROM THE HOST, AND SOMETIMES THE ANSWER IS NOBODY'S. An icon request is a plain image GET issued while the browser renders a third party's document. It carries no session and no token, so the host is the only signal there is. On an organization's own computers.<domain> that is a complete answer. On the shared platform host it is not: resolving by host there names the PLATFORM, as layout.tsx already says — "which is nobody's tenant". So the platform host deliberately resolves to no organization and gets an unbranded glyph. Every organization whose domain is not yet live shares that host, and painting KamoCRM's mark on a tenant's tab is the exact thing a white label exists to prevent — while looking, from here, indistinguishable from working. It is also indistinguishable from the correct answer for KamoCRM's own members, which is why there is no exception carved out for them. Nothing has to change for an organization to get its own icon: the moment its computers host is live, the host names it and the route resolves it. The glyph is a plain monitor outline in slate, no brand at all, at the two sizes Guacamole declares. An organization's own icon is resolved alias -> config.json -> favicon set, the same chain DynamicMetaLoader uses, and every failure along it falls back to the glyph: a favicon is not worth failing a page over, and a wrong brand is worse than no brand. THE ROUTE LIVES IN kamo, NOT BESIDE THE REST OF THE GATEWAY IN hosted-computers. Traefik runs with allowCrossNamespace and allowExternalNameServices both at their default of false, so an IngressRoute over there cannot reach kamowebinternal-service, and turning on either flag is a cluster-wide change to reach one favicon. The certificate is already issued in this namespace, so the route sits beside the service it forwards to and CI applies it with the code. themePublicBase is extracted so the bucket's layout is written down once: Theme.tsx is "use client" and the server needed the same shape.
