Commit Graph
69 Commits
Author SHA1 Message Date
zooqueenandHanzo Dev cf106de1da rip(casdoor): name the identity provider Hanzo IAM, and drop the dead manifest
main still called the provider Casdoor in ten places. hanzo.id is served by
github.com/hanzoai/iam, which its own LICENSE states is a clean-room
implementation carrying no third-party licensed source. The Casdoor-derived
server was hanzoai/iam-v1, retired and no part of this stack.

Every fact the text carried is kept. IAM really does stamp iss claims that
openid-client rejects, which is why the NextAuth provider is type: "oauth" and
why setting `issuer` breaks it; the applications really do live in the
iam-init-data configmap. Only the vendor name changed.

iam.py claimed a "Casdoor-compatible" flow. It is a standard flow — RFC 6749 and
OIDC Core — which is what HIP-0111 requires; naming a vendor for a capability
that has an RFC is what the standard exists to stop.

infra/k8s/cloud-deployment.yaml is deleted rather than edited. Its env block
named casdoorEndpoint / casdoorOrganization / casdoorApplication, and nothing
reads them: hanzoai/cloud configures IAM through IAM_URL, IAM_MINT_CLIENT_ID and
CLOUD_IAM_ISSUER, and ships no conf/. Renaming them to IAM_* would have produced
config that looks live and still does nothing. The file is unreferenced by
kustomization.yaml, duplicates declared state that belongs in universe
(infra/k8s/cloud/), pins registry.digitalocean.com instead of ghcr.io/hanzoai,
and pins a floating :latest tag that must never reach a cluster.

Landed directly on main via an isolated worktree. chore/use-datastore-fork is
139/137 divergent from a history rewrite; merging it would re-import that
lineage, and only two commit subjects there are genuinely absent from main.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:46:13 -07:00
zeekayandHanzo Dev 135a4ede57 chore(fleet): pin lux-fleet to the built Go image
ghcr.io/hanzoai/bootnode:fleet-7016d84, digest
sha256:15340b1b3584d91faed510972768ae6e318e8637afa99f069f36a25074f15703,
built on the in-cluster buildkit pool from Dockerfile.fleet. This is the image
serving api.cloud.lux.network/v1/fleets/lux/overview; the file had been left
pointing at the pre-transport-fix tag.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:46:13 -07:00
zeekayandHanzo Dev bdae39dd94 chore(fleet): drop the cross-cluster reader identity
The collector runs inside lux-k8s now and reads pods with its own in-cluster
ServiceAccount, so the ServiceAccount + ClusterRole + three RoleBindings this
file created for an out-of-cluster observer have no consumer. Applying it again
would only mint another long-lived cluster-read token nobody uses.

Revoked on the cluster too: the lux-k8s RBAC is deleted and the kubeconfig
Secret on bootnode-k8s is gone — the token it held now gets 401.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:44:58 -07:00
zeekayandHanzo Dev 613ca999c0 fix(fleet): serve HTTP, not ZAP
zip.Listen picks its transport from the address scheme, and a bare ":8000"
means ZAP. The dashboard and the kubelet both speak HTTP, so the readiness
probe's "GET " arrived as a ZAP frame header — frame size 1195725856, which is
the ASCII — and the pod never went Ready. The address now carries its scheme.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:36:37 -07:00
zeekayandHanzo Dev 734997e46c feat(fleet): the Lux fleet API is Go, and it runs where the fleet is
The lux.cloud dashboard was blank because the collector could not reach a
single validator. Two independent breaks, either one fatal:

  1. It called /ext. luxd 1.36 serves /v1 only — /ext/info is 404 — and the
     collector's _rpc() maps any non-200 to None, so every field came back
     null with no error anywhere.
  2. It dialled 15 hardcoded public LoadBalancer IPs. There are now zero
     LoadBalancer Services in lux-mainnet/testnet/devnet; those IPs do not
     answer at all (connect timeout, not 404).

Both are the same root defect: the observer was outside the thing it observes
and had to be told where to look. So the observer moves in. Running in lux-k8s,
a validator's address is its pod IP, read from the pod list on every
collection — there is nothing left to configure and nothing left to go stale.
Chain facts come from the node itself over /v1: info.getNodeVersion,
getNodeID, getNodeIP, peers, isBootstrapped per chain, eth_blockNumber at
/v1/bc/C/rpc (the bc/ segment is load-bearing; /v1/C/rpc is not a route) and
platform.getHeight at /v1/bc/P, which quotes its integer.

That also collapses the MODE A / MODE B split: there is one path, not two.

Two corrections to what the old collector reported:

  version is now what the fleet RUNS, not what the CR declares. The mainnet
  LuxNetwork CR asks for ghcr.io/luxfi/node:v1.34.0, a tag that does not
  exist; the nodes are on luxd/1.36.2. The dashboard must show the running
  truth, so observation wins and image keeps the declared value.

  external_ip becomes ip, matching console/lib/fleet.ts, and carries the
  address the node advertises for itself (info.getNodeIP) rather than an
  address someone wrote down.

Degraded is reported as degraded. A node that does not answer keeps every
field null and counts against nodes_rpc_ok; it is never smoothed over.

Placement: this stays in hanzoai/bootnode rather than folding into
hanzoai/cloud. cloud is not deployed on lux-k8s, and standing the whole
monolith up inside the chain cluster to run a read-only collector is a far
larger change than the collector itself. The surface is registered with zip's
Group; the route set is unchanged.

Deploy: Deployment/Service/RBAC in lux-k8s (lux-fleet.yaml, read-only —
list/get on pods and luxnetworks, no pods/proxy, no exec). The public URL
resolves to bootnode-k8s, so that cluster forwards just /v1/fleets/lux across
(lux-fleet-bridge.yaml); no other path on the host is touched.

Tests: a luxd stub that 404s anything outside /v1 and quotes platform height;
assertions that every probe path is under /v1, that no wire key is ever
omitted (an absent key reads as undefined and blanks a cell), that a down node
stays null, and that /v1/fleets/lux/zzzz is 404 next to a 200 on /overview.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:31:06 -07:00
zeekayandHanzo Dev 55aadd328c chore(lux): pin lux-fleet to the image that carries the /v1 collector
The floating :api tag made the running code unknowable from the manifest.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:28:38 -07:00
zeekayandHanzo Dev 1f30a4c21c fix(lux): the fleet is observed through lux-k8s, on /v1
luxd serves /v1 only — server/http/server.go pins baseURL="/v1" — so every
/ext call in this repo was a silent no-op. The fleet collector's _rpc()
returns None on non-200, so the lux.cloud dashboard rendered nodes_rpc_ok:0,
version:null and every node rpc_reachable:false while the fleet was in fact
running luxd/1.36.2 (mainnet), 1.36.24 (testnet), 1.36.25 (devnet).

Fixing the path alone would not have helped: the collector addressed each
validator by a hardcoded public LoadBalancer IP, and there are now zero
LoadBalancer Services in lux-mainnet/testnet/devnet. Those IPs time out. So
node addressing is no longer configured — it is derived from the cluster on
every collection, and the one way to reach a validator is the lux-k8s API
server's pod proxy, since luxd RPC is cluster-internal.

That collapses the old MODE A / MODE B split into a single path: read the CR
for the declared shape, the pods for phase/readiness/IP, then each pod's
JSON-RPC through the proxy. One credential authenticates both. Deleting the
endpoint ConfigMap and its 15 baked-in IPs removes the failure mode where
infrastructure moves and a dashboard quietly reports zeros.

Probes move to /v1/health/liveness, not /v1/health: a degraded-but-running
validator answers /v1/health with 503, so probing it would restart nodes that
are merely behind. Any fleet from charts/lux could never have gone Ready.

LuxNode.external_ip becomes .ip — with no public per-pod endpoint, the honest
value is the pod IP.

Avalanche endpoints keep /ext; that is their API, not ours.

Measured, with controls: pod-proxy POST /v1/info -> 200 on all 15 pods;
/ext/health -> 404; /zzz/health -> 404; nonexistent pod -> 404. A test asserts
every probe path is under /v1 and fails if /ext returns.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:18:04 -07:00
zeekayandHanzo Dev 7d293212cb refactor: web/ is now console/ — bootnode/bootnode is the backend, bootnode/console the frontend
Names the two halves for what they are. The repo already holds both (12407e9 merged
bootnode/bootnode into this history); this makes the frontend directory say so, so the layout
reads the way the owner describes the system: backend and frontend separate, one repo.

git mv throughout — 187 renames, history preserved. Every path reference follows: hanzo.yml
build context and dockerfile, compose.yml, compose.prod.yml, start.sh, LLM.md,
infra/k8s/web-deployments.yaml, infra/cloud/deploy.sh, and the Dockerfile's own COPY paths.
Image and container names (bootnode-web, the -web tag suffix) are deliberately NOT renamed here:
those are a deploy contract the App CR and ingress bind to on port 3001, and breaking them is a
separate, staged change.

Console builds green after the move; the Go tree builds.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 17:47:51 -07:00
zeekay 8f353bf348 one console shell, one image, brand from the Host header
The shell and design system half of the console merge. lux.cloud's look and
feel comes across as tokens and shell geometry, so all 67 existing routes
inherit it without one page being edited, and the per-deployment brand is
replaced by a hostname resolve.

DESIGN SYSTEM — lux.cloud's palette becomes the token layer
  app/globals.css now states lux.cloud's scheme in the variables Tailwind
  already reads: #000 ground, #f5f5f5 ink, 55% muted, 8% hairline / 18% strong
  border, #1a1a1a active fill, its status greens/ambers/reds, 10px/16px radii,
  clamp() display type, -0.01em tracking. Light is a faithful inversion, kept
  because the app ships a theme toggle. Because these are the same variables
  `bg-background` / `border-border` / `text-muted-foreground` always resolved
  to, every page changed appearance without changing.

  The shared primitives then say it in their own geometry: Card is lux's
  `.panel` (16px, hairline, no shadow — a shadow is invisible on black and
  grime on white), Table is `.vtable` (12px uppercase heads, border on the TOP
  of each row so the header needs no rule and the table ends flush), Badge is
  `.pill` with the status dot, Button and Input are `.btn` and `.stake-input`.

SHELL
  One header for marketing and console, as on lux.cloud — 57px, blurred, one
  hairline, brand lockup with the retracting wordmark, actions hard right,
  collapsing behind a single hamburger below `lg` into an OPAQUE sheet (a
  nested backdrop-filter re-roots the backdrop, the bug lux.cloud documents).
  ConsoleLayout adds the one thing the console needs: a 236px sticky rail that
  becomes a horizontally-scrolling strip on a phone — 7% of a 390x844 screen
  measured, against the 27% a wrapped grid of pills costs.

  Deleted: unified-navigation.tsx, a second console-only top bar with its own
  logo, an org switcher whose options changed nothing, and a bell wired to no
  notification source. The hard-coded `pl-64 pt-16` offsets are now the
  --header-h / --sidebar-w tokens, so the header and rail cannot disagree.

  Loading, empty and error are three components in one file instead of nine
  hand-rolled spinners at four sizes, and the callback page's `bg-green-100` /
  `text-red-600` — the only two colours in the app that ignored the tokens and
  so stayed light-mode on a black page — are gone.

WHITE-LABEL BY HOSTNAME — one image, five hosts
  lib/brand.ts resolves brand, theme, API origin, IAM issuer and OIDC client
  from window.location.hostname. Every triple was verified against the live
  /v1/iam/oauth/authorize (302 = registered, 400 = not):

    id.bootno.de  bootnode-platform  bootno.de/auth/callback           302
    hanzo.id      hanzo-web3         web3.hanzo.ai/auth/callback       302
    lux.id        lux-cloud          lux.cloud/auth/callback           302
    zoolabs.id    zoo-cloud          zoo.cloud/auth/callback           302
    zoolabs.id    zoo-cloud          cloud.zoo.network/auth/callback   302
    zoolabs.id    zoo-web3           cloud.zoo.network/auth/callback   400  ← was shipping

  Deleted, because all three were the same defect — a value picked at deploy
  time while ONE deployment serves five hosts:
    • public/config.json + config.example.json (the shipped catalog had the
      400 client above, and named apiUrls whose hosts do not resolve)
    • the Dockerfile's NEXT_PUBLIC_BRAND / _API_URL / _WS_URL, which were also
      inert — the runtime is the Go static binary, which never reads env
    • four near-identical Deployments differing only in those variables, now
      one, with the nine ingress rules pointing at the single service
    • NEXT_PUBLIC_AUTH_MODE and four NEXT_PUBLIC_* docs URLs

  Matching is exact-or-dot-suffix, never substring: `includes("lux.cloud")`
  hands lux.cloud's OIDC client to lux.cloud.attacker.example.

  Each brand also gets its own mark. public/logo/{brand}-icon.svg existed for
  all five and nothing used them — every brand pointed at one shared
  /logo.svg. bootnode's is fill="currentColor" and lux's is fill="white",
  which as an <img> (an isolated document) render invisible on black and on
  white respectively, so those two are painted in the current text colour via
  a CSS mask — which is what lux.cloud does with its own pyramid.

FIXED ALONG THE WAY
  • AuthProvider's local getApiUrl() shadowed the import at the top of the
    file and its last line called itself — infinite recursion on localhost,
    127.0.0.1, 192.168.* and 10.*. Every checkAuth/login/register in local
    development overflowed the stack. Deleted; lib/api's resolver is the one.
  • The console nav could not reach eight of its own pages —
    /dashboard/settings, assets/{tokens,nfts}, infrastructure/{lux,services,
    observability}, /chains, /agents rendered and were linked from nowhere.
  • No row was ever marked current: the image serves clean URLs as directory
    indexes, so the pathname is `/dashboard/` and an equality test never
    matched. Nested routes also lit two rows at once. Both are one selection
    rule now — longest matching href wins.
  • Two dead links in the chrome: /products (a directory of pages with no
    index — the static server answers it with the home page) and
    /docs/tutorials (a plain 404).

TESTS — 26, node:test with native TS stripping, no new dependency
  The five-host contract including the substring-matching attack; the nav
  reaching every built route; the trailing-slash and most-specific-row rules;
  and a whole-source dead-link check that derives routes by walking app/ so it
  cannot go stale. That check holds the shell at ZERO dead links and ratchets
  the 36 that predate this work in the docs and product pages — a test that
  fails on the day it is written gets deleted, one that stops the bleeding
  gets kept.

VERIFIED
  pnpm build exit 0, 77/77 pages, route set byte-identical to the baseline
  taken before any change. In a real browser against the built static export:
  body #000 / #f5f5f5, --border rgba(255,255,255,.08), header 57px sticky
  blur(24px), sidebar 236px sticky at top:57px, exactly one active row with
  #1a1a1a fill and aria-current, the phone strip 7% of the viewport scrolling
  inside itself with the body never scrolling sideways, the sheet opaque with
  no nested backdrop-filter, and the favicon, mark and "Sign in with Bootnode
  ID" all coming from the resolved brand.

Not deployed. No page bodies touched.
2026-07-26 15:32:42 -07:00
zeekay 39cb316a15 merge bootnode/bootnode into this history — one repo, both halves
github.com/bootnode/bootnode is the canonical home. These two diverged from
766da81c with real work on BOTH sides — 21 commits there, 26 here — so this is
a merge, not a fork-kill. Deleting either side would have destroyed shipped
work.

From CANONICAL (bootnode/bootnode):
  · Base/SQLite storage, Postgres coupling dropped (5650324)
  · Cluster + Node models — models this side never defined
  · native CI: hanzo.yml, zero .github/workflows (a698acc, aff0952)
  · images to ghcr.io/bootnode/bootnode, its own org (9d0957c)
  · luxd fleet dashboard, k8s validator detector

From HERE (hanzoai/bootnode):
  · HIP-0111 IAM: SPA PKCE, JWKS token validation (ed27226),
    JWT audience enforcement (49eb8cb) — security features canonical lacks
  · runtime white-label brand catalog (422f8f1 + today's work)
  · static-export build (852bb7c)
  · today: toolchain pinned, static export via hanzoai/static, one API
    resolver, honest error states

Seven conflicts, each resolved on evidence, not preference:

  web/lib/brand.ts        OURS   — canonical still hardcodes
                                   bootnode → iam.url "https://hanzo.id",
                                   which is the "Sign in to Hanzo ID" leak
                                   fixed today. It also carries a duplicate
                                   `skillsOrg` field.
  web/Dockerfile          OURS   — canonical runs `pnpm config set
                                   dangerously-allow-all-builds true` AND
                                   `--no-frozen-lockfile`: disables the
                                   supply-chain guard and ignores the lockfile.
  db/models.py            THEIRS — has Cluster + Node and no Postgres dialect.
  db/__init__.py          THEIRS — matches those models.
  .github/workflows/*     DELETED— canonical already went native.
  api/bootnode/main.py    BOTH   — took `__version__` from canonical (better
                                   than the hardcoded "2.0.0" here) and kept
                                   the conditional `docs` from b06f09f
                                   (canonical re-adds "docs": "/docs", a URL
                                   production disables, so it 404s).

This drops a386c9b, the Node/MPCWalletModel commit written earlier today. Its
problem did not exist on the canonical side: those models are already there,
and there is no MPC router to need MPCWalletModel. It was written against the
storage layer canonical replaced in June.

Verified on the merged tree, not assumed: `import bootnode.db` succeeds and
exports 14 models, all 27 API routers import, 0 postgresql dialect imports
remain, web tsc reports 0 errors and the production build exits 0 with
localhost:8000 in 0 chunks.
2026-07-26 14:18:12 -07:00
zeekay d5fbe67fad feat(lux): graphical fleet dashboard at lux.cloud
Turn lux.cloud into a live graphical fleet dashboard for the managed luxd
fleet (devnet/testnet/mainnet, 5 validators each on do-sfo3-lux-k8s).

Backend (read-only collector, no mutations, no monolith dependency):
- core/chains/lux_fleet.py: reads the operator LuxNetwork CR (lux.cloud/v1)
  for validators/version/plugin-set/phase, lists luxd-N pods + per-pod LB
  Services, and queries luxd JSON-RPC per node (info.getNodeVersion/getNodeID/
  peers/isBootstrapped, C-Chain eth_blockNumber, P-Chain platform.getHeight),
  plus a native D-Chain DEX summary. Aggregates all 3 nets concurrently.
- fleet_app.py: minimal standalone FastAPI exposing GET /v1/fleets/lux/overview
  (public, read-only). Reuses the bootnode api image; isolated from the
  (currently import-broken) monolith.
- fleets/__init__.py: same overview endpoint also mounted on the main router.
- Uses a READ-ONLY lux-k8s kubeconfig from KMS; only public chain data leaves.

Frontend (Next.js 16, Lux white-label, auto by hostname):
- lib/fleet.ts: typed client + health/status derivations.
- components/lux/fleet-dashboard.tsx: graphical multi-net dashboard — totals,
  world topology map, per-network cards (phase, version, plugin-set, peers,
  C-Chain height, DEX state, per-chain C/P/X/D bootstrap), expandable per-node
  tables (node ID, version, peers, heights). Auto-refresh 15s.
- app/fleet/page.tsx: public /fleet page (the lux.cloud fleet dashboard).
- components/lux/fleet-strip.tsx + page.tsx: live fleet status strip on the
  landing hero.
- navbar + dashboard nav: Fleet links; register existing Lux fleet mgmt page.
- brand.ts: add skillsOrg (fixes pre-existing typecheck/build break).

Deploy: infra/k8s/lux-fleet.yaml — lux-fleet Deployment/Service + ExternalSecret
(lux-k8s RO kubeconfig from KMS) + ingress path /v1/fleets/lux/overview on
api.cloud.lux.network.

Verified: collector live against all 3 nets (real heights/peers/versions/DEX);
api + collector tests pass (8/8); web typecheck + production build green;
/fleet renders live data in browser (screenshot).
2026-07-25 12:35:14 -07:00
zeekayandHanzo Dev 2307ce8f48 chore(kms): retire Node hanzoai/kms → luxfi/kms:1.11.9 in local-dev compose
Swap the local-dev KMS onto Go/ZAP luxfi/kms (embedded ZapDB): ZAP_PORT=0
(secrets-only — v1.11.x gates the consensus authorizer behind ZAP, so no
consensus/luxd needed locally), fixed dev KMS_MASTER_KEY_B64 /
KMS_ENCRYPTION_KEY_B64, /healthz healthcheck, kms_data volume. Drops the
Node env (DB_CONNECTION_URI/ENCRYPTION_KEY/AUTH_SECRET/SITE_URL) and the
Postgres/Redis deps only the Node kms used (both DBs kept for other services).
Live prod (luxfi/kms:1.11.9) untouched.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-19 00:49:24 -07:00
zeekay 9d0957c774 ci: bootnode images go to ghcr.io/bootnode/bootnode (own org, not hanzoai)
bootnode is its own GitHub org — its images belong in its own GHCR namespace,
per the never-mix-registries rule. This also removes cross-org friction: the
repo's own GITHUB_TOKEN pushes to ghcr.io/bootnode/* (same org), so once the
arcd App is on the bootnode org, build+push needs no cross-org token.
2026-06-19 21:14:50 +00:00
zeekay 766da81cc6 Merge remote-tracking branch 'origin/main' into consolidate-bootnode 2026-06-16 18:40:23 -07:00
zeekay ef2c77299e ingress: drop dead traefik.* annotations (hanzoai/ingress parses ingress.kubernetes.io/* only; these were inert router.tls/entrypoints/v1-redirect syntax) 2026-06-15 11:33:02 -07:00
zeekay b52fa408a8 infra: delete dead DO App Platform manifests
Per universe-wide policy, hanzo workloads ship on DOKS only. DO App Platform
was decommissioned February 2026 — all hanzo-apps/hanzo-platform/operator
specs here have been superseded by infra/k8s/. Removing the stale specs to
keep the only-one-way invariant.
2026-06-07 12:41:37 -07:00
zeekay 0687420325 deploy: pin :latest → semver across image refs
Replaces all ghcr.io/hanzoai/<svc>:latest pins with the latest published
semver tag for each service. Per CLAUDE.md auto-bump policy: mutable
branch tags (:latest, :main, :dev) are deprecated for cluster pins —
only immutable semver permitted.

Bulk update across services with published v* tags. Services without a
published semver remain on :latest until their release pipeline cuts a
v* tag.
2026-05-07 08:34:59 -07:00
zeekay 6c1878d606 deploy: pin :latest → semver across image refs
Replaces all ghcr.io/hanzoai/<svc>:latest pins with the latest published
semver tag for each service. Per CLAUDE.md auto-bump policy: mutable
branch tags (:latest, :main, :dev) are deprecated for cluster pins —
only immutable semver permitted.

Bulk update across services with published v* tags. Services without a
published semver remain on :latest until their release pipeline cuts a
v* tag.
2026-05-07 08:34:59 -07:00
zeekay 6c071fe9c8 ci: retrigger docker-release after bootstrapping bootnode-web GHCR package 2026-04-29 15:57:46 -07:00
zeekay 286a92b575 ci: retrigger docker-release after bootstrapping bootnode-web GHCR package 2026-04-29 15:57:46 -07:00
zeekay d1757172a2 feat(brand): route zoo.cloud through bootnode-web-zoo
- web/lib/brand.ts: detect zoo.cloud as zoo brand (alongside zoo.ngo, zoo.network)
- infra/k8s/ingress.yaml: add zoo.cloud + www.zoo.cloud as additional hosts on
  bootnode-zoo-ingress (TLS SAN via cert-manager, rules → bootnode-web-zoo:3001)

Makes zoo.cloud serve the same Bootnode platform as web3.zoo.ngo with Zoo brand.
2026-04-29 15:37:15 -07:00
zeekay a15dc95b71 feat(brand): route zoo.cloud through bootnode-web-zoo
- web/lib/brand.ts: detect zoo.cloud as zoo brand (alongside zoo.ngo, zoo.network)
- infra/k8s/ingress.yaml: add zoo.cloud + www.zoo.cloud as additional hosts on
  bootnode-zoo-ingress (TLS SAN via cert-manager, rules → bootnode-web-zoo:3001)

Makes zoo.cloud serve the same Bootnode platform as web3.zoo.ngo with Zoo brand.
2026-04-29 15:37:15 -07:00
zeekay ad970becd1 infra: replace all nginx references with hanzo ingress
Migrate every ingress resource from nginx annotations to
traefik.ingress.kubernetes.io for hanzoai/ingress controller.
Update network policies to match hanzo-ingress pod selector.
Update operator config to use className: hanzo.
2026-03-25 12:11:56 -07:00
zeekay 5ee151b452 infra: replace all nginx references with hanzo ingress
Migrate every ingress resource from nginx annotations to
traefik.ingress.kubernetes.io for hanzoai/ingress controller.
Update network policies to match hanzo-ingress pod selector.
Update operator config to use className: hanzo.
2026-03-25 12:11:56 -07:00
zeekay 1e422e81f1 rebrand: purge PostHog references 2026-03-13 17:46:50 -07:00
zeekay b56ff80d88 rebrand: purge PostHog references 2026-03-13 17:46:50 -07:00
zeekay f62ba98e30 fix: add /api/health endpoint, fix web pod probes and resources
- Add lightweight /api/health Next.js route for K8s probes
- Increase readiness probe: initialDelaySeconds 5→15, timeout 5s, failureThreshold 5
- Increase liveness probe: initialDelaySeconds 10→30, periodSeconds 15
- Bump memory limit 512Mi→1Gi for Next.js SSR cold start
- Bump CPU request 100m→200m, limit 500m→1000m
2026-03-12 17:02:54 -07:00
zeekay f234c74eb3 fix: add /api/health endpoint, fix web pod probes and resources
- Add lightweight /api/health Next.js route for K8s probes
- Increase readiness probe: initialDelaySeconds 5→15, timeout 5s, failureThreshold 5
- Increase liveness probe: initialDelaySeconds 10→30, periodSeconds 15
- Bump memory limit 512Mi→1Gi for Next.js SSR cold start
- Bump CPU request 100m→200m, limit 500m→1000m
2026-03-12 17:02:54 -07:00
zeekay 89933bfc5a feat: hanzo.ai-style mega-menu navbar with Products/Solutions dropdowns
Replace NavigationMenu with custom NavMenu hover dropdowns:
- Products: 3 featured hero cards (Node/Explorer/MPC) + 5-column category grid + SDK footer
- Solutions: Enterprise/Startup panels + Use Cases/By Role/By Chain columns
- Hover-to-open on desktop (150ms close delay), click on mobile
- Full-viewport-width backdrop-blur dropdowns matching hanzo.ai pattern

Also fix API deployment: increase probe timeouts, add ENVIRONMENT=staging
2026-03-12 16:11:50 -07:00
zeekay 62c0be939a feat: hanzo.ai-style mega-menu navbar with Products/Solutions dropdowns
Replace NavigationMenu with custom NavMenu hover dropdowns:
- Products: 3 featured hero cards (Node/Explorer/MPC) + 5-column category grid + SDK footer
- Solutions: Enterprise/Startup panels + Use Cases/By Role/By Chain columns
- Hover-to-open on desktop (150ms close delay), click on mobile
- Full-viewport-width backdrop-blur dropdowns matching hanzo.ai pattern

Also fix API deployment: increase probe timeouts, add ENVIRONMENT=staging
2026-03-12 16:11:50 -07:00
zeekay b65fb6b77c feat: add Explorer + MPC product pages, fleet management, operator, Helm charts, and CI/CD
- Add Explorer product page with branded block explorer deployment, contract
  verification, Etherscan-compatible API, and multi-chain support
- Add MPC product page with deep Lux MPC integration: CGGMP21 (ECDSA),
  FROST (EdDSA), LSS resharing, 15+ chain support, threshold signing API
- Update landing page with 6-product grid (Node, Data, Wallets, Explorer,
  MPC, Rollups) and 8 API cards including Explorer API and MPC Signing
- Update navbar and command menu with Explorer and MPC products
- Add Lux fleet management dashboard, observability, and services pages
- Add AI chat component and unified navigation with org switcher
- Add Kubernetes operator (Rust) for multi-chain node lifecycle management
- Add Lux Helm charts with genesis configs for devnet/testnet/mainnet
- Add docker-release.yml CI/CD pipeline for automated DOKS deployment
- Add monitoring, network policies, web deployments, and ingress updates
- Refactor API: fleet management, billing tracker, observability endpoints
- Update brand config, API client, and infrastructure manifests
2026-03-12 14:48:40 -07:00
zeekay 0aa9c4e346 feat: add Explorer + MPC product pages, fleet management, operator, Helm charts, and CI/CD
- Add Explorer product page with branded block explorer deployment, contract
  verification, Etherscan-compatible API, and multi-chain support
- Add MPC product page with deep Lux MPC integration: CGGMP21 (ECDSA),
  FROST (EdDSA), LSS resharing, 15+ chain support, threshold signing API
- Update landing page with 6-product grid (Node, Data, Wallets, Explorer,
  MPC, Rollups) and 8 API cards including Explorer API and MPC Signing
- Update navbar and command menu with Explorer and MPC products
- Add Lux fleet management dashboard, observability, and services pages
- Add AI chat component and unified navigation with org switcher
- Add Kubernetes operator (Rust) for multi-chain node lifecycle management
- Add Lux Helm charts with genesis configs for devnet/testnet/mainnet
- Add docker-release.yml CI/CD pipeline for automated DOKS deployment
- Add monitoring, network policies, web deployments, and ingress updates
- Refactor API: fleet management, billing tracker, observability endpoints
- Update brand config, API client, and infrastructure manifests
2026-03-12 14:48:40 -07:00
zeekay 4db33d9114 feat: add Graph Node + IPFS + subgraph infrastructure
- Add graph-node, graph-ipfs, graph-postgres to compose.yml (subgraph profile)
- Add k8s manifests for Graph Node stack (lux/graph-node.yaml)
- Add deploy-subgraph.sh for AMM V3/V2 subgraph deployment
- Update deploy.sh with 'graph' target for Graph Node infrastructure
- Matches existing lux-k8s lux-explorer namespace setup
2026-03-07 00:03:44 -08:00
zeekay 97c8a5842d feat: add Graph Node + IPFS + subgraph infrastructure
- Add graph-node, graph-ipfs, graph-postgres to compose.yml (subgraph profile)
- Add k8s manifests for Graph Node stack (lux/graph-node.yaml)
- Add deploy-subgraph.sh for AMM V3/V2 subgraph deployment
- Update deploy.sh with 'graph' target for Graph Node infrastructure
- Matches existing lux-k8s lux-explorer namespace setup
2026-03-07 00:03:44 -08:00
zeekay 63b0aaf38e fix: CI uses --extra dev to avoid hanzo-kms dep + add hanzo-ns k8s manifests
CI was failing because `uv sync` installs all extras including hanzo-kms
which isn't on PyPI. Switch to `uv sync --extra dev` for test jobs.

Add bootnode API deployment manifest for the hanzo namespace (separate
from the bootnode namespace deployment).
2026-02-13 16:44:05 -08:00
zeekay d66df4ae64 fix: CI uses --extra dev to avoid hanzo-kms dep + add hanzo-ns k8s manifests
CI was failing because `uv sync` installs all extras including hanzo-kms
which isn't on PyPI. Switch to `uv sync --extra dev` for test jobs.

Add bootnode API deployment manifest for the hanzo namespace (separate
from the bootnode namespace deployment).
2026-02-13 16:44:05 -08:00
zeekay 91b1be8ca3 fix: add Commerce billing to K8s deploy + create init.sql
- Add Commerce secretKeyRef (api-key, webhook-secret) to K8s api-deployment
- Create infra/sql/init.sql (uuid-ossp, pgcrypto extensions for PostgreSQL)
- Remove deprecated version: from docker-compose.prod.yml
2026-02-12 20:30:37 -08:00
zeekay 9e215ed3e9 fix: add Commerce billing to K8s deploy + create init.sql
- Add Commerce secretKeyRef (api-key, webhook-secret) to K8s api-deployment
- Create infra/sql/init.sql (uuid-ossp, pgcrypto extensions for PostgreSQL)
- Remove deprecated version: from docker-compose.prod.yml
2026-02-12 20:30:37 -08:00
zeekay cd1f006c47 fix: enforce Hanzo KMS for all secrets, remove plaintext credentials
- Remove hardcoded Secret from bootnode-deployment.yaml (conflicted with ExternalSecret)
- Fix Postgres/Redis pods to read passwords from KMS-managed bootnode-secrets
- Expand ExternalSecret from 7 to 30 secrets with UPPERCASE_UNDERSCORE keys matching Pydantic
- Enable hanzo-kms SDK as optional dependency for direct KMS access outside K8s
- Improve inject_secrets() startup logging to indicate active secrets path
- Rewrite secrets.yaml as documentation-only with flow diagram and setup guide
- Fix compose.yml Bitcoin healthcheck to use env vars instead of hardcoded password
2026-02-12 13:05:04 -08:00
zeekay 3fe4d9fa43 fix: enforce Hanzo KMS for all secrets, remove plaintext credentials
- Remove hardcoded Secret from bootnode-deployment.yaml (conflicted with ExternalSecret)
- Fix Postgres/Redis pods to read passwords from KMS-managed bootnode-secrets
- Expand ExternalSecret from 7 to 30 secrets with UPPERCASE_UNDERSCORE keys matching Pydantic
- Enable hanzo-kms SDK as optional dependency for direct KMS access outside K8s
- Improve inject_secrets() startup logging to indicate active secrets path
- Rewrite secrets.yaml as documentation-only with flow diagram and setup guide
- Fix compose.yml Bitcoin healthcheck to use env vars instead of hardcoded password
2026-02-12 13:05:04 -08:00
zeekay 30ae134cf3 fix: production billing hardening + Stripe→Commerce migration
- Replace eval() with json.loads() in usage tracker (security fix)
- Webhook verification fails-closed in production when secret missing
- Add Commerce env vars to K8s deployment (URL, API key, webhook secret)
- Expose ZAP port 9999 in Dockerfile and K8s service
- Replace Stripe env vars with Square in compose.yml
- Update privacy/terms pages: Stripe→Square via Hanzo Commerce
- Add full billing API client module to web/lib/api.ts (17 endpoints)
- Fix hardcoded localhost URLs in dashboard/analytics/organization pages
- Add production webhook rejection test (57 tests passing)
2026-02-12 11:22:03 -08:00
zeekay 8edcaa614f fix: production billing hardening + Stripe→Commerce migration
- Replace eval() with json.loads() in usage tracker (security fix)
- Webhook verification fails-closed in production when secret missing
- Add Commerce env vars to K8s deployment (URL, API key, webhook secret)
- Expose ZAP port 9999 in Dockerfile and K8s service
- Replace Stripe env vars with Square in compose.yml
- Update privacy/terms pages: Stripe→Square via Hanzo Commerce
- Add full billing API client module to web/lib/api.ts (17 endpoints)
- Fix hardcoded localhost URLs in dashboard/analytics/organization pages
- Add production webhook rejection test (57 tests passing)
2026-02-12 11:22:03 -08:00
zeekay f219464d32 fix: resolve config mismatch + auth security hardening
P0: config.py defined hanzo_commerce_* but billing code accessed
settings.commerce_* — causes AttributeError at runtime. Renamed fields
with AliasChoices for backward compat with HANZO_COMMERCE_* env vars.

P1: deps.py silently swallowed JWT errors (bare pass) — now logs them.
Virtual API key used fake UUID for missing projects — now raises 404.
Updated secrets.yaml to replace stale Stripe references with Commerce.
2026-02-12 10:44:47 -08:00
zeekay 82c099d128 fix: resolve config mismatch + auth security hardening
P0: config.py defined hanzo_commerce_* but billing code accessed
settings.commerce_* — causes AttributeError at runtime. Renamed fields
with AliasChoices for backward compat with HANZO_COMMERCE_* env vars.

P1: deps.py silently swallowed JWT errors (bare pass) — now logs them.
Virtual API key used fake UUID for missing projects — now raises 404.
Updated secrets.yaml to replace stale Stripe references with Commerce.
2026-02-12 10:44:47 -08:00
zeekay 7acebc977d feat: integrate Commerce/Square billing (checkout, webhooks, unified API)
- Add checkout/capture endpoints via Commerce → Square payment flow
- Add order.completed/cancelled and payment.paid/failed/refunded webhook handlers
- Update Commerce API paths (/api/v1/customers → /api/v1/user, /subscribe, etc.)
- Migrate unified billing from Stripe references to Square (customer accounts)
- Add customer_id to usage sync worker for proper metered billing
- Export UnifiedBillingClient, UnifiedUser from billing module
- Add Commerce tier-to-plan slug mapping (bootnode-free/payg/growth/enterprise)
2026-02-12 10:20:42 -08:00
zeekay 249e2984cd feat: integrate Commerce/Square billing (checkout, webhooks, unified API)
- Add checkout/capture endpoints via Commerce → Square payment flow
- Add order.completed/cancelled and payment.paid/failed/refunded webhook handlers
- Update Commerce API paths (/api/v1/customers → /api/v1/user, /subscribe, etc.)
- Migrate unified billing from Stripe references to Square (customer accounts)
- Add customer_id to usage sync worker for proper metered billing
- Export UnifiedBillingClient, UnifiedUser from billing module
- Add Commerce tier-to-plan slug mapping (bootnode-free/payg/growth/enterprise)
2026-02-12 10:20:42 -08:00
zeekay 284eb6906c refactor: rename domain bootnode.dev → bootno.de
Update K8s manifests (Ingress hosts, CRD API groups, CORS origins),
ZAP schemas, pyproject.toml URLs, SDK docs import paths, e2e test
emails, and K8s annotations to use the canonical bootno.de domain.
2026-02-12 10:20:22 -08:00
zeekay f46dc90a83 refactor: rename domain bootnode.dev → bootno.de
Update K8s manifests (Ingress hosts, CRD API groups, CORS origins),
ZAP schemas, pyproject.toml URLs, SDK docs import paths, e2e test
emails, and K8s annotations to use the canonical bootno.de domain.
2026-02-12 10:20:22 -08:00
zeekay a6f444ff83 fix: hanzo-web3 uses universal web-latest image tag
Single universal image with runtime brand detection, not per-brand builds.
2026-02-10 09:01:43 -08:00
zeekay 20cb05fd51 fix: hanzo-web3 uses universal web-latest image tag
Single universal image with runtime brand detection, not per-brand builds.
2026-02-10 09:01:43 -08:00