From c15451d49fc9bbf03193118522e110b49096f690 Mon Sep 17 00:00:00 2001 From: Bilal Godil Date: Fri, 24 Apr 2026 15:24:31 -0700 Subject: [PATCH] fix(emulator): move mock OAuth off port 8114 to avoid pnpm dev conflict Bind mock-oauth-server to EMULATOR_MOCK_OAUTH_PORT (default 26704) inside the emulator VM and forward the same port on the host. Keeps pnpm dev's 8114 free so both can run side-by-side, and keeps the OIDC issuer URL identical from browser and in-VM backend (same port both sides). --- apps/mock-oauth-server/src/index.ts | 2 +- .../qemu/cloud-init/emulator/user-data | 8 +++++++- docker/local-emulator/qemu/run-emulator.sh | 17 ++++++++++------- packages/stack-cli/src/commands/emulator.ts | 3 +++ 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/apps/mock-oauth-server/src/index.ts b/apps/mock-oauth-server/src/index.ts index 4fdec8fd57..54d1fb8fa0 100644 --- a/apps/mock-oauth-server/src/index.ts +++ b/apps/mock-oauth-server/src/index.ts @@ -5,7 +5,7 @@ import Provider, { errors } from 'oidc-provider'; const stackPortPrefix = process.env.NEXT_PUBLIC_STACK_PORT_PREFIX ?? "81"; const defaultMockOAuthPort = Number(`${stackPortPrefix}14`); -const port = Number(process.env.PORT ?? defaultMockOAuthPort); +const port = Number(process.env.STACK_OAUTH_MOCK_PORT ?? process.env.PORT ?? defaultMockOAuthPort); const backendPortForRedirects = `${stackPortPrefix}02`; const emulatorBackendPort = process.env.STACK_EMULATOR_BACKEND_PORT ?? "32102"; const providerIds = [ diff --git a/docker/local-emulator/qemu/cloud-init/emulator/user-data b/docker/local-emulator/qemu/cloud-init/emulator/user-data index 6ec0976192..cad28a9166 100644 --- a/docker/local-emulator/qemu/cloud-init/emulator/user-data +++ b/docker/local-emulator/qemu/cloud-init/emulator/user-data @@ -130,6 +130,11 @@ write_files: HP_DASHBOARD="$STACK_EMULATOR_DASHBOARD_HOST_PORT" HP_MINIO="$STACK_EMULATOR_MINIO_HOST_PORT" HP_INBUCKET="$STACK_EMULATOR_INBUCKET_HOST_PORT" + # Mock OAuth binds to this port inside the VM and the host forwards the + # same port through, so the OIDC issuer URL is reachable identically + # from the browser and from the backend. Falls back to ${P}14 for + # older ISOs that don't set it. + HP_MOCK_OAUTH="${STACK_EMULATOR_MOCK_OAUTH_HOST_PORT:-${P}14}" cat < "$cfg_dir/runtime.env" cp "$base_env" "$cfg_dir/base.env" @@ -351,11 +353,12 @@ build_qemu_cmd() { netdev+=",hostfwd=tcp:127.0.0.1:${EMULATOR_BACKEND_PORT}-:${PORT_PREFIX}02" netdev+=",hostfwd=tcp:127.0.0.1:${EMULATOR_MINIO_PORT}-:9090" netdev+=",hostfwd=tcp:127.0.0.1:${EMULATOR_INBUCKET_PORT}-:9001" - # Mock OAuth server: browser redirects land on `localhost:${PORT_PREFIX}14` - # (backend sets STACK_OAUTH_MOCK_URL to that value), so we forward host:port - # ↔ VM:port on the same number. Collides with pnpm dev, but the two modes - # are mutually exclusive. - netdev+=",hostfwd=tcp:127.0.0.1:${PORT_PREFIX}14-:${PORT_PREFIX}14" + # Mock OAuth server: the VM-internal mock binds to $EMULATOR_MOCK_OAUTH_PORT + # (overrides the pnpm-dev default of ${PORT_PREFIX}14 via STACK_OAUTH_MOCK_PORT + # threaded through runtime-config.iso). Host and guest use the same port so + # the OIDC issuer URL `http://localhost:${EMULATOR_MOCK_OAUTH_PORT}` resolves + # identically from the browser and from the backend inside the VM. + netdev+=",hostfwd=tcp:127.0.0.1:${EMULATOR_MOCK_OAUTH_PORT}-:${EMULATOR_MOCK_OAUTH_PORT}" # In snapshot-resume mode the QEMU command-line MUST match the device set # used at snapshot capture time, otherwise migration replay fails (broken @@ -499,7 +502,7 @@ tail_vm_logs() { } ensure_ports_free() { - local ports=("$EMULATOR_DASHBOARD_PORT" "$EMULATOR_BACKEND_PORT" "$EMULATOR_MINIO_PORT" "$EMULATOR_INBUCKET_PORT" "${PORT_PREFIX}14") + local ports=("$EMULATOR_DASHBOARD_PORT" "$EMULATOR_BACKEND_PORT" "$EMULATOR_MINIO_PORT" "$EMULATOR_INBUCKET_PORT" "$EMULATOR_MOCK_OAUTH_PORT") local port for port in "${ports[@]}"; do if lsof -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1; then @@ -761,7 +764,7 @@ cmd_start() { info "Starting QEMU local emulator" info "Arch: $ARCH | Accel: $ACCEL" - info "Ports: Dashboard=$EMULATOR_DASHBOARD_PORT Backend=$EMULATOR_BACKEND_PORT MinIO=$EMULATOR_MINIO_PORT Inbucket=$EMULATOR_INBUCKET_PORT" + info "Ports: Dashboard=$EMULATOR_DASHBOARD_PORT Backend=$EMULATOR_BACKEND_PORT MinIO=$EMULATOR_MINIO_PORT Inbucket=$EMULATOR_INBUCKET_PORT MockOAuth=$EMULATOR_MOCK_OAUTH_PORT" local using_snapshot=0 if snapshot_available; then diff --git a/packages/stack-cli/src/commands/emulator.ts b/packages/stack-cli/src/commands/emulator.ts index 3a67d26c07..4815e09e45 100644 --- a/packages/stack-cli/src/commands/emulator.ts +++ b/packages/stack-cli/src/commands/emulator.ts @@ -14,6 +14,7 @@ const DEFAULT_EMULATOR_BACKEND_PORT = 26701; const DEFAULT_EMULATOR_DASHBOARD_PORT = 26700; const DEFAULT_EMULATOR_MINIO_PORT = 26702; const DEFAULT_EMULATOR_INBUCKET_PORT = 26703; +const DEFAULT_EMULATOR_MOCK_OAUTH_PORT = 26704; const DEFAULT_PORT_PREFIX = "81"; const GITHUB_API = "https://api.github.com"; const DEFAULT_REPO = "stack-auth/stack-auth"; @@ -188,6 +189,7 @@ function prepareRuntimeConfigIso(): void { const backendPort = envPort("EMULATOR_BACKEND_PORT", DEFAULT_EMULATOR_BACKEND_PORT); const minioPort = envPort("EMULATOR_MINIO_PORT", DEFAULT_EMULATOR_MINIO_PORT); const inbucketPort = envPort("EMULATOR_INBUCKET_PORT", DEFAULT_EMULATOR_INBUCKET_PORT); + const mockOAuthPort = envPort("EMULATOR_MOCK_OAUTH_PORT", DEFAULT_EMULATOR_MOCK_OAUTH_PORT); const runtimeEnv = [ `STACK_EMULATOR_PORT_PREFIX=${portPrefix}`, @@ -195,6 +197,7 @@ function prepareRuntimeConfigIso(): void { `STACK_EMULATOR_BACKEND_HOST_PORT=${backendPort}`, `STACK_EMULATOR_MINIO_HOST_PORT=${minioPort}`, `STACK_EMULATOR_INBUCKET_HOST_PORT=${inbucketPort}`, + `STACK_EMULATOR_MOCK_OAUTH_HOST_PORT=${mockOAuthPort}`, `STACK_EMULATOR_VM_DIR_HOST=${vmDir}`, "", ].join("\n");