Skip to content

refactor: unify environment variable structure and improve author resolution logic#359

Closed
hieuntg81 wants to merge 3 commits intomainfrom
refactor/env-var-consolidation-2
Closed

refactor: unify environment variable structure and improve author resolution logic#359
hieuntg81 wants to merge 3 commits intomainfrom
refactor/env-var-consolidation-2

Conversation

@hieuntg81
Copy link
Copy Markdown
Collaborator

Summary

  • Problem: 6 separate env vars for IAM/OIDC/Cogit/LLM URLs are redundant ? OIDC endpoints (authorize, token, issuer) are always derived from the IAM base, and API version paths (/api/v1) are baked into env vars instead of being appended at point of use.
  • Why it matters: Adding a new IAM endpoint requires updating multiple env vars. Misconfiguring one OIDC URL while the others are correct causes subtle auth failures that are hard to diagnose.
  • What changed:
    • Replaced 6 env vars with 3 base URL vars:
      • BRV_API_BASE_URL, BRV_AUTHORIZATION_URL, BRV_ISSUER_URL, BRV_TOKEN_URL ? BRV_IAM_BASE_URL
      • BRV_COGIT_API_BASE_URL ? BRV_COGIT_BASE_URL
      • BRV_LLM_API_BASE_URL ? BRV_LLM_BASE_URL
    • OIDC URLs (authorizationUrl, issuerUrl, tokenUrl) are now derived from iamBaseUrl inside getCurrentConfig()
    • API version paths (/api/v1) are appended at point of use in feature-handlers.ts
    • Updated EnvironmentConfig type, all consumers, and tests
  • What did NOT change (scope boundary): No behavioral changes to auth flow, OIDC discovery, or any HTTP service. Only the source of URL values changed.

Type of change

  • Bug fix
  • New feature
  • Refactor (no behavior change)
  • Documentation
  • Test
  • Chore (build, dependencies, CI)

Scope (select all touched areas)

  • TUI / REPL
  • Agent / Tools
  • LLM Providers
  • Server / Daemon
  • Shared (constants, types, transport events)
  • CLI Commands (oclif)
  • Hub / Connectors
  • Cloud Sync
  • CI/CD / Infra

Linked issues

  • Related #ENG-2002

Root cause (bug fixes only, otherwise write N/A)

N/A

Test plan

  • Coverage added:
    • Unit test
    • Integration test
    • Manual verification only
  • Test file(s): test/unit/config/environment.test.ts
  • Key scenario(s) covered:
    • All URL properties read correctly from new env vars
    • OIDC URLs derived correctly from BRV_IAM_BASE_URL
    • Missing required env var throws with correct variable name

User-visible changes

  • .env.example updated ? developers must update their .env.development / .env.production files:
Old New
BRV_API_BASE_URL=http://localhost:3000/api/v1 BRV_IAM_BASE_URL=http://localhost:3000
BRV_AUTHORIZATION_URL=http://localhost:3000/api/v1/oidc/authorize (removed, derived)
BRV_ISSUER_URL=http://localhost:3000/api/v1/oidc (removed, derived)
BRV_TOKEN_URL=http://localhost:3000/api/v1/oidc/token (removed, derived)
BRV_COGIT_API_BASE_URL=http://localhost:3001/api/v1 BRV_COGIT_BASE_URL=http://localhost:3001
BRV_LLM_API_BASE_URL=http://localhost:3002 BRV_LLM_BASE_URL=http://localhost:3002

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording

TypeScript type check and all environment config tests pass after changes.

Checklist

  • Tests added or updated and passing (npm test)
  • Lint passes (npm run lint)
  • Type check passes (npm run typecheck)
  • Build succeeds (npm run build)
  • Commits follow Conventional Commits format
  • Documentation updated (if applicable)
  • No breaking changes (or clearly documented above)
  • Branch is up to date with main

Risks and mitigations

  • Risk: Developers with existing .env.development / .env.production files will get startup errors after pulling this change.
    • Mitigation: Error message clearly states which env var is missing (Missing required environment variable: BRV_IAM_BASE_URL). .env.example serves as reference.

hieuntg81 and others added 3 commits April 11, 2026 14:17
…olution logic

- Replace `apiBaseUrl` references with `iamBaseUrl`, `cogitBaseUrl`, and `llmBaseUrl` for consistent base URL handling.
- Simplify and centralize commit author detection logic with `resolveAuthor` method, including better fallback mechanisms.
- Adjust OIDC URLs to derive dynamically from `iamBaseUrl`, removing redundant variables.
- Update transport handlers, services, and configuration logic to align with refactored base URL structure.
- Refine signing key CRUD operations and CLI commands for enhanced reliability.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

Claude finished @leehpham's task in 2m 45s —— View job


PR Review

  • Gather context
  • Read changed files
  • Analyze for correctness, security, and code quality
  • Post inline comments
  • Post summary with score

Summary

Score: 4 / 5

This is a clean, well-reasoned refactor. Collapsing 6 env vars into 3 base URL vars and deriving OIDC paths programmatically is the right call — it eliminates an entire class of misconfiguration bugs where individual OIDC URLs could drift out of sync with the IAM base.

What's good

  • The readRequiredEnv → throw pattern gives clear, actionable error messages at startup.
  • API version paths (/api/v1) are now appended at a single, visible point of use rather than baked into env vars — easier to audit and change.
  • Type renames (cogitApiBaseUrlcogitBaseUrl, llmApiBaseUrlllmBaseUrl) are accurate since those fields no longer carry the version path.
  • Test coverage for the derived OIDC URL logic and the fallback auth path is solid.
  • Scope boundary respected — no behavioral changes to auth flow or HTTP services.

Issues found

Correctness — trailing slash normalization (3 inline comments)
BRV_IAM_BASE_URL=http://localhost:3000/ (trailing slash) silently produces malformed URLs: http://localhost:3000//api/v1/oidc/authorize. This affects environment.ts:62, feature-handlers.ts:104, and feature-handlers.ts:149. A .replace(/\/$/, '') before each interpolation is the minimal fix.

Testing — missing required-var coverage (1 inline comment on environment.test.ts:124)
Only BRV_IAM_BASE_URL is tested for the "missing → throws" path. The other four required vars have no coverage.

Nitpick — dual semantics on BRV_GIT_REMOTE_BASE_URL (1 inline comment on environment.ts:79)
getGitRemoteBaseUrl() silently falls back to https://byterover.dev while getCurrentConfig() hard-throws for the same env var. Pre-existing issue, but visible since this file was touched.

Non-issues

  • ConfigGetEnvironmentResponse rename (apiBaseUrliamBaseUrl) is correct; no TUI/oclif consumers of that event were found, so no missed update.
  • LLM base URL not having /api/v1 appended is intentional — the old BRV_LLM_API_BASE_URL example value was already the raw base (http://localhost:3002), so behavior is unchanged.

@leehpham
Copy link
Copy Markdown
Member

@hieuntg81 please go through the feedback from Claude Code first.

})
export const getCurrentConfig = (): EnvironmentConfig => {
const iamBaseUrl = readRequiredEnv('BRV_IAM_BASE_URL')
const oidcBase = `${iamBaseUrl}/api/v1/oidc`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (correctness): If BRV_IAM_BASE_URL is set with a trailing slash (e.g. http://localhost:3000/), all derived OIDC URLs will contain a double slash (http://localhost:3000//api/v1/oidc/authorize). Consider normalizing the value:

Suggested change
const oidcBase = `${iamBaseUrl}/api/v1/oidc`
const oidcBase = `${iamBaseUrl.replace(/\/$/, '')}/api/v1/oidc`

Same protection would be good for cogitBaseUrl and llmBaseUrl in feature-handlers.ts.

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`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (correctness): Same trailing-slash hazard here. If iamBaseUrl ends with /, iamApiV1 becomes http://localhost:3000//api/v1. Strip before concatenating:

Suggested change
const iamApiV1 = `${envConfig.iamBaseUrl}/api/v1`
const iamApiV1 = `${envConfig.iamBaseUrl.replace(/\/$/, '')}/api/v1`

const contextFileReader = new FileContextFileReader()
const cogitPushService = new HttpCogitPushService({apiBaseUrl: envConfig.cogitApiBaseUrl})
const cogitPullService = new HttpCogitPullService({apiBaseUrl: envConfig.cogitApiBaseUrl})
const cogitApiV1 = `${envConfig.cogitBaseUrl}/api/v1`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (correctness): Same trailing-slash concern for cogitBaseUrl:

Suggested change
const cogitApiV1 = `${envConfig.cogitBaseUrl}/api/v1`
const cogitApiV1 = `${envConfig.cogitBaseUrl.replace(/\/$/, '')}/api/v1`

@@ -125,11 +123,11 @@ describe('Environment Configuration', () => {

it('should throw when a required env var is missing', async () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Only BRV_IAM_BASE_URL is tested as a missing required var. The other four required vars (BRV_COGIT_BASE_URL, BRV_GIT_REMOTE_BASE_URL, BRV_LLM_BASE_URL, BRV_WEB_APP_URL) have no coverage for the "missing → throws" path. Consider parameterizing:

for (const key of ['BRV_COGIT_BASE_URL', 'BRV_GIT_REMOTE_BASE_URL', 'BRV_LLM_BASE_URL', 'BRV_WEB_APP_URL']) {
  it(`should throw when ${key} is missing`, async () => {
    delete process.env[key]
    const {getCurrentConfig} = await import(`../../../src/server/config/environment.js?t=${Date.now()}`)
    expect(() => getCurrentConfig()).to.throw(`Missing required environment variable: ${key}`)
  })
}

Not a blocker, but improves safety net for future env-var changes.

}
}

export const getGitRemoteBaseUrl = (): string =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (consistency): getGitRemoteBaseUrl() silently falls back to 'https://byterover.dev' when the env var is absent, but getCurrentConfig() calls readRequiredEnv('BRV_GIT_REMOTE_BASE_URL') which throws on the same var. These two functions have divergent semantics for the same key. This predates the PR, but since the file was touched it's worth tracking — a caller using getGitRemoteBaseUrl() could silently get the production default while getCurrentConfig() would hard-fail in the same environment.

@hieuntg81 hieuntg81 closed this Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants