/** * Spec-conformance tests for `openspec/specs/crypto-cipher/spec.md`. * * Pins structural scenarios that the per-primitive unit suites do not * cover directly: every AEAD has both `noble.ts` and `native.ts`, * every `*.select.ts` carries the GENERATED banner, every * `*.native.ts` is currently a `PrimitiveNotImplemented` stub * (runtime reflection of the dangerous-tier flip gate), the package * is in a consistent pre/post-Phase-0.5 vendoring state, and no * primitive source file consumes a CSPRNG (nonce-is-caller-supplied). */ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; import { describe, expect, it } from "@suaveplan/testing/runner"; const ROOT = join(__dirname, ".."); const SRC = join(ROOT, "src"); const PRIMITIVES = join(SRC, "primitives"); const AEAD_IDS = [ "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", ] as const; function* walk(dir: string): Generator { for (const entry of readdirSync(dir)) { const full = join(dir, entry); const st = statSync(full); if ( st.isDirectory() && !full.includes("node_modules") && !full.includes("dist") ) { yield* walk(full); } else if (full.endsWith(".ts") && !full.endsWith(".test.ts")) { yield full; } } } describe("crypto-cipher — universal AEAD primitive surface", () => { it("every AEAD id has its primitive directory", { timeout: 5000 }, () => { for (const id of AEAD_IDS) { expect(existsSync(join(PRIMITIVES, id))).toBe(true); } }); }); describe("crypto-cipher — per-primitive replaceability layout", () => { for (const id of AEAD_IDS) { it(`${id} has both noble.ts and native.ts impl files`, { timeout: 5000, }, () => { expect( existsSync( join( PRIMITIVES, id, "impl", `${id}.noble`, `${id}.noble.ts` ) ) ).toBe(true); expect( existsSync( join( PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts` ) ) ).toBe(true); }); it(`${id}.select.ts carries the GENERATED banner`, { timeout: 5000, }, () => { const sel = join(PRIMITIVES, id, `${id}.select`, `${id}.select.ts`); expect(existsSync(sel)).toBe(true); const c = readFileSync(sel, "utf8"); expect(c).toMatch(/GENERATED/); expect(c).toMatch(/DO NOT EDIT/); }); } }); describe("crypto-cipher — vendored noble source (Phase 0.5)", () => { it("is a Phase-0.5 forward gate; current state is pre-0.5 (noble dep + no vendored/)", { timeout: 5000, }, () => { const pkg = JSON.parse( readFileSync(join(ROOT, "package.json"), "utf8") ); const noblePresent = "@noble/ciphers" in (pkg.dependencies ?? {}) || "@noble/ciphers" in (pkg.peerDependencies ?? {}); const vendoredPresent = existsSync(join(SRC, "vendored")); const upstreamFile = existsSync(join(ROOT, "NOBLE_UPSTREAM.md")); const pre05 = noblePresent && !vendoredPresent && !upstreamFile; const post05 = !noblePresent && vendoredPresent && upstreamFile; expect(pre05 || post05).toBe(true); }); }); describe("crypto-cipher — constant-time and dangerous-tier reflection", () => { for (const id of AEAD_IDS) { it(`${id}.native.ts is currently a PrimitiveNotImplemented stub`, { timeout: 5000, }, () => { const src = readFileSync( join(PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts`), "utf8" ); expect(src).toMatch(/PrimitiveNotImplemented/); }); } it("every native is a stub today, so no AEAD has been flipped without an audit", { timeout: 5000, }, () => { const offenders: string[] = []; for (const id of AEAD_IDS) { const src = readFileSync( join(PRIMITIVES, id, "impl", `${id}.native`, `${id}.native.ts`), "utf8" ); if (!/PrimitiveNotImplemented/.test(src)) offenders.push(id); } expect(offenders).toEqual([]); }); }); describe("crypto-cipher — nonce is caller-supplied", () => { it("no primitive source file consumes a CSPRNG (no Math.random / crypto.getRandomValues / randomBytes)", { timeout: 5000, }, () => { const banned = [ /\bMath\.random\b/, /\bcrypto\.getRandomValues\b/, /\brandomBytes\b/, ]; const hits: string[] = []; for (const file of walk(SRC)) { const c = readFileSync(file, "utf8"); for (const re of banned) { if (re.test(c)) hits.push(`${file}: ${re}`); } } expect(hits).toEqual([]); }); });