Skip to content

Commit 0264481

Browse files
committed
config: add secret_source=metadata mode and ${secret:NAME} interpolation
Phase C Cloud tenants need to fetch the provider API key from the host metadata gateway instead of reading process.env. The loader now supports two modes: the existing default secret_source: env continues to read process.env unchanged, and the new secret_source: metadata fetches the named secret from http://169.254.169.254/v1/secrets/<name>, populates process.env.ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN, and walks the parsed config replacing ${secret:NAME} references with their resolved plaintext. Self-host installs that omit secret_source see no behaviour change. Whole-string interpolation only, so partial-string references in URLs and other composed values are intentionally left untouched to avoid leaking plaintext through any code path that logs the original string. Adds MetadataSecretFetcher (60s TTL cache, ETag/If-None-Match against X-Phantom-Rotation-Id) and updates two callers (src/index.ts, src/cli/doctor.ts) to await the now-async loadConfig. The original sync code path is preserved as loadConfigSync for any context that genuinely cannot await.
1 parent 34c252a commit 0264481

13 files changed

Lines changed: 557 additions & 55 deletions

src/agent/__tests__/prompt-assembler.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ const baseConfig: PhantomConfig = {
99
port: 3100,
1010
role: "swe",
1111
model: "claude-opus-4-6",
12-
provider: { type: "anthropic" },
12+
provider: { type: "anthropic", secret_name: "provider_token" },
13+
secret_source: "env",
1314
effort: "max",
1415
max_budget_usd: 0,
1516
timeout_minutes: 240,

src/cli/doctor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async function checkConfig(): Promise<CheckResult> {
9090
}
9191
try {
9292
const { loadConfig } = await import("../config/loader.ts");
93-
const config = loadConfig();
93+
const config = await loadConfig();
9494
return { name: "Config", status: "ok", message: `${config.name} (${config.role}, port ${config.port})` };
9595
} catch (err: unknown) {
9696
const msg = err instanceof Error ? err.message : String(err);

0 commit comments

Comments
 (0)