import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { ensureAuthProfileStore } from "./auth-profiles.js"; import { AUTH_STORE_VERSION, CODEX_CLI_PROFILE_ID } from "./auth-profiles/constants.js"; import { withTempHome } from "../../test/helpers/temp-home.js"; describe("ensureAuthProfileStore", () => { it("migrates legacy auth.json and deletes it (PR #368)", () => { const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-auth-profiles-")); try { const legacyPath = path.join(agentDir, "auth.json"); fs.writeFileSync( legacyPath, `${JSON.stringify( { anthropic: { type: "oauth", provider: "anthropic", access: "access-token", refresh: "refresh-token", expires: Date.now() + 60_000, }, }, null, 2, )}\n`, "utf8", ); const store = ensureAuthProfileStore(agentDir); expect(store.profiles["anthropic:default"]).toMatchObject({ type: "oauth", provider: "anthropic", }); const migratedPath = path.join(agentDir, "auth-profiles.json"); expect(fs.existsSync(migratedPath)).toBe(true); expect(fs.existsSync(legacyPath)).toBe(false); // idempotent const store2 = ensureAuthProfileStore(agentDir); expect(store2.profiles["anthropic:default"]).toBeDefined(); expect(fs.existsSync(legacyPath)).toBe(false); } finally { fs.rmSync(agentDir, { recursive: true, force: true }); } }); it("merges main auth profiles into agent store and keeps agent overrides", () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-auth-merge-")); const previousAgentDir = process.env.CLAWDBOT_AGENT_DIR; const previousPiAgentDir = process.env.PI_CODING_AGENT_DIR; try { const mainDir = path.join(root, "main-agent"); const agentDir = path.join(root, "agent-x"); fs.mkdirSync(mainDir, { recursive: true }); fs.mkdirSync(agentDir, { recursive: true }); process.env.CLAWDBOT_AGENT_DIR = mainDir; process.env.PI_CODING_AGENT_DIR = mainDir; const mainStore = { version: AUTH_STORE_VERSION, profiles: { "openai:default": { type: "api_key", provider: "openai", key: "main-key", }, "anthropic:default": { type: "api_key", provider: "anthropic", key: "main-anthropic-key", }, }, }; fs.writeFileSync( path.join(mainDir, "auth-profiles.json"), `${JSON.stringify(mainStore, null, 2)}\n`, "utf8", ); const agentStore = { version: AUTH_STORE_VERSION, profiles: { "openai:default": { type: "api_key", provider: "openai", key: "agent-key", }, }, }; fs.writeFileSync( path.join(agentDir, "auth-profiles.json"), `${JSON.stringify(agentStore, null, 2)}\n`, "utf8", ); const store = ensureAuthProfileStore(agentDir); expect(store.profiles["anthropic:default"]).toMatchObject({ type: "api_key", provider: "anthropic", key: "main-anthropic-key", }); expect(store.profiles["openai:default"]).toMatchObject({ type: "api_key", provider: "openai", key: "agent-key", }); } finally { if (previousAgentDir === undefined) { delete process.env.CLAWDBOT_AGENT_DIR; } else { process.env.CLAWDBOT_AGENT_DIR = previousAgentDir; } if (previousPiAgentDir === undefined) { delete process.env.PI_CODING_AGENT_DIR; } else { process.env.PI_CODING_AGENT_DIR = previousPiAgentDir; } fs.rmSync(root, { recursive: true, force: true }); } }); it("drops codex-cli from merged store when a custom openai-codex profile matches", async () => { await withTempHome(async (tempHome) => { const root = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-auth-dedup-merge-")); const previousAgentDir = process.env.CLAWDBOT_AGENT_DIR; const previousPiAgentDir = process.env.PI_CODING_AGENT_DIR; try { const mainDir = path.join(root, "main-agent"); const agentDir = path.join(root, "agent-x"); fs.mkdirSync(mainDir, { recursive: true }); fs.mkdirSync(agentDir, { recursive: true }); process.env.CLAWDBOT_AGENT_DIR = mainDir; process.env.PI_CODING_AGENT_DIR = mainDir; process.env.HOME = tempHome; fs.writeFileSync( path.join(mainDir, "auth-profiles.json"), `${JSON.stringify( { version: AUTH_STORE_VERSION, profiles: { [CODEX_CLI_PROFILE_ID]: { type: "oauth", provider: "openai-codex", access: "shared-access-token", refresh: "shared-refresh-token", expires: Date.now() + 3600000, }, }, }, null, 2, )}\n`, "utf8", ); fs.writeFileSync( path.join(agentDir, "auth-profiles.json"), `${JSON.stringify( { version: AUTH_STORE_VERSION, profiles: { "openai-codex:my-custom-profile": { type: "oauth", provider: "openai-codex", access: "shared-access-token", refresh: "shared-refresh-token", expires: Date.now() + 3600000, }, }, }, null, 2, )}\n`, "utf8", ); const store = ensureAuthProfileStore(agentDir); expect(store.profiles[CODEX_CLI_PROFILE_ID]).toBeUndefined(); expect(store.profiles["openai-codex:my-custom-profile"]).toBeDefined(); } finally { if (previousAgentDir === undefined) { delete process.env.CLAWDBOT_AGENT_DIR; } else { process.env.CLAWDBOT_AGENT_DIR = previousAgentDir; } if (previousPiAgentDir === undefined) { delete process.env.PI_CODING_AGENT_DIR; } else { process.env.PI_CODING_AGENT_DIR = previousPiAgentDir; } fs.rmSync(root, { recursive: true, force: true }); } }); }); });