Files
zooqueenandHanzo Dev df50d16787
Hanzo CI/CD / cicd (push) Failing after 1h10m29s
CI/CD / cicd (push) Failing after 2h37m43s
Render every console page with the brand of the host serving it
A static export has no host when it prerenders, so BrandProvider renders the
tree only once the browser has resolved the host, pages that show the brand
are client components, the static head names no brand, and the title and
favicon come from the host. The chain page keeps its static params and
metadata on the server and renders its body on the client, with RPC endpoints
on the brand's API origin at /v1/rpc/{chain}/{network}.

Hanzo's API origin is web3.hanzo.ai itself. The node fleet view, its landing
strip and its nav link belong to the brand that operates a fleet, which is
Lux alone. llms.txt, one file for every host, names no brand and points at
each host's own /docs/api.

Marketing copy states no certification the company does not hold and no
unmeasured uptime, latency, volume or response-time figure. Every internal
link points at a page that exists, every catalog chain is prerendered, and
the routes test holds page bodies to zero dead links.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-15 12:01:27 -07:00

127 lines
5.6 KiB
TypeScript

// The white-label contract, as executable assertions.
//
// Run: `pnpm test` (node:test + native TypeScript stripping — no test
// framework, no new dependency).
//
// Every expectation here was verified against the live IAM before it was
// written down; see the probe table at the top of lib/brand.ts. This file is
// what stops it drifting: change a client id or a host and the build's test
// step says so, instead of a customer discovering it at the login screen.
import { strict as assert } from "node:assert"
import { describe, it } from "node:test"
import { getBrand, getBrandKey } from "./brand.ts"
// host → [brand key, IAM issuer, OIDC client id]. The five hosts this one
// image must serve, plus the aliases that ride along with them.
const CONTRACT: [string, string, string, string][] = [
["bootno.de", "bootnode", "https://id.bootno.de", "bootnode-platform"],
["web3.hanzo.ai", "hanzo", "https://hanzo.id", "hanzo-web3"],
["lux.cloud", "lux", "https://lux.id", "lux-cloud"],
["zoo.cloud", "zoo", "https://zoolabs.id", "zoo-cloud"],
["cloud.zoo.network", "zoo", "https://zoolabs.id", "zoo-cloud"],
// Aliases that must inherit their parent's brand.
["www.bootno.de", "bootnode", "https://id.bootno.de", "bootnode-platform"],
["nodes.lux.cloud", "lux", "https://lux.id", "lux-cloud"],
["console.zoo.cloud", "zoo", "https://zoolabs.id", "zoo-cloud"],
["cloud.pars.network", "pars", "https://pars.id", "pars-app"],
]
describe("white-label by hostname", () => {
for (const [host, key, issuer, clientId] of CONTRACT) {
it(`${host} → ${key} / ${clientId}`, () => {
const brand = getBrand(host)
assert.equal(getBrandKey(host), key)
assert.equal(brand.key, key)
assert.equal(brand.iam.url, issuer)
assert.equal(brand.iam.clientId, clientId)
})
}
it("serves the Hanzo API from the console's own origin", () => {
// web3.hanzo.ai routes /v1 to the bootnode service, so a Hanzo page never
// calls a bootno.de address.
const hanzo = getBrand("web3.hanzo.ai")
assert.equal(hanzo.apiUrl, "https://web3.hanzo.ai")
assert.equal(hanzo.wsUrl, "wss://web3.hanzo.ai")
assert.equal(getBrand("bootno.de").apiUrl, "https://api.bootno.de")
})
it("shows a node fleet only on the brand that operates one", () => {
assert.equal(getBrand("lux.cloud").fleet, "lux")
for (const host of ["bootno.de", "web3.hanzo.ai", "zoo.cloud", "cloud.pars.network"]) {
assert.equal(getBrand(host).fleet, null, host)
}
})
it("does not regress the one login that works today", () => {
// lux.cloud + lux-cloud + https://lux.cloud/auth/callback is the triple
// that answers 302 on lux.id and lands a real user on /dashboard. If this
// assertion ever fails, the merge broke a working production login.
const lux = getBrand("lux.cloud")
assert.equal(lux.iam.url, "https://lux.id")
assert.equal(lux.iam.clientId, "lux-cloud")
})
it("resolves unknown hosts and localhost to the neutral default", () => {
for (const host of ["localhost", "127.0.0.1", "example.com", ""]) {
assert.equal(getBrandKey(host), "bootnode")
}
})
it("matches on exact host or dot-suffix, never on substring", () => {
// The old resolver used `hostname.includes(match)`, which would hand a
// real brand's OIDC client id — and therefore its login — to any host an
// attacker can name. These must all fall through to the default.
for (const host of [
"lux.cloud.attacker.example",
"zoo.cloudy.example",
"notbootno.de.example",
"web3.hanzo.ai.evil.test",
"xlux.cloud",
]) {
assert.equal(getBrandKey(host), "bootnode", host)
}
})
it("gives every brand its own mark, wordmark and favicon", () => {
// One image, five identities: a shared /logo.svg for all of them would
// mean bootno.de's mark showing up on zoo.cloud.
const seen = new Set<string>()
for (const host of ["bootno.de", "web3.hanzo.ai", "lux.cloud", "zoo.cloud", "cloud.pars.network"]) {
const brand = getBrand(host)
assert.match(brand.logoIcon, new RegExp(`/logo/${brand.key}-icon\\.svg$`))
assert.match(brand.logoWhite, new RegExp(`/logo/${brand.key}-logo-white\\.svg$`))
assert.equal(brand.favicon, brand.logoIcon)
assert.ok(!seen.has(brand.name), `duplicate brand name ${brand.name}`)
seen.add(brand.name)
}
assert.equal(seen.size, 5)
})
it("flags exactly the marks that cannot paint themselves", () => {
// Measured from public/logo/*-icon.svg: bootnode is fill="currentColor"
// and lux is fill="white" — both need the current-text-colour mask, or one
// is invisible on black and the other on white. The rest ship a palette.
assert.equal(getBrand("bootno.de").monoMark, true)
assert.equal(getBrand("lux.cloud").monoMark, true)
assert.equal(getBrand("zoo.cloud").monoMark, false)
assert.equal(getBrand("web3.hanzo.ai").monoMark, false)
assert.equal(getBrand("cloud.pars.network").monoMark, false)
})
it("carries a complete, non-empty config for every brand", () => {
for (const host of ["bootno.de", "web3.hanzo.ai", "lux.cloud", "zoo.cloud", "cloud.pars.network"]) {
const b = getBrand(host)
for (const field of ["name", "shortName", "tagline", "domain", "apiUrl", "statusUrl", "networkName"] as const) {
assert.ok(b[field], `${host}: ${field} is empty`)
}
// Partial catalog entries used to produce `undefined` colours and crash
// rendering, which is why no catalog was ever shipped.
assert.ok(b.colors.accent && b.colors.accentEnd)
assert.ok(b.iam.idLabel)
assert.match(b.apiUrl, /^https:\/\//)
}
})
})