From 04d57d91ed63165087b6708a573f2207a7001791 Mon Sep 17 00:00:00 2001 From: BilalG1 Date: Mon, 27 Apr 2026 09:39:34 -0700 Subject: [PATCH] fix(emulator): move mock OAuth off 8114 to avoid pnpm dev conflict (#1385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - The emulator's mock OAuth server bound to `${PORT_PREFIX}14` (8114) inside the VM and the host forwarded the same port, colliding with `pnpm dev`'s mock-oauth-server on 8114. - Moves the emulator's mock OAuth to `EMULATOR_MOCK_OAUTH_PORT` (default `26704`, joining the existing `267xx` host port block) and binds the VM-internal mock to the same port. Same port on both sides keeps the OIDC issuer URL (`http://localhost:26704`) resolvable identically from the browser and from the backend inside the VM. - Plumbed via `runtime-config.iso` as `STACK_EMULATOR_MOCK_OAUTH_HOST_PORT`, read by cloud-init into `STACK_OAUTH_MOCK_URL` + new `STACK_OAUTH_MOCK_PORT`; `mock-oauth-server` now prefers `STACK_OAUTH_MOCK_PORT` so `pnpm dev` (which doesn't set it) stays on 8114. ## Files - `docker/local-emulator/qemu/run-emulator.sh` — new `EMULATOR_MOCK_OAUTH_PORT`, hostfwd/ensure_ports_free/runtime.env updates - `docker/local-emulator/qemu/cloud-init/emulator/user-data` — reads the host port, sets `STACK_OAUTH_MOCK_URL` + `STACK_OAUTH_MOCK_PORT` - `apps/mock-oauth-server/src/index.ts` — honors `STACK_OAUTH_MOCK_PORT` - `packages/stack-cli/src/commands/emulator.ts` — default + runtime.env entry ## Test plan - [ ] `pnpm emulator:build` succeeds and new snapshot boots - [ ] `stack emulator start` with `pnpm dev` running on 8114 — no port collision - [ ] OAuth sign-in via mock provider completes end-to-end in the emulator - [ ] `pnpm dev` mock OAuth unchanged (still 8114) ## Summary by CodeRabbit ## Release Notes * **New Features** * The mock OAuth server port is now configurable in the local emulator with a sensible default, allowing custom port assignments via environment variable. * **Improvements** * Updated port forwarding and environment variable handling to ensure consistent mock OAuth endpoint configuration across host and guest systems in the emulator. --- 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 4fdec8fd5..54d1fb8fa 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 6ec097619..cad28a916 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 3a67d26c0..4815e09e4 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");