From 4e1167e390bbcfaed337dd7808508d87a54f78d1 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 09:30:11 +0200 Subject: [PATCH] =?UTF-8?q?test(scripts):=20resolveClaudeAuth=20=E2=80=94?= =?UTF-8?q?=20subscription/api-key/missing=20modes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/work/dispatch.test.mjs | 61 ++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/scripts/work/dispatch.test.mjs b/scripts/work/dispatch.test.mjs index 7e80811..79402e0 100644 --- a/scripts/work/dispatch.test.mjs +++ b/scripts/work/dispatch.test.mjs @@ -6,6 +6,7 @@ import { findNextTask, findFirstUncheckedBullet, buildTaskSpec, + resolveClaudeAuth, } from "./dispatch.mjs"; function makeWorkTree({ epics }) { @@ -137,3 +138,63 @@ describe("buildTaskSpec", () => { expect(spec).toContain("## Goal"); }); }); + +describe("resolveClaudeAuth", () => { + it("returns subscription mode when ~/.claude exists on host", () => { + const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "auth-sub-")); + fs.mkdirSync(path.join(tmpHome, ".claude")); + const result = resolveClaudeAuth({ env: {}, home: tmpHome }); + expect(result.mode).toBe("subscription"); + expect(result.hostPath).toBe(path.join(tmpHome, ".claude")); + expect(result.sandboxPath).toBe("~/.claude"); + }); + + it("honours SANDCASTLE_CLAUDE_CREDS_DIR override", () => { + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "auth-override-")); + const overrideDir = path.join(tmpRoot, "custom-claude"); + fs.mkdirSync(overrideDir); + const result = resolveClaudeAuth({ + env: { SANDCASTLE_CLAUDE_CREDS_DIR: overrideDir }, + home: "/nonexistent", + }); + expect(result.mode).toBe("subscription"); + expect(result.hostPath).toBe(overrideDir); + }); + + it("falls back to ANTHROPIC_API_KEY when ~/.claude does not exist", () => { + const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "auth-key-")); + // No .claude directory created + const result = resolveClaudeAuth({ + env: { ANTHROPIC_API_KEY: "sk-test" }, + home: tmpHome, + }); + expect(result.mode).toBe("api-key"); + expect(result.env).toEqual({ ANTHROPIC_API_KEY: "sk-test" }); + }); + + it("falls back to OPENAI_API_KEY when only that is set", () => { + const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "auth-openai-")); + const result = resolveClaudeAuth({ + env: { OPENAI_API_KEY: "sk-openai" }, + home: tmpHome, + }); + expect(result.mode).toBe("api-key"); + expect(result.env).toEqual({ OPENAI_API_KEY: "sk-openai" }); + }); + + it("returns missing when neither subscription nor API key available", () => { + const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "auth-missing-")); + const result = resolveClaudeAuth({ env: {}, home: tmpHome }); + expect(result.mode).toBe("missing"); + }); + + it("prefers subscription over API key when both available", () => { + const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "auth-both-")); + fs.mkdirSync(path.join(tmpHome, ".claude")); + const result = resolveClaudeAuth({ + env: { ANTHROPIC_API_KEY: "sk-test" }, + home: tmpHome, + }); + expect(result.mode).toBe("subscription"); + }); +});