@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user