fix(frontend): filter empty env vars to prevent OAuth token override (#520)

* fix(frontend): filter empty env vars to prevent OAuth token override

When .auto-claude/.env contains CLAUDE_CODE_OAUTH_TOKEN= (empty value),
it was overriding valid OAuth tokens from profiles, causing
'Control request timeout: initialize' errors.

The fix filters out empty values when loading environment variables from
.env files in loadProjectEnv() and loadAutoBuildEnv() functions.

Fixes #451

* refactor(frontend): extract parseEnvFile helper per code review

Address code review feedback from gemini-code-assist and coderabbitai:
- Extract duplicated .env parsing logic into shared parseEnvFile() helper
- Clarify comment: filter applies to all env vars, not just tokens
- Follows DRY principle for better maintainability

---------

Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
This commit is contained in:
Ashwinhegde19
2026-01-04 01:33:41 +05:30
committed by GitHub
parent acdd7d9b1e
commit 556f0b2129
+47 -70
View File
@@ -239,6 +239,51 @@ export class AgentProcessManager {
return env;
}
/**
* Parse environment variables from a .env file content.
* Filters out empty values to prevent overriding valid tokens from profiles.
*/
private parseEnvFile(envPath: string): Record<string, string> {
if (!existsSync(envPath)) {
return {};
}
try {
const envContent = readFileSync(envPath, 'utf-8');
const envVars: Record<string, string> = {};
// Handle both Unix (\n) and Windows (\r\n) line endings
for (const line of envContent.split(/\r?\n/)) {
const trimmed = line.trim();
// Skip comments and empty lines
if (!trimmed || trimmed.startsWith('#')) {
continue;
}
const eqIndex = trimmed.indexOf('=');
if (eqIndex > 0) {
const key = trimmed.substring(0, eqIndex).trim();
let value = trimmed.substring(eqIndex + 1).trim();
// Remove quotes if present
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
// Skip empty values to prevent overriding valid values from other sources
if (value) {
envVars[key] = value;
}
}
}
return envVars;
} catch {
return {};
}
}
/**
* Load environment variables from project's .auto-claude/.env file
* This contains frontend-configured settings like memory/Graphiti configuration
@@ -253,41 +298,7 @@ export class AgentProcessManager {
}
const envPath = path.join(projectPath, project.autoBuildPath, '.env');
if (!existsSync(envPath)) {
return {};
}
try {
const envContent = readFileSync(envPath, 'utf-8');
const envVars: Record<string, string> = {};
// Handle both Unix (\n) and Windows (\r\n) line endings
for (const line of envContent.split(/\r?\n/)) {
const trimmed = line.trim();
// Skip comments and empty lines
if (!trimmed || trimmed.startsWith('#')) {
continue;
}
const eqIndex = trimmed.indexOf('=');
if (eqIndex > 0) {
const key = trimmed.substring(0, eqIndex).trim();
let value = trimmed.substring(eqIndex + 1).trim();
// Remove quotes if present
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
envVars[key] = value;
}
}
return envVars;
} catch {
return {};
}
return this.parseEnvFile(envPath);
}
/**
@@ -300,41 +311,7 @@ export class AgentProcessManager {
}
const envPath = path.join(autoBuildSource, '.env');
if (!existsSync(envPath)) {
return {};
}
try {
const envContent = readFileSync(envPath, 'utf-8');
const envVars: Record<string, string> = {};
// Handle both Unix (\n) and Windows (\r\n) line endings
for (const line of envContent.split(/\r?\n/)) {
const trimmed = line.trim();
// Skip comments and empty lines
if (!trimmed || trimmed.startsWith('#')) {
continue;
}
const eqIndex = trimmed.indexOf('=');
if (eqIndex > 0) {
const key = trimmed.substring(0, eqIndex).trim();
let value = trimmed.substring(eqIndex + 1).trim();
// Remove quotes if present
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
envVars[key] = value;
}
}
return envVars;
} catch {
return {};
}
return this.parseEnvFile(envPath);
}
/**