diff --git a/.env.example b/.env.example index af08f44e0..f622f7803 100644 --- a/.env.example +++ b/.env.example @@ -2,11 +2,8 @@ # Copy this file to .env.development (for dev) or .env.production (for production) # and fill in the values for your environment. -BRV_API_BASE_URL=http://localhost:3000/api/v1 -BRV_AUTHORIZATION_URL=http://localhost:3000/api/v1/oidc/authorize -BRV_COGIT_API_BASE_URL=http://localhost:3001/api/v1 +BRV_IAM_BASE_URL=http://localhost:3000 +BRV_COGIT_BASE_URL=http://localhost:3001 BRV_GIT_REMOTE_BASE_URL=http://localhost:8080 -BRV_ISSUER_URL=http://localhost:3000/api/v1/oidc -BRV_LLM_API_BASE_URL=http://localhost:3002 -BRV_TOKEN_URL=http://localhost:3000/api/v1/oidc/token +BRV_LLM_BASE_URL=http://localhost:3002 BRV_WEB_APP_URL=http://localhost:8080 diff --git a/src/server/config/environment.ts b/src/server/config/environment.ts index e16160db6..6ff71777a 100644 --- a/src/server/config/environment.ts +++ b/src/server/config/environment.ts @@ -15,16 +15,22 @@ export const ENVIRONMENT: Environment = isEnvironment(envValue) ? envValue : 'de /** * Environment-specific configuration. + * + * Base URL vars (BRV_IAM_BASE_URL, BRV_COGIT_BASE_URL, BRV_LLM_BASE_URL) + * store only the root domain (e.g., http://localhost:8080). + * API version paths (/api/v1, /api/v3) are appended at the point of use. + * + * OIDC URLs are derived from iamBaseUrl; no separate env vars needed. */ type EnvironmentConfig = { - apiBaseUrl: string authorizationUrl: string clientId: string - cogitApiBaseUrl: string + cogitBaseUrl: string gitRemoteBaseUrl: string hubRegistryUrl: string + iamBaseUrl: string issuerUrl: string - llmApiBaseUrl: string + llmBaseUrl: string scopes: string[] tokenUrl: string webAppUrl: string @@ -51,19 +57,24 @@ const readRequiredEnv = (name: string): string => { return value } -export const getCurrentConfig = (): EnvironmentConfig => ({ - apiBaseUrl: readRequiredEnv('BRV_API_BASE_URL'), - authorizationUrl: readRequiredEnv('BRV_AUTHORIZATION_URL'), - clientId: DEFAULTS.clientId, - cogitApiBaseUrl: readRequiredEnv('BRV_COGIT_API_BASE_URL'), - gitRemoteBaseUrl: readRequiredEnv('BRV_GIT_REMOTE_BASE_URL'), - hubRegistryUrl: DEFAULTS.hubRegistryUrl, - issuerUrl: readRequiredEnv('BRV_ISSUER_URL'), - llmApiBaseUrl: readRequiredEnv('BRV_LLM_API_BASE_URL'), - scopes: [...DEFAULTS.scopes[ENVIRONMENT]], - tokenUrl: readRequiredEnv('BRV_TOKEN_URL'), - webAppUrl: readRequiredEnv('BRV_WEB_APP_URL'), -}) +export const getCurrentConfig = (): EnvironmentConfig => { + const iamBaseUrl = readRequiredEnv('BRV_IAM_BASE_URL') + const oidcBase = `${iamBaseUrl}/api/v1/oidc` + + return { + authorizationUrl: `${oidcBase}/authorize`, + clientId: DEFAULTS.clientId, + cogitBaseUrl: readRequiredEnv('BRV_COGIT_BASE_URL'), + gitRemoteBaseUrl: readRequiredEnv('BRV_GIT_REMOTE_BASE_URL'), + hubRegistryUrl: DEFAULTS.hubRegistryUrl, + iamBaseUrl, + issuerUrl: oidcBase, + llmBaseUrl: readRequiredEnv('BRV_LLM_BASE_URL'), + scopes: [...DEFAULTS.scopes[ENVIRONMENT]], + tokenUrl: `${oidcBase}/token`, + webAppUrl: readRequiredEnv('BRV_WEB_APP_URL'), + } +} export const getGitRemoteBaseUrl = (): string => process.env.BRV_GIT_REMOTE_BASE_URL ?? 'https://byterover.dev' diff --git a/src/server/infra/daemon/agent-process.ts b/src/server/infra/daemon/agent-process.ts index a76326f57..e9de2af6c 100644 --- a/src/server/infra/daemon/agent-process.ts +++ b/src/server/infra/daemon/agent-process.ts @@ -248,7 +248,7 @@ async function start(): Promise { const envConfig = getCurrentConfig() const agentConfig = { - apiBaseUrl: envConfig.llmApiBaseUrl, + apiBaseUrl: envConfig.llmBaseUrl, fileSystem: {allowedPaths: ['.', ...sharedAllowedPaths], workingDirectory: projectPath}, llm: { maxIterations: 10, diff --git a/src/server/infra/process/feature-handlers.ts b/src/server/infra/process/feature-handlers.ts index 1ccd512b1..aab9fd225 100644 --- a/src/server/infra/process/feature-handlers.ts +++ b/src/server/infra/process/feature-handlers.ts @@ -101,9 +101,10 @@ export async function setupFeatureHandlers({ const envConfig = getCurrentConfig() const tokenStore = createTokenStore() const projectConfigStore = new ProjectConfigStore() - const userService = new HttpUserService({apiBaseUrl: envConfig.apiBaseUrl}) - const teamService = new HttpTeamService({apiBaseUrl: envConfig.apiBaseUrl}) - const spaceService = new HttpSpaceService({apiBaseUrl: envConfig.apiBaseUrl}) + const iamApiV1 = `${envConfig.iamBaseUrl}/api/v1` + const userService = new HttpUserService({apiBaseUrl: iamApiV1}) + const teamService = new HttpTeamService({apiBaseUrl: iamApiV1}) + const spaceService = new HttpSpaceService({apiBaseUrl: iamApiV1}) // Auth handler requires async OIDC discovery const discoveryService = new OidcDiscoveryService() @@ -145,8 +146,9 @@ export async function setupFeatureHandlers({ const contextTreeWriterService = new FileContextTreeWriterService({snapshotService: contextTreeSnapshotService}) const contextTreeMerger = new FileContextTreeMerger({snapshotService: contextTreeSnapshotService}) const contextFileReader = new FileContextFileReader() - const cogitPushService = new HttpCogitPushService({apiBaseUrl: envConfig.cogitApiBaseUrl}) - const cogitPullService = new HttpCogitPullService({apiBaseUrl: envConfig.cogitApiBaseUrl}) + const cogitApiV1 = `${envConfig.cogitBaseUrl}/api/v1` + const cogitPushService = new HttpCogitPushService({apiBaseUrl: cogitApiV1}) + const cogitPullService = new HttpCogitPullService({apiBaseUrl: cogitApiV1}) // ConnectorManager factory — creates per-project instances since constructor binds to projectRoot const fileService = new FsFileService() diff --git a/src/server/infra/transport/handlers/config-handler.ts b/src/server/infra/transport/handlers/config-handler.ts index 05ecded65..e303041d3 100644 --- a/src/server/infra/transport/handlers/config-handler.ts +++ b/src/server/infra/transport/handlers/config-handler.ts @@ -22,7 +22,7 @@ export class ConfigHandler { this.transport.onRequest(ConfigEvents.GET_ENVIRONMENT, () => { const config = getCurrentConfig() return { - apiBaseUrl: config.apiBaseUrl, + iamBaseUrl: config.iamBaseUrl, isDevelopment: isDevelopment(), webAppUrl: config.webAppUrl, } diff --git a/src/shared/transport/events/config-events.ts b/src/shared/transport/events/config-events.ts index 7b744cd54..de15e0035 100644 --- a/src/shared/transport/events/config-events.ts +++ b/src/shared/transport/events/config-events.ts @@ -7,7 +7,7 @@ export const ConfigEvents = { } as const export interface ConfigGetEnvironmentResponse { - apiBaseUrl: string + iamBaseUrl: string isDevelopment: boolean webAppUrl: string } diff --git a/test/unit/config/auth.config.test.ts b/test/unit/config/auth.config.test.ts index 1935479ea..16c6e68e4 100644 --- a/test/unit/config/auth.config.test.ts +++ b/test/unit/config/auth.config.test.ts @@ -9,13 +9,10 @@ describe('Auth Configuration', () => { let consoleWarnStub: sinon.SinonStub const ENV_VARS = { - BRV_API_BASE_URL: 'https://api.test', - BRV_AUTHORIZATION_URL: 'https://auth.test/authorize', - BRV_COGIT_API_BASE_URL: 'https://cogit.test', + BRV_COGIT_BASE_URL: 'https://cogit.test', BRV_GIT_REMOTE_BASE_URL: 'https://cogit-git.test', - BRV_ISSUER_URL: 'https://issuer.test', - BRV_LLM_API_BASE_URL: 'https://llm.test', - BRV_TOKEN_URL: 'https://auth.test/token', + BRV_IAM_BASE_URL: 'https://iam.test', + BRV_LLM_BASE_URL: 'https://llm.test', BRV_WEB_APP_URL: 'https://app.test', } @@ -109,8 +106,8 @@ describe('Auth Configuration', () => { it('should fallback to env var URLs when discovery fails', async () => { const config = await getAuthConfig(discoveryService) - expect(config.authorizationUrl).to.equal('https://auth.test/authorize') - expect(config.tokenUrl).to.equal('https://auth.test/token') + expect(config.authorizationUrl).to.equal('https://iam.test/api/v1/oidc/authorize') + expect(config.tokenUrl).to.equal('https://iam.test/api/v1/oidc/token') }) it('should still use environment-specific clientId and scopes in fallback', async () => { @@ -123,7 +120,7 @@ describe('Auth Configuration', () => { }) it('should throw on network errors', async () => { - discoveryService.discover = stub().rejects(new Error('getaddrinfo ENOTFOUND issuer.test')) + discoveryService.discover = stub().rejects(new Error('getaddrinfo ENOTFOUND iam.test')) try { await getAuthConfig(discoveryService) diff --git a/test/unit/config/environment.test.ts b/test/unit/config/environment.test.ts index 89ad09154..c0ebe4645 100644 --- a/test/unit/config/environment.test.ts +++ b/test/unit/config/environment.test.ts @@ -2,13 +2,10 @@ import {expect} from 'chai' describe('Environment Configuration', () => { const ENV_VARS = { - BRV_API_BASE_URL: 'https://api.test', - BRV_AUTHORIZATION_URL: 'https://auth.test/authorize', - BRV_COGIT_API_BASE_URL: 'https://cogit.test', + BRV_COGIT_BASE_URL: 'https://cogit.test', BRV_GIT_REMOTE_BASE_URL: 'https://cogit-git.test', - BRV_ISSUER_URL: 'https://issuer.test', - BRV_LLM_API_BASE_URL: 'https://llm.test', - BRV_TOKEN_URL: 'https://auth.test/token', + BRV_IAM_BASE_URL: 'https://iam.test', + BRV_LLM_BASE_URL: 'https://llm.test', BRV_WEB_APP_URL: 'https://app.test', } @@ -78,12 +75,13 @@ describe('Environment Configuration', () => { const {getCurrentConfig} = await import(`../../../src/server/config/environment.js?t=${Date.now()}`) const config = getCurrentConfig() - expect(config.apiBaseUrl).to.equal('https://api.test') - expect(config.authorizationUrl).to.equal('https://auth.test/authorize') - expect(config.cogitApiBaseUrl).to.equal('https://cogit.test') - expect(config.issuerUrl).to.equal('https://issuer.test') - expect(config.llmApiBaseUrl).to.equal('https://llm.test') - expect(config.tokenUrl).to.equal('https://auth.test/token') + expect(config.iamBaseUrl).to.equal('https://iam.test') + expect(config.authorizationUrl).to.equal('https://iam.test/api/v1/oidc/authorize') + expect(config.cogitBaseUrl).to.equal('https://cogit.test') + expect(config.gitRemoteBaseUrl).to.equal('https://cogit-git.test') + expect(config.issuerUrl).to.equal('https://iam.test/api/v1/oidc') + expect(config.llmBaseUrl).to.equal('https://llm.test') + expect(config.tokenUrl).to.equal('https://iam.test/api/v1/oidc/token') expect(config.webAppUrl).to.equal('https://app.test') }) @@ -125,11 +123,11 @@ describe('Environment Configuration', () => { it('should throw when a required env var is missing', async () => { delete process.env.BRV_ENV - delete process.env.BRV_API_BASE_URL + delete process.env.BRV_IAM_BASE_URL const {getCurrentConfig} = await import(`../../../src/server/config/environment.js?t=${Date.now()}`) - expect(() => getCurrentConfig()).to.throw('Missing required environment variable: BRV_API_BASE_URL') + expect(() => getCurrentConfig()).to.throw('Missing required environment variable: BRV_IAM_BASE_URL') }) }) })