feat(zoo-exchange): KMS-backed secrets, drop init-container patch script
* Replaced init-container ConfigMap (sed URL rewrites + fetch interceptor + CSP injection) with clean SPA wiring — secrets come from KMSSecret CRD syncing /zoo path from hanzo-exchange KMS project to zoo-exchange-secrets in the cluster. * Image moves from ghcr.io/luxfi/exchange@sha256:9b97... (digest pin + nodeAffinity hack) to ghcr.io/zooai/exchange:latest with normal pull. * SPA_INSIGHTS_API_KEY arrives via envFrom: secretRef. SPA runtime templates /config.json from SPA_* env at pod start; brand singleton reads insightsApiKey at boot. * Removed wildcard *.api.zoo.exchange Ingress + cert (no more fake cloudflare-prefix subdomains — events go to insights.hanzo.ai directly).
This commit is contained in:
@@ -1,44 +1,40 @@
|
||||
---
|
||||
# zoo.exchange — hanzoai/spa runtime, no nginx, in `zoo` namespace.
|
||||
# Init container reuses the SPA bundle baked into the cached luxfi/exchange
|
||||
# image (digest pin so we don't need a fresh ghcr-luxfi PAT on disk; the
|
||||
# image is already on cluster nodes lux-nodes-vvfa0/kzit5/kzitk).
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
# zoo.exchange — hanzoai/spa serving the @luxfi/exchange SPA bundle.
|
||||
#
|
||||
# Secrets ALL come from Hanzo KMS via KMSSecret CRD.
|
||||
# DNS: zoo.exchange / www.zoo.exchange / exchange.zoo.network / trade.zoo.exchange →
|
||||
# lux-k8s LB 134.199.138.27 → ingress → this Service.
|
||||
# Per-org Insights API key lives at KMS path /zoo in the hanzo-exchange project.
|
||||
# Public chain RPC + bridge endpoints come from the SPA brand config (/config.json),
|
||||
# which is templated by the hanzoai/spa runtime from the SPA_* env vars below.
|
||||
apiVersion: kms.hanzo.ai/v1alpha1
|
||||
kind: KMSSecret
|
||||
metadata:
|
||||
name: zoo-exchange-patch
|
||||
name: zoo-exchange
|
||||
namespace: zoo
|
||||
data:
|
||||
patch.sh: |
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
SRC="${SRC:-/usr/share/nginx/html}"
|
||||
cp -a "$SRC"/. /public/
|
||||
INDEX=/public/index.html
|
||||
if [ -f "$INDEX" ]; then
|
||||
# Title — Zoo
|
||||
sed -i 's|<title>Lux Exchange</title>|<title>Zoo Exchange — Trade ZOO and every token on Zoo Network</title>|g' "$INDEX"
|
||||
sed -i 's|<title>Uniswap Interface</title>|<title>Zoo Exchange — Trade ZOO and every token on Zoo Network</title>|g' "$INDEX"
|
||||
# CSP — append Zoo + real gateway origins to connect-src
|
||||
sed -i 's|wss://nbstream.binance.com|https://*.gateway.uniswap.org wss://*.gateway.uniswap.org https://*.gateway.zoo.exchange wss://*.gateway.zoo.exchange https://api.statsig.com https://*.statsig.com https://api.zoo.network https://api.zoo-test.network https://api.zoo-dev.network https://kms.zoo.network https://iam.zoo.network https://zoolabs.id wss://*.zoo.network wss://*.zoo.exchange wss://nbstream.binance.com|g' "$INDEX"
|
||||
echo "[patch] index.html updated"
|
||||
fi
|
||||
# Rewrite bogus gateway.lux.org (fork placeholder, no matching
|
||||
# deployment) → real gateway.uniswap.org in every built asset. This
|
||||
# unblocks Statsig gating (gating.interface.gateway.lux.org) which
|
||||
# was 404ing and leaving the app in an infinite init loop → blank page.
|
||||
find /public -type f \( -name "*.js" -o -name "*.html" -o -name "*.css" -o -name "*.json" \) \
|
||||
-exec sed -i 's|gateway\.lux\.org|gateway.uniswap.org|g' {} + 2>/dev/null || true
|
||||
echo "[patch] gateway.lux.org → gateway.uniswap.org rewritten in assets"
|
||||
spec:
|
||||
authentication:
|
||||
universalAuth:
|
||||
credentialsRef:
|
||||
secretName: kms-zoo-exchange-credentials
|
||||
secretNamespace: zoo
|
||||
managedSecretReference:
|
||||
secretName: zoo-exchange-secrets
|
||||
secretNamespace: zoo
|
||||
secretType: Opaque
|
||||
resyncInterval: 60
|
||||
secretsScope:
|
||||
projectSlug: hanzo-exchange
|
||||
environmentSlug: prod
|
||||
secretsPath: /zoo
|
||||
recursive: false
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: zoo-exchange
|
||||
namespace: zoo
|
||||
labels:
|
||||
app: zoo-exchange
|
||||
brand: zoo
|
||||
labels: { app: zoo-exchange, brand: zoo }
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
@@ -48,60 +44,33 @@ spec:
|
||||
rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: zoo-exchange
|
||||
brand: zoo
|
||||
labels: { app: zoo-exchange, brand: zoo }
|
||||
spec:
|
||||
# Schedule onto a node that already has the luxfi/exchange image
|
||||
# cached — avoids the expired ghcr-luxfi PAT pull failure.
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/hostname
|
||||
operator: In
|
||||
values:
|
||||
- lux-nodes-vvfa0
|
||||
- lux-nodes-kzit5
|
||||
- lux-nodes-kzitk
|
||||
volumes:
|
||||
- name: spa
|
||||
emptyDir: {}
|
||||
- name: patch
|
||||
configMap:
|
||||
name: zoo-exchange-patch
|
||||
defaultMode: 0755
|
||||
initContainers:
|
||||
- name: extract
|
||||
image: ghcr.io/luxfi/exchange@sha256:9b9765e099d4fe4d377efe0e3e02c5f09d5628f644922eef3c6cc9ef5b57c6c5
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["/patch/patch.sh"]
|
||||
volumeMounts:
|
||||
- { name: spa, mountPath: /public }
|
||||
- { name: patch, mountPath: /patch }
|
||||
env:
|
||||
# The original image keeps the SPA bundle in /usr/share/nginx/html.
|
||||
- { name: SRC, value: /usr/share/nginx/html }
|
||||
imagePullSecrets:
|
||||
- name: ghcr-zoo
|
||||
containers:
|
||||
- name: spa
|
||||
image: ghcr.io/hanzoai/spa:1.2.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
image: ghcr.io/zooai/exchange:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- { containerPort: 3000, name: http }
|
||||
# Secrets sourced from KMS — single source of truth.
|
||||
envFrom:
|
||||
- secretRef: { name: zoo-exchange-secrets }
|
||||
# Public, non-secret runtime config templated into /config.json on pod start.
|
||||
env:
|
||||
- { name: PORT, value: "3000" }
|
||||
- { name: ROOT, value: /public }
|
||||
# Runtime /config.json — overrides per env via SPA_*
|
||||
- { name: SPA_BRAND_NAME, value: "Zoo Exchange" }
|
||||
- { name: SPA_DEFAULT_CHAIN, value: "200200" }
|
||||
- { name: SPA_RPC_HOST, value: "https://api.zoo.network" }
|
||||
- { name: SPA_IAM_HOST, value: "https://iam.zoo.network" }
|
||||
- { name: SPA_ID_HOST, value: "https://zoolabs.id" }
|
||||
- { name: SPA_KMS_HOST, value: "https://kms.zoo.network" }
|
||||
- { name: SPA_GATEWAY_HOST, value: "https://dex.lux.network" }
|
||||
volumeMounts:
|
||||
- { name: spa, mountPath: /public }
|
||||
- { name: PORT, value: "3000" }
|
||||
- { name: ROOT, value: /public }
|
||||
- { name: SPA_BRAND_NAME, value: "Zoo Exchange" }
|
||||
- { name: SPA_DEFAULT_CHAIN, value: "200200" }
|
||||
- { name: SPA_RPC_HOST, value: "https://api.zoo.network" }
|
||||
- { name: SPA_API_HOST, value: "https://api.zoo.exchange" }
|
||||
- { name: SPA_GATEWAY_HOST, value: "https://api.zoo.exchange" }
|
||||
- { name: SPA_IAM_HOST, value: "https://iam.zoo.network" }
|
||||
- { 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" }
|
||||
# SPA_INSIGHTS_API_KEY arrives via envFrom (zoo-exchange-secrets).
|
||||
readinessProbe:
|
||||
httpGet: { path: /health, port: http }
|
||||
initialDelaySeconds: 2
|
||||
@@ -136,11 +105,7 @@ metadata:
|
||||
spec:
|
||||
ingressClassName: ingress
|
||||
tls:
|
||||
- hosts:
|
||||
- zoo.exchange
|
||||
- www.zoo.exchange
|
||||
- exchange.zoo.network
|
||||
- trade.zoo.exchange
|
||||
- hosts: [zoo.exchange, www.zoo.exchange, exchange.zoo.network, trade.zoo.exchange]
|
||||
secretName: zoo-exchange-tls
|
||||
rules:
|
||||
- host: zoo.exchange
|
||||
|
||||
Reference in New Issue
Block a user