Files
zeekayandHanzo Dev da042e74bf fix(zoo-exchange): point SPA_IAM_HOST at zoolabs.id — iam.zoo.network never existed
zoo.exchange/config.json shipped "iamHost":"https://iam.zoo.network" to every
browser. That host has no ingress, no Traefik router and no IAM_ISSUER_MAP
entry anywhere; its DNS A record pointed at the lux-k8s LB, which answered the
handshake with CN=INGRESS DEFAULT CERT. So every IAM call from the Zoo Exchange
SPA — mainnet and testnet — died before the first byte of HTTP. A client written
against a route that never existed.

zoolabs.id is Zoo's identity origin and already serves both halves: the login
SPA at / and the IAM API at /v1/iam, /oauth, /.well-known (routers
zoolabs-id + zoolabs-id-iam-api in the hanzoai/ingress file provider). Its
discovery doc reports issuer=https://zoolabs.id with a reachable 9-key JWKS, so
fetching discovery from that origin is self-consistent — which is what a strict
OIDC client checks. SPA_ID_HOST was already zoolabs.id.

There is no iam.<brand> host in the design. iam.hanzo.ai is the one legacy IAM
host, kept because the shared Google/GitHub OAuth clients register exactly one
callback against it; every brand otherwise reaches IAM through its own id
origin. iam.zoo.network / iam.pars.network are being retired to NXDOMAIN, and
the orphaned hanzo/iam-multi Ingress that claimed them is deleted.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 15:46:04 -07:00

70 lines
2.6 KiB
YAML

# exchange.zoo-test.network — Zoo testnet exchange (hanzoai/spa @zooai/exchange).
#
# Deployed into the existing `zoo` namespace (reuses ghcr-zoo pull secret and
# the KMS-synced zoo-exchange-secrets). Points at the LIVE zoo testnet C-Chain
# (chainId 200201 at api.zoo-test.network). Mirrors zoo-mainnet but with the
# testnet chain + RPC host.
apiVersion: apps/v1
kind: Deployment
metadata:
name: zoo-exchange-testnet
labels: { app: zoo-exchange-testnet, brand: zoo, env: testnet }
spec:
replicas: 2
selector:
matchLabels: { app: zoo-exchange-testnet }
strategy:
type: RollingUpdate
rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
template:
metadata:
labels: { app: zoo-exchange-testnet, brand: zoo, env: testnet }
spec:
imagePullSecrets:
- name: ghcr-zoo
- name: ghcr-secret
containers:
- name: spa
image: ghcr.io/zooai/exchange:latest
imagePullPolicy: Always
ports:
- { containerPort: 3000, name: http }
envFrom:
- secretRef: { name: zoo-exchange-secrets }
env:
- { name: PORT, value: "3000" }
- { name: ROOT, value: /public }
- { name: SPA_BRAND_NAME, value: "Zoo Exchange (Testnet)" }
- { name: SPA_DEFAULT_CHAIN, value: "200201" }
- { name: SPA_RPC_HOST, value: "https://api.zoo-test.network" }
- { name: SPA_API_HOST, value: "https://api.zoo-test.network" }
- { name: SPA_GATEWAY_HOST, value: "https://api.zoo-test.network" }
# zoolabs.id, not iam.zoo.network — see the zoo-mainnet overlay for why
# (iam.zoo.network never had a router; IAM calls died at the handshake).
- { name: SPA_IAM_HOST, value: "https://zoolabs.id" }
- { name: SPA_ID_HOST, value: "https://zoolabs.id" }
- { name: SPA_KMS_HOST, value: "https://kms.zoo.network" }
- { name: SPA_INSIGHTS_HOST, value: "https://insights.hanzo.ai" }
readinessProbe:
httpGet: { path: /health, port: http }
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet: { path: /health, port: http }
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests: { cpu: "50m", memory: "64Mi" }
limits: { cpu: "500m", memory: "256Mi" }
---
apiVersion: v1
kind: Service
metadata:
name: zoo-exchange-testnet
labels: { app: zoo-exchange-testnet, brand: zoo, env: testnet }
spec:
type: ClusterIP
selector: { app: zoo-exchange-testnet }
ports:
- { name: http, port: 3000, targetPort: http, protocol: TCP }