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.
NEXT_PUBLIC_BRAND gets baked at build time by Next.js, always resolving
to the Dockerfile default ("bootnode"). Use headers() + Host-based
detection in generateMetadata() so cloud.lux.network shows "Lux Cloud"
at request time, not "Bootnode".
Root cause: ghcr-secret was expired/missing, causing ImagePullBackOff
on all web portal pods. Now auto-refreshes using GITHUB_TOKEN on each
deploy. Also cleans up stale pending pods from previous failed rollouts.
Instead of storing DIGITALOCEAN_ACCESS_TOKEN and cluster names as
GitHub Secrets, authenticate to KMS at deploy time and fetch them
from /deploy path. Falls back to GitHub Secrets if KMS is unavailable.
Matches the pattern used by hanzo/app and other Hanzo services:
only KMS_CLIENT_ID + KMS_CLIENT_SECRET stored in GitHub.
The build-and-push and deploy jobs were duplicated in ci.yml with missing
REGISTRY env vars, causing Docker login failures. docker-release.yml is
the canonical deploy pipeline (triggers on CI workflow_run completion).
- 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
The K8s DATABASE_URL env var uses postgresql:// which makes
create_async_engine try to load psycopg2 (sync driver). Add
_ensure_async_dsn() to convert postgresql:// and postgres:// to
postgresql+asyncpg:// at engine creation time. asyncpg is already
in dependencies.
Add BOOTNODE_GHCR_PAT secret-based login to push API and web images
to the canonical ghcr.io/bootnode/bootnode registry in addition to
ghcr.io/hanzoai/bootnode. Also add provenance=false/sbom=false to web
build to avoid attestation timeouts on linux/amd64.
capnp.AsyncIoStream.create_server() must be called from within an active
KJ event loop context. Wrap the entire serve lifecycle in a background
asyncio Task that runs under `async with capnp.kj_loop()`, fixing the
startup error: "The KJ event-loop is not running on this thread".
The server now signals readiness via `_running=True` after bind and
the caller polls for up to 1 s before raising if startup fails.
uv sync resolves ALL extras including hanzo (which depends on
hanzo-kms, not published to PyPI) even with --no-extra flag.
Switch to uv pip install -e ".[dev]" which only resolves the
specified extras.
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).
- 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
- Create /dashboard/organization/billing page with plan comparison
- Wire up disabled "Manage Subscription" button to new billing page
- Fix analytics nav billing link to point to organization/billing
- Shows current plan, usage stats, and upgrade via Commerce checkout
- All 4 tiers displayed: Free, PAYG, Growth, Enterprise
All dashboard pages now use NEXT_PUBLIC_API_URL with localhost fallback
for local dev. Fixes tokens, volumes, storage, clusters, monitoring,
infrastructure, and usage pages for production deployment.
- 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)
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.
- Fix Lux brand IAM URL: lux.id → iam.lux.network (matches actual deployment)
- Use getBrand().iam.url for IAM URL in HanzoLoginButton (brand-aware auth)
- Fix missing newline at EOF in unified-navigation.tsx
- Update LLM.md with Commerce billing and IAM documentation
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.
- OAuth callback accepts redirect_uri from frontend to derive correct
IAM client_id per network (all use lux-web3 shared app)
- Token verification accepts tokens from any known IAM app audience
- Frontend sends redirect_uri in callback POST body
- Login page uses proper /login/oauth/authorize URL with client_id
- Brand configs unified to use lux-web3 IAM app for all networks
- Removed dead code (duplicate get_current_user, unreachable methods)
- IAM init data updated with cloud redirect URIs for pars/zoo/hanzo
The networks module imported get_current_user from bootnode.api.deps
where it doesn't exist — it's in bootnode.core.iam. This broke the
entire API startup (uvicorn can't import bootnode.main:app).