fix(coding-agent): make config env references explicit

closes #5095
This commit is contained in:
Armin Ronacher
2026-05-28 11:57:10 +02:00
parent 5b31ffd744
commit 3e9f717445
17 changed files with 930 additions and 71 deletions

View File

@@ -112,13 +112,13 @@ describe("AuthStorage", () => {
expect(apiKey).toBeUndefined();
});
test("apiKey as environment variable name resolves to env value", async () => {
test("apiKey with $ prefix resolves to env value", async () => {
const originalEnv = process.env.TEST_AUTH_API_KEY_12345;
process.env.TEST_AUTH_API_KEY_12345 = "env-api-key-value";
try {
writeAuthJson({
anthropic: { type: "api_key", key: "TEST_AUTH_API_KEY_12345" },
anthropic: { type: "api_key", key: "$TEST_AUTH_API_KEY_12345" },
});
authStorage = AuthStorage.create(authJsonPath);
@@ -134,6 +134,140 @@ describe("AuthStorage", () => {
}
});
test("apiKey with braced env syntax resolves to env value", async () => {
const originalEnv = process.env.TEST_AUTH_BRACED_API_KEY_12345;
process.env.TEST_AUTH_BRACED_API_KEY_12345 = "braced-env-api-key-value";
const bracedKey = "$" + "{TEST_AUTH_BRACED_API_KEY_12345}";
try {
writeAuthJson({
anthropic: { type: "api_key", key: bracedKey },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("anthropic");
expect(apiKey).toBe("braced-env-api-key-value");
} finally {
if (originalEnv === undefined) {
delete process.env.TEST_AUTH_BRACED_API_KEY_12345;
} else {
process.env.TEST_AUTH_BRACED_API_KEY_12345 = originalEnv;
}
}
});
test("apiKey interpolates braced env references inside literals", async () => {
const originalPartA = process.env.TEST_AUTH_INTERPOLATED_PART_A_12345;
const originalPartB = process.env.TEST_AUTH_INTERPOLATED_PART_B_12345;
process.env.TEST_AUTH_INTERPOLATED_PART_A_12345 = "left";
process.env.TEST_AUTH_INTERPOLATED_PART_B_12345 = "right";
const interpolatedKey = [
"$",
"{TEST_AUTH_INTERPOLATED_PART_A_12345}_$",
"{TEST_AUTH_INTERPOLATED_PART_B_12345}",
].join("");
try {
writeAuthJson({
anthropic: { type: "api_key", key: interpolatedKey },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("anthropic");
expect(apiKey).toBe("left_right");
} finally {
if (originalPartA === undefined) {
delete process.env.TEST_AUTH_INTERPOLATED_PART_A_12345;
} else {
process.env.TEST_AUTH_INTERPOLATED_PART_A_12345 = originalPartA;
}
if (originalPartB === undefined) {
delete process.env.TEST_AUTH_INTERPOLATED_PART_B_12345;
} else {
process.env.TEST_AUTH_INTERPOLATED_PART_B_12345 = originalPartB;
}
}
});
test("apiKey with $$ prefix escapes a leading dollar", async () => {
writeAuthJson({
anthropic: { type: "api_key", key: "$$TEST_AUTH_API_KEY_12345" },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("anthropic");
expect(apiKey).toBe("$TEST_AUTH_API_KEY_12345");
});
test("apiKey with $! escapes a literal bang and still interpolates later env refs", async () => {
const originalEnv = process.env.TEST_AUTH_API_KEY_12345;
process.env.TEST_AUTH_API_KEY_12345 = "env-api-key-value";
try {
writeAuthJson({
anthropic: { type: "api_key", key: "$!literal-$TEST_AUTH_API_KEY_12345" },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("anthropic");
expect(apiKey).toBe("!literal-env-api-key-value");
} finally {
if (originalEnv === undefined) {
delete process.env.TEST_AUTH_API_KEY_12345;
} else {
process.env.TEST_AUTH_API_KEY_12345 = originalEnv;
}
}
});
test("plain API key is used directly even when it matches an env var", async () => {
const originalEnv = process.env.TEST_AUTH_API_KEY_12345;
process.env.TEST_AUTH_API_KEY_12345 = "env-api-key-value";
try {
writeAuthJson({
anthropic: { type: "api_key", key: "TEST_AUTH_API_KEY_12345" },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("anthropic");
expect(apiKey).toBe("TEST_AUTH_API_KEY_12345");
} finally {
if (originalEnv === undefined) {
delete process.env.TEST_AUTH_API_KEY_12345;
} else {
process.env.TEST_AUTH_API_KEY_12345 = originalEnv;
}
}
});
test("literal public API key is not corrupted by the Windows PUBLIC env var", async () => {
const originalPublic = process.env.PUBLIC;
process.env.PUBLIC = "C:\\Users\\Public";
try {
writeAuthJson({
opencode: { type: "api_key", key: "public" },
});
authStorage = AuthStorage.create(authJsonPath);
const apiKey = await authStorage.getApiKey("opencode");
expect(apiKey).toBe("public");
} finally {
if (originalPublic === undefined) {
delete process.env.PUBLIC;
} else {
process.env.PUBLIC = originalPublic;
}
}
});
test("apiKey as literal value is used directly when not an env var", async () => {
// Make sure this isn't an env var
delete process.env.literal_api_key_value;
@@ -274,7 +408,7 @@ describe("AuthStorage", () => {
process.env[envVarName] = "first-value";
writeAuthJson({
anthropic: { type: "api_key", key: envVarName },
anthropic: { type: "api_key", key: `$${envVarName}` },
});
authStorage = AuthStorage.create(authJsonPath);