/** * Unit tests for the Codex bulk-import normalizer. * * Pure helpers — no I/O, no network. Synthetic id_tokens are crafted by * base64url-encoding a header/payload/signature triple (only the payload is * decoded; we never verify the signature). * * Ported from decolua/9router#1257 (beaaan). */ import test, { describe } from "node:test"; import assert from "node:assert/strict"; import { normalizeCodexImportRecord, flattenCodexImportPayload, } from "../../src/lib/oauth/services/codexImport.ts"; // ── Helpers ─────────────────────────────────────────────────────────────────── function b64url(obj: unknown): string { return Buffer.from(JSON.stringify(obj)) .toString("base64") .replace(/=+$/, "") .replace(/\+/g, "-") .replace(/\//g, "_"); } function makeIdToken(payload: Record): string { const header = b64url({ alg: "RS256", typ: "JWT" }); const body = b64url(payload); return `${header}.${body}.signature`; } const FULL_RECORD = { id_token: makeIdToken({ email: "test-jwt@example.com", "https://api.openai.com/auth": { chatgpt_account_id: "acct-from-jwt", chatgpt_plan_type: "plus", }, }), access_token: "access-xyz", refresh_token: "refresh-xyz", account_id: "acct-from-record", email: "test-record@example.com", type: "codex", expired: "2026-05-22T10:34:04+07:00", }; // ── normalizeCodexImportRecord ──────────────────────────────────────────────── describe("normalizeCodexImportRecord", () => { test("normalizes a full Codex export record", () => { const result = normalizeCodexImportRecord(FULL_RECORD); assert.equal(result.ok, true); if (!result.ok) return; const { payload } = result; assert.equal(payload.provider, "codex"); assert.equal(payload.authType, "oauth"); assert.equal(payload.accessToken, "access-xyz"); assert.equal(payload.refreshToken, "refresh-xyz"); assert.equal(payload.idToken, FULL_RECORD.id_token); assert.equal(payload.testStatus, "active"); // JWT email wins over the record-level email. assert.equal(payload.email, "test-jwt@example.com"); assert.deepEqual(payload.providerSpecificData, { chatgptAccountId: "acct-from-jwt", chatgptPlanType: "plus", }); // ISO-formatted, parses back to the right instant. const expiresMs = Date.parse(payload.expiresAt); assert.ok(Number.isFinite(expiresMs)); assert.equal(expiresMs, Date.parse(FULL_RECORD.expired)); }); test("falls back to record email when id_token has none", () => { const idToken = makeIdToken({ "https://api.openai.com/auth": { chatgpt_account_id: "x" }, }); const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "fallback@example.com", id_token: idToken, }); assert.equal(result.ok, true); if (!result.ok) return; assert.equal(result.payload.email, "fallback@example.com"); assert.equal(result.payload.providerSpecificData?.chatgptAccountId, "x"); }); test("falls back to account_id when id_token is missing", () => { const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "no-jwt@example.com", account_id: "acct-top-level", }); assert.equal(result.ok, true); if (!result.ok) return; assert.equal(result.payload.providerSpecificData?.chatgptAccountId, "acct-top-level"); assert.equal(result.payload.idToken, undefined); }); test("synthesizes expiresAt when `expired` is missing", () => { const before = Date.now(); const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "x@example.com", }); const after = Date.now(); assert.equal(result.ok, true); if (!result.ok) return; const expiresMs = Date.parse(result.payload.expiresAt); assert.ok(expiresMs > before, "expiresAt should be in the future"); // Default lifetime is 10 days; allow a generous upper bound. assert.ok( expiresMs <= after + 11 * 24 * 60 * 60 * 1000, "expiresAt should be within ~11 days", ); }); test("rejects invalid `expired` strings by falling back to default", () => { const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "x@example.com", expired: "not-a-date", }); assert.equal(result.ok, true); if (!result.ok) return; assert.ok(Number.isFinite(Date.parse(result.payload.expiresAt))); }); test("rejects records missing required fields", () => { assert.equal(normalizeCodexImportRecord({}).ok, false); assert.equal( normalizeCodexImportRecord({ access_token: "a", email: "x@y.z" }).ok, false, ); assert.equal( normalizeCodexImportRecord({ access_token: "a", refresh_token: "r" }).ok, false, // no email anywhere ); }); test("rejects records with non-codex `type`", () => { const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "x@example.com", type: "claude", }); assert.equal(result.ok, false); if (result.ok) return; assert.match(result.error, /Unsupported type/); }); test("rejects non-objects", () => { assert.equal(normalizeCodexImportRecord(null).ok, false); assert.equal(normalizeCodexImportRecord("foo").ok, false); assert.equal(normalizeCodexImportRecord([]).ok, false); }); test("omits providerSpecificData when no account info is present", () => { const result = normalizeCodexImportRecord({ access_token: "a", refresh_token: "r", email: "x@example.com", }); assert.equal(result.ok, true); if (!result.ok) return; assert.equal(result.payload.providerSpecificData, undefined); }); test("unwraps the Codex CLI auth.json shape", () => { const idToken = makeIdToken({ email: "cli@example.com", "https://api.openai.com/auth": { chatgpt_account_id: "acct-cli", chatgpt_plan_type: "free", }, }); // Access token's `exp` is the only expiry signal in auth.json. const expEpoch = Math.floor(Date.now() / 1000) + 3600; const accessToken = makeIdToken({ exp: expEpoch }); const authJson = { auth_mode: "chatgpt", OPENAI_API_KEY: null, tokens: { id_token: idToken, access_token: accessToken, refresh_token: "rt-cli", account_id: "acct-cli", }, last_refresh: "2026-05-16T11:35:58.322795500Z", }; const result = normalizeCodexImportRecord(authJson); assert.equal(result.ok, true); if (!result.ok) return; assert.equal(result.payload.accessToken, accessToken); assert.equal(result.payload.refreshToken, "rt-cli"); assert.equal(result.payload.idToken, idToken); assert.equal(result.payload.email, "cli@example.com"); assert.deepEqual(result.payload.providerSpecificData, { chatgptAccountId: "acct-cli", chatgptPlanType: "free", }); // Falls back to the access_token's `exp` claim when no `expired` field exists. assert.equal(Date.parse(result.payload.expiresAt), expEpoch * 1000); }); test("rejects auth.json when nested tokens are incomplete", () => { const result = normalizeCodexImportRecord({ auth_mode: "chatgpt", tokens: { id_token: "x" }, // missing access_token + refresh_token }); assert.equal(result.ok, false); }); }); // ── flattenCodexImportPayload ───────────────────────────────────────────────── describe("flattenCodexImportPayload", () => { test("wraps a single object", () => { const result = flattenCodexImportPayload({ a: 1 }); assert.equal(result.ok, true); if (!result.ok) return; assert.deepEqual(result.records, [{ a: 1 }]); }); test("passes arrays through", () => { const result = flattenCodexImportPayload([{ a: 1 }, { b: 2 }]); assert.equal(result.ok, true); if (!result.ok) return; assert.deepEqual(result.records, [{ a: 1 }, { b: 2 }]); }); test("rejects scalars", () => { assert.equal(flattenCodexImportPayload("nope").ok, false); assert.equal(flattenCodexImportPayload(42).ok, false); assert.equal(flattenCodexImportPayload(null).ok, false); }); });