/** * Structural regression tests for OAuth provider error handling. * * These are text-based assertions on source files (no network calls). * They verify that each refresh function: * - Exists with the expected signature * - Handles the provider-specific unrecoverable error codes * - Returns the normalized { error: "unrecoverable_refresh_error", code } sentinel */ import test from "node:test"; import assert from "node:assert/strict"; import { readFile } from "fs/promises"; import path from "path"; const root = path.resolve(import.meta.dirname, "../.."); const read = (rel: string) => readFile(path.join(root, rel), "utf8"); // ─── P0: GitLab Duo ─────────────────────────────────────────────────────────── test("P0: gitlab-duo is registered in providerRegistry", async () => { const src = await read("open-sse/config/providerRegistry.ts"); assert.match(src, /["']gitlab-duo["']\s*:/, "gitlab-duo must be a key in REGISTRY"); }); test("P0: refreshGitLabDuoToken exists and handles invalid_grant as unrecoverable", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); assert.match( src, /export\s+async\s+function\s+refreshGitLabDuoToken\(/, "refreshGitLabDuoToken must be exported" ); // Extract the function body const fnMatch = src.match(/export\s+async\s+function\s+refreshGitLabDuoToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshGitLabDuoToken function body not found"); assert.match(fnMatch[0], /invalid_grant/, "must detect invalid_grant"); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); test("P0: gitlab-duo case exists in _getAccessTokenInternal", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); assert.match(src, /case\s+["']gitlab-duo["']/, "gitlab-duo case must exist in switch"); }); test("P0: gitlab-duo is in supportsTokenRefresh explicit set", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); // Find the explicitlySupported Set const setMatch = src.match(/const\s+explicitlySupported\s*=\s*new\s+Set\(\[[\s\S]+?\]\)/); assert.ok(setMatch, "explicitlySupported Set not found"); assert.match(setMatch[0], /["']gitlab-duo["']/, "gitlab-duo must be in explicitlySupported"); }); // ─── P1: Kimi Coding stable device_id ──────────────────────────────────────── test("P1: refreshKimiCodingToken accepts providerSpecificData parameter", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); assert.match( src, /export\s+async\s+function\s+refreshKimiCodingToken\([^)]*providerSpecificData/, "refreshKimiCodingToken must accept providerSpecificData" ); }); test("P1: refreshKimiCodingToken does NOT use ephemeral Date.now() device ID", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); // Extract function body — match from declaration to next top-level export function const fnMatch = src.match(/export\s+async\s+function\s+refreshKimiCodingToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshKimiCodingToken function body not found"); assert.doesNotMatch( fnMatch[0], /["']kimi-refresh-["']\s*\+\s*Date\.now\(\)/, "must NOT use ephemeral kimi-refresh-+Date.now() device ID" ); }); test("P1: refreshKimiCodingToken handles invalid_grant as unrecoverable", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshKimiCodingToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshKimiCodingToken function body not found"); assert.match(fnMatch[0], /invalid_grant/, "must detect invalid_grant"); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); test("P1: _getAccessTokenInternal passes providerSpecificData to refreshKimiCodingToken", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); // The case for kimi-coding should pass credentials.providerSpecificData assert.match( src, /case\s+["']kimi-coding["']:[\s\S]{1,300}providerSpecificData/, "kimi-coding case must pass providerSpecificData" ); }); // ─── P1: GitHub Copilot sub-token health check ──────────────────────────────── test("P1: GitHub Copilot sub-token is refreshed by tokenHealthCheck", async () => { const src = await read("src/lib/tokenHealthCheck.ts"); assert.match(src, /copilot|Copilot/i, "tokenHealthCheck must reference Copilot"); // Must import refreshCopilotToken assert.match(src, /refreshCopilotToken/, "must import and call refreshCopilotToken"); }); test("P1: tokenHealthCheck checks copilotTokenExpiresAt before refreshing", async () => { const src = await read("src/lib/tokenHealthCheck.ts"); assert.match(src, /copilotTokenExpiresAt/, "must check copilotTokenExpiresAt"); assert.match(src, /conn\.provider\s*===\s*["']github["']/, "must be gated on github provider"); }); // ─── P2: Google invalid_grant ───────────────────────────────────────────────── test("P2: refreshGoogleToken parses invalid_grant as unrecoverable", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshGoogleToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshGoogleToken function body not found"); assert.match(fnMatch[0], /invalid_grant/, "must detect invalid_grant"); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); // ─── P2: Qwen invalid_grant ─────────────────────────────────────────────────── test("P2: refreshQwenToken handles invalid_grant in addition to invalid_request", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshQwenToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshQwenToken function body not found"); assert.match(fnMatch[0], /invalid_grant/, "must detect invalid_grant"); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); // ─── P2: Kiro AWS InvalidGrantException ────────────────────────────────────── test("P2: refreshKiroToken parses AWS InvalidGrantException", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshKiroToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshKiroToken function body not found"); assert.match( fnMatch[0], /InvalidGrantException|ExpiredTokenException/, "must detect AWS error types" ); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); test("P2: refreshKiroToken handles AWS errors on both AWS OIDC and social auth paths", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshKiroToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshKiroToken function body not found"); // Count occurrences of InvalidGrantException — should appear in both paths const matchCount = (fnMatch[0].match(/InvalidGrantException/g) || []).length; assert.ok( matchCount >= 2, `InvalidGrantException should be checked in both paths (found ${matchCount} occurrences)` ); }); // ─── P3: Claude error shape normalization ───────────────────────────────────── test("P3: refreshClaudeOAuthToken normalizes invalid_grant to unrecoverable_refresh_error sentinel", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshClaudeOAuthToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshClaudeOAuthToken function body not found"); assert.match( fnMatch[0], /unrecoverable_refresh_error[\s\S]{1,100}invalid_grant|invalid_grant[\s\S]{1,100}unrecoverable_refresh_error/, "invalid_grant must map to unrecoverable_refresh_error sentinel" ); // Must NOT return the old non-normalized shape { error: errorBody.error, code: "http_..." } assert.doesNotMatch( fnMatch[0], /code:\s*`http_\$\{response\.status\}`/, "must NOT return http_NNN code format for invalid_grant" ); }); // ─── P3: Windsurf Firebase errors ──────────────────────────────────────────── test("P3: refreshWindsurfToken parses Firebase USER_DISABLED/TOKEN_EXPIRED errors", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+async\s+function\s+refreshWindsurfToken\([\s\S]+?\n\}/); assert.ok(fnMatch, "refreshWindsurfToken function body not found"); assert.match( fnMatch[0], /USER_DISABLED|TOKEN_EXPIRED|INVALID_REFRESH_TOKEN/, "must detect Firebase error codes" ); assert.match(fnMatch[0], /unrecoverable_refresh_error/, "must return unrecoverable sentinel"); }); // ─── isUnrecoverableRefreshError consistency ────────────────────────────────── test("isUnrecoverableRefreshError detects the normalized sentinel shape", async () => { const src = await read("open-sse/services/tokenRefresh.ts"); const fnMatch = src.match(/export\s+function\s+isUnrecoverableRefreshError\([\s\S]+?\n\}/); assert.ok(fnMatch, "isUnrecoverableRefreshError function body not found"); assert.match( fnMatch[0], /unrecoverable_refresh_error/, "must detect unrecoverable_refresh_error" ); });