diff options
| author | jerop <[email protected]> | 2025-06-06 13:54:59 +0000 |
|---|---|---|
| committer | Jerop Kipruto <[email protected]> | 2025-06-06 11:47:37 -0400 |
| commit | 4e9d365407564e0f440bf4645607aa47a1d16bca (patch) | |
| tree | 257684bdade5e42fe7a07bd304321a990ea4ede7 /packages/cli/src/config/settings.ts | |
| parent | 9ad615c2a486675c4ad75c986a0a5dbd8f8b030e (diff) | |
feat: Enable environment variable substitution in settings
This commit introduces the ability to use system environment variables
within the settings files (e.g., `settings.json`). Users can now
reference environment variables using the `${VAR_NAME}` syntax.
This enhancement improves security and flexibility, particularly
for configurations like MCP server settings, which often require
sensitive tokens.
Previously, to configure an MCP server, a token might be directly
embedded:
```json
"mcpServers": {
"github": {
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "pat_abc123"
}
// ...
}
}
```
With this change, the same configuration can securely reference an
environment variable:
```json
"mcpServers": {
"github": {
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
// ...
}
}
```
This allows users to avoid storing secrets directly in configuration files.
Diffstat (limited to 'packages/cli/src/config/settings.ts')
| -rw-r--r-- | packages/cli/src/config/settings.ts | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index db5dabb6..8205a018 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -98,6 +98,39 @@ export class LoadedSettings { } } +function resolveEnvVarsInString(value: string): string { + const envVarRegex = /\$(?:(\w+)|{([^}]+)})/g; // Find $VAR_NAME or ${VAR_NAME} + return value.replace(envVarRegex, (match, varName1, varName2) => { + const varName = varName1 || varName2; + if (process && process.env && typeof process.env[varName] === 'string') { + return process.env[varName]!; + } + return match; + }); +} + +function resolveEnvVarsInObject<T>(obj: T): T { + if (typeof obj === 'string') { + return resolveEnvVarsInString(obj) as unknown as T; + } + + if (Array.isArray(obj)) { + return obj.map((item) => resolveEnvVarsInObject(item)) as unknown as T; + } + + if (obj && typeof obj === 'object') { + const newObj = { ...obj } as T; + for (const key in newObj) { + if (Object.prototype.hasOwnProperty.call(newObj, key)) { + newObj[key] = resolveEnvVarsInObject(newObj[key]); + } + } + return newObj; + } + + return obj; +} + /** * Loads settings from user and workspace directories. * Project settings override user settings. @@ -110,7 +143,10 @@ export function loadSettings(workspaceDir: string): LoadedSettings { try { if (fs.existsSync(USER_SETTINGS_PATH)) { const userContent = fs.readFileSync(USER_SETTINGS_PATH, 'utf-8'); - userSettings = JSON.parse(stripJsonComments(userContent)) as Settings; + const parsedUserSettings = JSON.parse( + stripJsonComments(userContent), + ) as Settings; + userSettings = resolveEnvVarsInObject(parsedUserSettings); // Support legacy theme names if (userSettings.theme && userSettings.theme === 'VS') { userSettings.theme = DefaultLight.name; @@ -132,9 +168,10 @@ export function loadSettings(workspaceDir: string): LoadedSettings { try { if (fs.existsSync(workspaceSettingsPath)) { const projectContent = fs.readFileSync(workspaceSettingsPath, 'utf-8'); - workspaceSettings = JSON.parse( + const parsedWorkspaceSettings = JSON.parse( stripJsonComments(projectContent), ) as Settings; + workspaceSettings = resolveEnvVarsInObject(parsedWorkspaceSettings); if (workspaceSettings.theme && workspaceSettings.theme === 'VS') { workspaceSettings.theme = DefaultLight.name; } else if ( |
