fix(config): expand environment variable references in YAML config#699
fix(config): expand environment variable references in YAML config#699kajirita2002 wants to merge 1 commit intoComposioHQ:mainfrom
Conversation
Read the raw YAML content and substitute \${VAR} placeholders with
process.env values before parsing, so users can reference env vars
(e.g. Slack webhook URLs) in agent-orchestrator.yaml without hardcoding
secrets. Unset variables are left as-is. Added tests for both cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
|
|
||
| const config = loadConfig(configPath); | ||
| expect(config.port).toBe(7000); | ||
| }); |
There was a problem hiding this comment.
Unset env var test contains no variable references
Medium Severity
The test "should leave unset environment variable references unchanged" writes a YAML config that contains zero ${...} placeholders. The ${testDir} on the path: line is a JavaScript template literal interpolated at write time, not a literal env var reference for the config loader. Since no \${UNSET_VAR_12345} or similar escaped reference appears in the YAML content, the substitution logic is never exercised. This test passes regardless of whether the feature works.
| expect(config.projects["env-project"]).toBeDefined(); | ||
| // Verify the raw YAML was parsed after substitution by checking port | ||
| expect(config.port).toBe(6000); | ||
| }); |
There was a problem hiding this comment.
Expansion test never verifies substituted value exists
Medium Severity
The test "should expand environment variable references in config" places the \${TEST_SLACK_WEBHOOK_URL} reference inside a notifications.slack.webhookUrl field, but ProjectConfigSchema has no notifications property and doesn't use .passthrough(), so Zod silently strips it. The assertions only check that the project is defined and the port is 6000—both true even without any substitution. The test would pass if the substitution regex were completely broken.
|
|
||
| const raw = readFileSync(path, "utf-8"); | ||
| const parsed = parseYaml(raw); | ||
| const substituted = raw.replace(/\$\{([^}]+)\}/g, (_, key) => process.env[key] ?? `\${${key}}`); |
There was a problem hiding this comment.
Env var values with YAML metacharacters break parsing
Medium Severity
The raw.replace() injects env var values directly into the YAML string before parsing. If a value contains YAML metacharacters (colons followed by spaces, #, newlines, {, [, etc.), it can alter the document structure or cause parse errors. Since the PR encourages unquoted usage like webhookUrl: ${SLACK_WEBHOOK_URL}, values containing these characters will silently corrupt the config or throw cryptic YAML parse errors.


Summary
loadConfigandloadConfigWithPathinpackages/core/src/config.tsnow substitute${VAR}placeholders in the raw YAML string withprocess.envvalues before parsing${UNSET_VAR}stays as-is)packages/core/__tests__/config.test.tscovering successful substitution and the unset-variable fallbackMotivation
Users were forced to hardcode secrets (e.g. Slack webhook URLs) directly in
agent-orchestrator.yamlbecause env var references like${SLACK_WEBHOOK_URL}were passed through as literal strings to the YAML parser. This change unblocks the common pattern of keeping secrets in environment variables and referencing them from config files.Usage after fix
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/... ao startCloses #701