diff --git a/app/gateway-api/src/orchestrator/gatewayOrchestrator.ts b/app/gateway-api/src/orchestrator/gatewayOrchestrator.ts index 102e74ca..b603f431 100644 --- a/app/gateway-api/src/orchestrator/gatewayOrchestrator.ts +++ b/app/gateway-api/src/orchestrator/gatewayOrchestrator.ts @@ -467,6 +467,11 @@ export const buildProcessDefinitions = ( tournament: { name: string; script: string; cwd: string; env: Record }; } => { const baseEnv = sanitizeManagedProcessEnv(config.baseEnv ?? {}); + const profileDatabaseUrl = resolveGatewayPostgresConfigFromEnv(baseEnv, profile.profile).url; + const backendEnv = { + ...baseEnv, + DATABASE_URL: profileDatabaseUrl, + }; const frontendName = buildProcessName(profile.profileName, 'frontend'); const apiName = buildProcessName(profile.profileName, 'api'); const daemonName = buildProcessName(profile.profileName, 'daemon'); @@ -483,7 +488,7 @@ export const buildProcessDefinitions = ( const daemonScript = path.join(daemonCwd, 'dist', 'index.js'); const turnDaemonNodeOptions = baseEnv.TURN_DAEMON_NODE_OPTIONS?.trim(); const apiEnv = { - ...baseEnv, + ...backendEnv, POSTGRES_POOL_MAX: managedPostgresPoolMax(baseEnv, 'GAME_API_POSTGRES_POOL_MAX', 4), GAME_API_ROLE: 'server', PROFILE: profile.profile, @@ -498,7 +503,7 @@ export const buildProcessDefinitions = ( GATEWAY_INTERNAL_API_URL: config.gatewayInternalApiUrl, }; const daemonEnv = { - ...baseEnv, + ...backendEnv, ...(turnDaemonNodeOptions ? { NODE_OPTIONS: turnDaemonNodeOptions } : {}), POSTGRES_POOL_MAX: managedPostgresPoolMax(baseEnv, 'TURN_DAEMON_POSTGRES_POOL_MAX', 2), GAME_ENGINE_ROLE: 'turn-daemon', diff --git a/app/gateway-api/test/orchestratorPlan.test.ts b/app/gateway-api/test/orchestratorPlan.test.ts index 2a29a838..7026238e 100644 --- a/app/gateway-api/test/orchestratorPlan.test.ts +++ b/app/gateway-api/test/orchestratorPlan.test.ts @@ -250,7 +250,6 @@ describe('buildProcessDefinitions', () => { }); for (const definition of Object.values(definitions)) { - expect(definition.env).toMatchObject({ DATABASE_URL: 'postgresql://integration.invalid/sammo' }); expect(definition.env).not.toHaveProperty('pm_id'); expect(definition.env).not.toHaveProperty('args'); expect(definition.env).not.toHaveProperty('pm_exec_path'); @@ -258,9 +257,46 @@ describe('buildProcessDefinitions', () => { expect(definition.env).not.toHaveProperty('NODE_APP_INSTANCE'); expect(definition.env).not.toHaveProperty('GATEWAY_ROLE'); } + expect(definitions.frontend.env.DATABASE_URL).toBe('postgresql://integration.invalid/sammo'); + for (const definition of [ + definitions.api, + definitions.daemon, + definitions.auction, + definitions.battleSim, + definitions.tournament, + ]) { + expect(definition.env.DATABASE_URL).toBe('postgresql://integration.invalid/sammo?schema=che'); + } expect(definitions.frontend.env.VITE_APP_BASE_PATH).toBe('/che'); }); + it('passes the encoded profile database URL to every backend process', () => { + const definitions = buildProcessDefinitions(buildProfile(), { + ...processConfig, + baseEnv: { + GATEWAY_DATABASE_URL: + 'postgresql://sammo:encoded%23password@postgres:5432/sammo?schema=public', + POSTGRES_USER: 'sammo', + POSTGRES_PASSWORD: 'raw#password', + POSTGRES_HOST: 'postgres', + POSTGRES_PORT: '5432', + POSTGRES_DB: 'sammo', + }, + }); + const expectedUrl = 'postgresql://sammo:encoded%23password@postgres:5432/sammo?schema=che'; + + for (const definition of [ + definitions.api, + definitions.daemon, + definitions.auction, + definitions.battleSim, + definitions.tournament, + ]) { + expect(definition.env.DATABASE_URL).toBe(expectedUrl); + } + expect(definitions.frontend.env).not.toHaveProperty('DATABASE_URL'); + }); + it('applies a dedicated Node heap option only to the turn daemon', () => { const definitions = buildProcessDefinitions(buildProfile(), { ...processConfig, diff --git a/app/gateway-api/test/profileDeployOperation.test.ts b/app/gateway-api/test/profileDeployOperation.test.ts index 67154d05..93d1ec01 100644 --- a/app/gateway-api/test/profileDeployOperation.test.ts +++ b/app/gateway-api/test/profileDeployOperation.test.ts @@ -144,9 +144,11 @@ describe('profile DEPLOY operation', () => { ]; const backendProcessNames = processNames.filter((name) => !name.endsWith(':game-frontend')); const running = new Set(processNames); + const startedDefinitions: Array[0]> = []; const processManager: ProcessManager = { list: async () => [...running].map((name) => ({ name, status: 'online' })), start: async (definition) => { + startedDefinitions.push(definition); running.add(definition.name); }, stop: async () => {}, @@ -225,6 +227,12 @@ describe('profile DEPLOY operation', () => { expect(commandGroups[1]?.[0]?.env?.DATABASE_URL).toBe( 'postgresql://user:encoded%23password@integration.invalid/sammo?schema=che' ); + expect(startedDefinitions).toHaveLength(backendProcessNames.length); + for (const definition of startedDefinitions) { + expect(definition.env?.DATABASE_URL).toBe( + 'postgresql://user:encoded%23password@integration.invalid/sammo?schema=che' + ); + } expect(commandGroups.flat().some((command) => command.env?.GATEWAY_ROLE === 'profile-seed')).toBe(false); expect(patches.at(-1)).toMatchObject({ buildStatus: 'SUCCEEDED',