Files
suaveplan/packages/security-stack/crypto/crypto-cipher/tests/spec-conformance.test.ts
2026-05-27 23:47:53 +01:00

156 lines
5.2 KiB
TypeScript

/**
* 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<string> {
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([]);
});
});