@mesh-tech/mesh-cli
Version:
CLI for Mesh platform development utilities
140 lines (136 loc) • 6.09 kB
YAML
# Local Hub overlay (`mesh start --with-hub`).
#
# Images are built from the published @mesh-tech/hub tarball on first use
# (see hub-local.ts) — the interim path until the hub pipeline publishes
# pullable images. Requires one-time registry access (mesh registry login);
# the core profile stays zero-access without this overlay.
#
# The Hub reads the SAME local fabric the apps use: SSM registry via
# ministack (x-local-aws-env in the base file), the seeded `hub` database,
# Temporal, SpiceDB — and the local observability backends (Loki logs,
# Tempo traces, Prometheus metrics via the base file's OTel collector), so
# the Hub's operational views run the exact hosted code paths. Only the
# K8s-API views (pod state/metrics) have no local backend.
#
# No HUB_TENANT here on purpose: a local platform is a STANDALONE hub, so
# hub-api resolves the single-tenant conventions ({tenant}-{env}-{app} for
# K8s + Temporal namespaces) that everything local creates — zero
# local-vs-hosted translation.
services:
hub-api:
image: mesh-local-hub-api:${MESH_HUB_VERSION:-latest}
ports:
# 4568 host-side: the 3000 range belongs to `mesh dev` app services
- '4568:3002'
environment:
AWS_ENDPOINT_URL: http://ministack:4566
AWS_REGION: us-east-2
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
PORT: 3002
PULUMI_STATE_BUCKET: mesh-local-artifacts
DATABASE_URL: postgres://postgres:postgres@database:5432/hub?sslmode=disable
OPS_DB_HOST: database
OPS_DB_PORT: 5432
OPS_DB_NAME: hub
OPS_DB_USER: postgres
DATABASE_PASSWORD: postgres
PGSSLMODE: disable
TEMPORAL_ADDRESS: temporal:7233
TEMPORAL_NAMESPACE: local-dev
TEMPORAL_UI_URL: http://localhost:8233
LOKI_URL: http://loki:3100
TEMPO_URL: http://tempo:3200
PROMETHEUS_URL: http://prometheus:9090
# The REAL issuer URL (what `mesh login local` tokens carry). Valid
# inside the container via the Dockerfile's loopback forward to the
# zitadel service — Zitadel routes by Host header, so the issuer host
# must be `localhost` everywhere, exactly like the hosted public URL.
ZITADEL_ISSUER: http://localhost:8080
# The Hub's ADMIN plane. Without this the Hub can verify a token but cannot
# write to Zitadel, so creating a user or minting an API key silently has
# nowhere to go — the console offers no affordance and nothing reaches the
# IdP. `mesh start` seeds the machine key this points at (seed-zitadel).
ZITADEL_OPSHUB_SECRET_NAME: mesh/local/dev/zitadel/ops-hub
SPICEDB_ENDPOINT: spicedb:50051
SPICEDB_HTTP_ENDPOINT: http://spicedb:8443
SPICEDB_HTTP_SCHEME: http
SPICEDB_PRESHARED_KEY: local-dev-key
CORS_ORIGINS: http://localhost:${MESH_HUB_PORT:-9000}
MESH_LOCAL: "1"
depends_on:
database:
condition: service_healthy
ministack:
condition: service_healthy
networks:
- mesh_network
hub-ui:
image: mesh-local-hub-ui:${MESH_HUB_VERSION:-latest}
environment:
PORT: 9000
API_URL: http://hub-api:3002
# Browser-facing API base (SSR link env is in-network; the browser
# needs the host-published port).
PUBLIC_API_URL: http://localhost:4568
AGENT_API_URL: http://hub-api:3002
MESH_LOCAL: "1"
depends_on:
- hub-api
networks:
- mesh_network
# oauth2-proxy in front of the Hub UI — the SAME sidecar mesh.apps.Service
# deploys with `auth.provider: "mesh"` (image + flags mirrored from
# Service.ts; local deltas: cookie-secure=false because http, in-network
# upstream instead of localhost, and the roles scope the hub reads).
# Serves the Hub at http://localhost:9000: unauthenticated browsers land on
# the local Zitadel login, then get X-Forwarded-Access-Token / -User /
# -Email + Authorization headers forwarded — exactly like deployed.
hub-auth:
# Built locally from stack/hub/Dockerfile.auth (public images only):
# oauth2-proxy v7.7.1 + the in-container loopback forward that makes the
# real issuer URL valid here (Zitadel routes by Host header).
image: mesh-local-hub-auth:v7.7.1-r1
restart: unless-stopped
ports:
# MESH_HUB_PORT lets this Hub run beside another process that owns
# 9000 (e.g. a hub-ui dev server from a different checkout). The CLI's
# status probes + Zitadel seeding read the same variable.
- '${MESH_HUB_PORT:-9000}:4180'
command:
- --http-address=0.0.0.0:4180
- --upstream=http://hub-ui:9000
- --provider=oidc
# The ONE issuer URL tokens carry; valid in-container via the
# baked-in loopback forward.
- --oidc-issuer-url=http://localhost:8080
- --scope=openid email profile urn:zitadel:iam:org:project:roles
- --email-domain=*
# RP-initiated logout: hub-ui's /logout redirects through
# /oauth2/sign_out?rd=<issuer end_session>; rd hosts must be
# whitelisted (same flag the Service sidecar sets in the cloud).
- --whitelist-domain=localhost:8080
- --pass-authorization-header=true
- --pass-access-token=true
- --pass-user-headers=true
- --cookie-secure=false
- --cookie-samesite=lax
- --cookie-refresh=4h
- --cookie-expire=12h
- --skip-jwt-bearer-tokens=true
- --skip-provider-button=true
- --silence-ping-logging=true
- --auth-logging=true
- --standard-logging=true
- --redirect-url=http://localhost:${MESH_HUB_PORT:-9000}/oauth2/callback
environment:
OAUTH2_PROXY_CLIENT_ID: ${MESH_HUB_OAUTH2_CLIENT_ID:-unseeded}
OAUTH2_PROXY_CLIENT_SECRET: ${MESH_HUB_OAUTH2_CLIENT_SECRET:-unseeded}
# Placeholder (raw 32 bytes) keeps the container from crash-looping
# pre-seed; the CLI always passes the real persisted secret
# (hub-auth.json).
OAUTH2_PROXY_COOKIE_SECRET: ${MESH_HUB_OAUTH2_COOKIE_SECRET:-local-dev-placeholder-cookie-32b}
depends_on:
- hub-ui
networks:
- mesh_network