|
| 1 | +import { describe, expect, test } from "bun:test"; |
| 2 | +import { Glob } from "bun"; |
| 3 | +import { dirname, join } from "node:path"; |
| 4 | +import { fileURLToPath } from "node:url"; |
| 5 | +import { CODEX_AUTH_FILENAME } from "./codex/store.js"; |
| 6 | +import { |
| 7 | + buildCredentialPatterns, |
| 8 | + credentialDirDescriptors, |
| 9 | + credentialFileDescriptors, |
| 10 | +} from "./credential-surface.js"; |
| 11 | +import { MCP_AUTH_DIRNAME } from "../mcp/auth-store.js"; |
| 12 | +import { XAI_AUTH_FILENAME } from "./xai/store.js"; |
| 13 | + |
| 14 | +const here = dirname(fileURLToPath(import.meta.url)); |
| 15 | + |
| 16 | +// Auth-owned credential literals live in exactly these store modules. Test |
| 17 | +// fixtures (concurrent-auth.json, test-auth.json) live in *.test.ts, which the |
| 18 | +// scan below excludes, so fixture names can never become denylist patterns. |
| 19 | +const STORE_FILES = [ |
| 20 | + join(here, "codex", "store.ts"), |
| 21 | + join(here, "xai", "store.ts"), |
| 22 | + join(here, "..", "mcp", "auth-store.ts"), |
| 23 | +]; |
| 24 | + |
| 25 | +async function scanStoreSources(): Promise<Map<string, string>> { |
| 26 | + const sources = new Map<string, string>(); |
| 27 | + const glob = new Glob("**/*.ts"); |
| 28 | + for await (const entry of glob.scan({ cwd: here, absolute: true })) { |
| 29 | + if (entry.endsWith(".test.ts")) continue; |
| 30 | + sources.set(entry, await Bun.file(entry).text()); |
| 31 | + } |
| 32 | + for (const file of STORE_FILES) { |
| 33 | + if (!sources.has(file)) sources.set(file, await Bun.file(file).text()); |
| 34 | + } |
| 35 | + return sources; |
| 36 | +} |
| 37 | + |
| 38 | +function authFileLiterals(source: string): string[] { |
| 39 | + const found: string[] = []; |
| 40 | + const pattern = /["']([A-Za-z0-9_.-]+-auth\.json)["']/g; |
| 41 | + let match: RegExpExecArray | null; |
| 42 | + while ((match = pattern.exec(source)) !== null) { |
| 43 | + const literal = match[1]; |
| 44 | + if (literal !== undefined && !found.includes(literal)) found.push(literal); |
| 45 | + } |
| 46 | + return found; |
| 47 | +} |
| 48 | + |
| 49 | +describe("CL-7789 credential-surface coverage", () => { |
| 50 | + test("every *-auth.json literal in auth-owned stores is denied", async () => { |
| 51 | + const sources = await scanStoreSources(); |
| 52 | + const patterns = buildCredentialPatterns(); |
| 53 | + const seen = new Set<string>(); |
| 54 | + for (const source of sources.values()) { |
| 55 | + for (const literal of authFileLiterals(source)) { |
| 56 | + seen.add(literal); |
| 57 | + const probe = join("~", ".corbits", literal); |
| 58 | + expect( |
| 59 | + patterns.some((pattern) => pattern.test(probe)), |
| 60 | + `${literal} has no denylist pattern`, |
| 61 | + ).toBe(true); |
| 62 | + } |
| 63 | + } |
| 64 | + expect([...seen].sort()).toEqual( |
| 65 | + [CODEX_AUTH_FILENAME, XAI_AUTH_FILENAME].sort(), |
| 66 | + ); |
| 67 | + }); |
| 68 | + |
| 69 | + test("every registry descriptor resolves back to a store literal", async () => { |
| 70 | + const sources = await scanStoreSources(); |
| 71 | + const texts = [...sources.values()]; |
| 72 | + for (const { filename } of credentialFileDescriptors) { |
| 73 | + expect( |
| 74 | + texts.some((source) => source.includes(`"${filename}"`)), |
| 75 | + `${filename} is registered but no store writes it`, |
| 76 | + ).toBe(true); |
| 77 | + } |
| 78 | + for (const { dirname } of credentialDirDescriptors) { |
| 79 | + expect( |
| 80 | + texts.some((source) => source.includes(`"${dirname}"`)), |
| 81 | + `${dirname} is registered but no store writes it`, |
| 82 | + ).toBe(true); |
| 83 | + } |
| 84 | + expect(texts.some((source) => source.includes(MCP_AUTH_DIRNAME))).toBe( |
| 85 | + true, |
| 86 | + ); |
| 87 | + }); |
| 88 | +}); |
0 commit comments