Skip to content

Commit bdbe4e0

Browse files
authored
Merge pull request #10 from kiran-4444/fix/config-placeholder-discovery
Ignore env-var placeholders during config key discovery
2 parents 4e2b177 + d3ccdaa commit bdbe4e0

2 files changed

Lines changed: 61 additions & 13 deletions

File tree

src/utils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,11 @@ export function readExistingConfig() {
386386
const baseUrl = jsonRead(filePath, "env.ANTHROPIC_BASE_URL");
387387
if (!baseUrl) continue;
388388

389-
const authToken = jsonRead(filePath, "env.ANTHROPIC_AUTH_TOKEN") || "";
389+
const rawToken = jsonRead(filePath, "env.ANTHROPIC_AUTH_TOKEN") || "";
390+
// A committed config stores the env-var reference (e.g. "${PORTKEY_API_KEY}"),
391+
// not a usable key. Treat that as "no key here" so discovery falls through to
392+
// the real environment variable instead of using the placeholder literally.
393+
const authToken = rawToken.includes("${") ? "" : rawToken;
390394
const headers = jsonRead(filePath, "env.ANTHROPIC_CUSTOM_HEADERS") || "";
391395
const model = jsonRead(filePath, "model") || "";
392396

tests/utils.test.js

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
21
import fs from "node:fs";
3-
import path from "node:path";
42
import os from "node:os";
3+
import path from "node:path";
4+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
55
import {
6-
mask,
7-
normalizeProvider,
8-
sortModels,
96
isLikelyPortkeyApiKeyPermissionError,
107
jsonRead,
11-
settingsSetEnv,
8+
mask,
9+
normalizeProvider,
10+
readExistingConfig,
11+
removeShellRcBlock,
12+
settingsReadMcp,
1213
settingsRemoveKeys,
13-
settingsSetMcp,
1414
settingsRemoveMcp,
15-
settingsReadMcp,
16-
writeShellRc,
17-
removeShellRcBlock,
18-
writeFileSecure,
15+
settingsSetEnv,
16+
settingsSetMcp,
17+
sortModels,
1918
warnIfFileGroupOrWorldReadable,
19+
writeFileSecure,
20+
writeShellRc,
2021
} from "../src/utils.js";
2122

2223
function mode(file) {
@@ -146,7 +147,6 @@ describe("jsonRead", () => {
146147
});
147148
});
148149

149-
// ── writeFileSecure (0600 for secret-bearing files) ───────────────────────────
150150

151151
describe("writeFileSecure", () => {
152152
let dir;
@@ -371,3 +371,47 @@ describe("writeShellRc + removeShellRcBlock", () => {
371371
expect(removeShellRcBlock(file)).toBe(false);
372372
});
373373
});
374+
375+
// ── readExistingConfig (key discovery + placeholder guard) ────────────────────
376+
377+
describe("readExistingConfig", () => {
378+
let dir, cwd;
379+
beforeEach(() => {
380+
dir = tmpDir();
381+
fs.mkdirSync(path.join(dir, ".git"), { recursive: true }); // mark project root
382+
fs.mkdirSync(path.join(dir, ".claude"), { recursive: true });
383+
cwd = process.cwd();
384+
process.chdir(dir);
385+
});
386+
afterEach(() => {
387+
process.chdir(cwd);
388+
fs.rmSync(dir, { recursive: true, force: true });
389+
});
390+
391+
function writeSharedSettings(env) {
392+
fs.writeFileSync(
393+
path.join(dir, ".claude", "settings.json"),
394+
JSON.stringify({ env }, null, 2)
395+
);
396+
}
397+
398+
it("recovers a literal key from an existing (pre-fix) config", () => {
399+
writeSharedSettings({
400+
ANTHROPIC_BASE_URL: "https://api.portkey.ai/v1",
401+
ANTHROPIC_AUTH_TOKEN: "pk-live-REAL-KEY",
402+
});
403+
const cfg = readExistingConfig();
404+
expect(cfg.found).toBe(true);
405+
expect(cfg.portkeyKey).toBe("pk-live-REAL-KEY");
406+
});
407+
408+
it("does NOT return the ${PORTKEY_API_KEY} placeholder as a usable key", () => {
409+
writeSharedSettings({
410+
ANTHROPIC_BASE_URL: "https://api.portkey.ai/v1",
411+
ANTHROPIC_AUTH_TOKEN: "${PORTKEY_API_KEY}",
412+
});
413+
const cfg = readExistingConfig();
414+
expect(cfg.found).toBe(true);
415+
expect(cfg.portkeyKey).toBe("");
416+
});
417+
});

0 commit comments

Comments
 (0)