Files
zeekay 1598696ac7 chore(brand): purge the upstream name from comments, docs and one env var
Prose only, plus one config knob. Applied to comment lines exclusively, so
import paths, the exported lura symbols (core.Krakend*), the X-KRAKEND header
const, the KRAKEND_ koanf prefix and the devopsfaith/* extra_config namespace
keys were structurally out of reach of the rewrite.

`KRAKEND_ZAP_LISTEN` -> `GATEWAY_ZAP_LISTEN`. LLM.md listed this as pinned to
the koanf env prefix; it is not. koanf owns `KRAKEND_<KEY>` for config-file
key overrides, but this var is the fork's own knob read by direct os.Getenv,
so it belongs with GATEWAY_LISTEN / GATEWAY_SHUTDOWN_TIMEOUT. Nothing in
k8s/ or configs/ sets it, so nothing to migrate -- one prefix for our knobs.

`TestGatewayConfig_NoKrakendAudience` -> `TestGatewayConfig_NoJWTAudience`.

Kept deliberately, and now documented with the reason rather than a bare
"never rebrand": the two `rebrand.go` files (they are the de-branders -- they
must name what they strip), the Makefile schema-rewrite pipeline (same role),
the negative-assertion lists in brand_test.go / production_headers_test.go
(those are the regression guard that FAILS if the brand ever reaches a Server
header -- deleting the token would delete the protection), LICENSE + NOTICE
attribution, deps.sh's module-name grep, and the upstream image address in
mirror-images.yml.

Two LLM.md rows were wrong and are corrected: the extra_config namespace keys
live in the `aliases` map in cmd/gateway/main_legacy.go, not in
configs/*/gateway.json -- the shipped configs use only the friendly aliases
and are already brand-free; and the ingress cross-reference described a
`DefaultRootName` that fork no longer has.

Verified: both builds, all unit packages under -tags legacy, and the legacy
integration harness with CI's skip list.
2026-07-25 13:04:06 -07:00

60 lines
2.7 KiB
Go

// Copyright © 2026 Hanzo AI. MIT License.
package gateway
import "strings"
// brandForHost resolves a request Host to its white-label brand id for the
// Server response header. The gateway is the shared multi-brand edge — it fronts
// api.hanzo.ai, api.lux.network, api.zoo.ngo, ... from one binary — so the Server
// header cannot be a single hardcoded brand; it must be the brand of the request
// Host, or a neutral default when no brand domain matches.
//
// A Host at or under a brand's registrable domain resolves to that brand; the
// longest matching domain wins; the port is stripped and the compare is
// case-insensitive. Returns "" when nothing matches, so the caller supplies its
// own neutral default (NeutralServerBrand).
//
// This mirrors the canonical platform registry in hanzoai/cloud (brand.go /
// BrandForHostOK). The gateway keeps its own copy because its pinned cloud does
// not yet export BrandForHostOK and, more fundamentally, zip's white-label
// middleware rides the zap-proto/fiber fork that the pinned cloud predates — a
// coordinated cloud+zip bump is out of scope for a response-header change. When
// that alignment lands (or a shared brand module is extracted) this folds into
// that one home.
func brandForHost(host string) string {
host = strings.ToLower(strings.TrimSpace(host))
if i := strings.IndexByte(host, ':'); i >= 0 {
host = host[:i]
}
// A fully-qualified Host may carry a trailing root dot ("api.lux.network.");
// strip it so the suffix match still resolves the brand instead of failing to
// neutral. Mirrors cloud/brand.go BrandForHostOK.
host = strings.TrimSuffix(host, ".")
best, bestLen := "", -1
for _, bd := range brandDomains {
if (host == bd.domain || strings.HasSuffix(host, "."+bd.domain)) && len(bd.domain) > bestLen {
best, bestLen = bd.brand, len(bd.domain)
}
}
return best
}
// brandDomains mirrors cloud/brand.go's per-brand Domain + AltDomains.
var brandDomains = []struct{ brand, domain string }{
{"hanzo", "hanzo.ai"}, {"hanzo", "hanzo.cloud"}, {"hanzo", "hanzo.app"},
{"lux", "lux.network"}, {"lux", "lux.cloud"},
{"zoo", "zoo.ngo"}, {"zoo", "zoo.network"}, {"zoo", "zoo.cloud"},
{"pars", "pars.network"}, {"pars", "pars.ai"},
{"bootnode", "bootno.de"},
}
// NeutralServerBrand is the Server value when a request Host matches no brand
// (internal k8s probes, direct-IP hits). Brand-neutral and honest about the role
// without ever naming the framework (fasthttp / fiber / zip / the legacy engine).
const NeutralServerBrand = "gateway"
// hstsPolicy is the Strict-Transport-Security value: two years, subdomains
// included — the Stripe/Cloudflare/GitHub production floor.
const hstsPolicy = "max-age=63072000; includeSubDomains"