import { readFile } from "node:fs/promises"; import { describe, expect, it } from "vitest"; import { diffDependencyInventories, isValidSha512Integrity, parsePnpmLockfilePackages, supplyChainDigest, validateDependencyReview, validateLicensePolicy, } from "../../scripts/lib/supply-chain.ts"; import { digestReleaseInputFiles } from "../../scripts/lib/release-input-evidence.ts"; import { findSecretMatches } from "../../scripts/lib/secret-scan.ts"; import { parseSecretScanIncludedPaths, selectIncludedInventoryFiles, } from "../../scripts/lib/secret-scan-policy.ts"; import { checkSecurityFixtures } from "../../scripts/lib/security-fixture-check.ts"; const integrity = `sha512-${Buffer.alloc(64, 7).toString("base64")}`; const dependency = { name: "fixture", version: "1.0.0", direct: true, scope: "production", optional: false, license: "MIT", integrity, dependencies: [], }; describe("supply-chain policy", () => { it.each([ ["empty", []], ["empty entry", [""]], ["blank entry", [" "]], ["absolute", ["/src"]], ["backslash", ["src\\file.ts"]], ["dot", ["."]], ["dotdot", [".."]], ["traversal", ["src/../docs"]], ["trailing slash", ["src/"]], ["mixed", ["src", 42]], ["duplicate", ["src", "src"]], ])("rejects %s secret-scan include paths", (_name, includedPaths) => { expect(() => parseSecretScanIncludedPaths(includedPaths)).toThrow(); }); it("requires every configured include path to match the inventory", () => { expect( selectIncludedInventoryFiles( ["README.md", "src/app.ts"], ["src"], ), ).toEqual(["src/app.ts"]); expect(() => selectIncludedInventoryFiles( ["README.md", "src/app.ts"], ["misspelled"], ), ).toThrow(/misspelled/u); expect( selectIncludedInventoryFiles( ["README.md", "src/app.ts"], null, ), ).toEqual(["README.md", "src/app.ts"]); }); it("rejects a crashed fixture scan and cannot reuse a stale repository artifact", async () => { const cleaned: string[] = []; await expect( checkSecurityFixtures({ createTempDirectory: async () => "/tmp/fresh-security-fixture", runScan: () => ({ status: 1, signal: null, stdout: "", stderr: "Security scan found 3 blocking result(s).\n", }), readArtifact: async (artifactPath) => { expect(artifactPath).toBe( "/tmp/fresh-security-fixture/scan-fixture.sarif", ); throw Object.assign(new Error("fresh artifact missing"), { code: "ENOENT", }); }, cleanup: async (directory) => { cleaned.push(directory); }, }), ).rejects.toThrow(/fresh artifact missing/u); expect(cleaned).toEqual(["/tmp/fresh-security-fixture"]); await expect( checkSecurityFixtures({ createTempDirectory: async () => "/tmp/fresh-security-fixture", runScan: () => ({ status: null, signal: "SIGTERM", stdout: "", stderr: "Security scan found 3 blocking result(s).\n", }), readArtifact: async () => "{}", cleanup: async () => undefined, }), ).rejects.toThrow(/did not fail exactly/u); }); it("wires the exact security fixture checker as a passing CI gate", async () => { const gates = JSON.parse(await readFile("config/ci/gates.json", "utf8")) as { gates: Record; }; const securityGate = gates.gates["FE-GATE-013"]!; expect(securityGate.steps).toContainEqual({ script: "check:security:fixtures", expect: "pass", }); expect(securityGate.steps).not.toEqual( expect.arrayContaining([ expect.objectContaining({ script: "scan:security:fixture" }), ]), ); expect(securityGate.evidence).not.toContain( "artifacts/security/scan-fixture.sarif", ); }); it("uses one fail-closed repository inventory for provenance and secret scanning", async () => { const [provenanceSource, securitySource] = await Promise.all([ readFile("scripts/generate-supply-chain.ts", "utf8"), readFile("scripts/security-scan.ts", "utf8"), ]); for (const source of [provenanceSource, securitySource]) { expect(source).toContain("buildRepositoryFileInventory"); expect(source).not.toContain("async function filesWithin"); } }); it("binds provenance digest behavior to tracked files outside policy roots", async () => { const contents = new Map([ ["src/app.ts", Buffer.from("app\n")], ["README.md", Buffer.from("one\n")], ]); const first = await digestReleaseInputFiles( ["README.md", "src/app.ts"], async (file) => contents.get(file)!, ); contents.set("README.md", Buffer.from("two\n")); const second = await digestReleaseInputFiles( ["README.md", "src/app.ts"], async (file) => contents.get(file)!, ); expect(second).not.toBe(first); }); it("detects every forbidden secret fixture, including quoted JSON keys", async () => { const fixtureRoot = "tests/fixtures/security/secret-detection/forbidden"; const findings = ( await Promise.all( ["source.ts", "dist.ts", "config.json"].map(async (file) => findSecretMatches( `${fixtureRoot}/${file}`, await readFile(`${fixtureRoot}/${file}`, "utf8"), ), ), ) ).flat(); expect(findings.map((finding) => [finding.file, finding.ruleId])).toEqual([ [`${fixtureRoot}/source.ts`, "aws-access-key"], [`${fixtureRoot}/dist.ts`, "assigned-secret"], [`${fixtureRoot}/config.json`, "assigned-secret"], ]); }); it("covers every mandatory release input in the secret scan policy", async () => { const policy = JSON.parse( await readFile("config/security/secret-scan-policy.json", "utf8"), ) as { trackedRoots: string[] }; expect(policy.trackedRoots).toEqual( expect.arrayContaining([ "index.html", ".dependency-cruiser.json", ".nvmrc", ".npmrc", "eslint.config.ts", "package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", "scripts", "schemas", "config", ".gitea/workflows/quality-gates.yml", "vite.config.ts", "vite.service-worker.config.ts", "vitest.config.ts", "playwright.config.ts", "playwright.capabilities.config.ts", "playwright.dev.config.ts", "playwright.storybook.config.ts", "playwright.visual.config.ts", "tsconfig.json", "tsconfig.app.json", "tsconfig.base.json", "tsconfig.node.json", "tsconfig.recipes.json", "tsconfig.service-worker.json", "tsconfig.test.json", "tsconfig.web-worker.json", ]), ); }); it("parses every top-level lockfile package and validates SRI", () => { const parsed = parsePnpmLockfilePackages(` packages: '@scope/one@1.0.0': resolution: {integrity: ${integrity}} two@2.0.0: resolution: {integrity: ${integrity}} snapshots: `); expect(parsed).toEqual([ { name: "@scope/one", version: "1.0.0", integrity }, { name: "two", version: "2.0.0", integrity }, ]); expect(parsed.every((entry) => isValidSha512Integrity(entry.integrity))).toBe( true, ); }); it("keeps inventory digests stable when dependency ordering changes", () => { const other = { ...dependency, name: "other" }; expect(supplyChainDigest([dependency, other])).toBe( supplyChainDigest([other, dependency]), ); }); it("calculates actual additions and requires independent high-risk review", () => { const before = { dependencies: [] }; const after = { dependencies: [dependency] }; const diff = diffDependencyInventories(before, after); expect(diff.added).toEqual(["fixture@1.0.0"]); expect( validateDependencyReview(diff, after, { changes: [ { changeId: "add:fixture@1.0.0", owner: "one", reviewer: "one", reason: "fixture", rollback: "remove", }, ], }).passed, ).toBe(false); }); it("allows explicit policy licenses and rejects denied licenses", () => { expect( validateLicensePolicy( { dependencies: [dependency] }, { allowedLicenses: ["MIT"], deniedLicensePatterns: ["AGPL"] }, ).passed, ).toBe(true); expect( validateLicensePolicy( { dependencies: [{ ...dependency, license: "AGPL-3.0" }], }, { allowedLicenses: ["MIT"], deniedLicensePatterns: ["AGPL"] }, ).passed, ).toBe(false); }); });