feat: add multi-engine regex flavour support
This commit is contained in:
199
scripts/cpp-engine-pack.test.ts
Normal file
199
scripts/cpp-engine-pack.test.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
// @vitest-environment node
|
||||
|
||||
import { createHash } from "node:crypto";
|
||||
import { cp, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { writeEngineChecksums } from "./checksummed-engine-pack.mjs";
|
||||
import { CPP_LOCK, verifyCppPack } from "./cpp-engine-pack.mjs";
|
||||
|
||||
const temporaryDirectories: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
temporaryDirectories
|
||||
.splice(0)
|
||||
.map((directory) => rm(directory, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
describe("C++ engine-pack gate", () => {
|
||||
it("verifies the installed exact Emscripten/libc++ pack and bridge sources", async () => {
|
||||
await expect(
|
||||
verifyCppPack(path.resolve("public", "engines", "cpp")),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
engineVersion: "Emscripten 6.0.4 libc++ std::wregex",
|
||||
bridge: expect.objectContaining({
|
||||
abiVersion: 1,
|
||||
dynamicExecutionDisabled: true,
|
||||
replacement: {
|
||||
semantics: "libc++ match_results::format default grammar",
|
||||
implementation:
|
||||
"bounded streaming expansion without materializing an unbounded native format result",
|
||||
paritySelfTest:
|
||||
"load-time fixtures compare the bounded expander with libc++ match_results::format",
|
||||
},
|
||||
}),
|
||||
toolchain: expect.objectContaining({
|
||||
version: "6.0.4",
|
||||
commitSha1: "fe5be6afdff43ad58860d821fcc8572a23f92d19",
|
||||
emsdkCommitSha1: "224ec5f9f2f72f09f9ce0e26d66bae7dbd8b692f",
|
||||
releaseCommitSha1: "b23272fac5d05617cd36dc451356dca0f79bf22d",
|
||||
llvmVersion: "24.0.0git",
|
||||
llvmCommitSha1: "c050c487e9edb97ef44f53cb29fe1d8bcddb8f76",
|
||||
}),
|
||||
licensing: {
|
||||
sourceManifest: "SOURCE-MANIFEST.json",
|
||||
linkedComponentCount: 6,
|
||||
auditedExclusions: ["libunwind"],
|
||||
independentlyPinnedLegalFiles: 6,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("pins exception-enabled compilation and its exact traced native component set", async () => {
|
||||
expect(CPP_LOCK.emscriptenVersion).toBe("6.0.4");
|
||||
expect(CPP_LOCK.linkedArchives).toEqual([
|
||||
"libc++.a",
|
||||
"libc++abi.a",
|
||||
"libc.a",
|
||||
"libclang_rt.builtins.a",
|
||||
"libembind-rtti.a",
|
||||
"libemmalloc.a",
|
||||
"libnoexit.a",
|
||||
"libstubs.a",
|
||||
]);
|
||||
const metadata = JSON.parse(
|
||||
await readFile(
|
||||
path.resolve("public", "engines", "cpp", "engine-metadata.json"),
|
||||
"utf8",
|
||||
),
|
||||
) as { toolchain: { command: string } };
|
||||
expect(metadata.toolchain.command).toContain("-fexceptions");
|
||||
expect(metadata.toolchain.command).toContain("-sMALLOC=emmalloc");
|
||||
expect(metadata.toolchain.command).toContain("-Wl,--trace");
|
||||
|
||||
const sourceManifest = JSON.parse(
|
||||
await readFile(
|
||||
path.resolve("public", "engines", "cpp", "SOURCE-MANIFEST.json"),
|
||||
"utf8",
|
||||
),
|
||||
) as {
|
||||
buildSelection: { exactLinkedArchives: string[] };
|
||||
sourceEvidence: { sourcePath: string; sourceSha256: string }[];
|
||||
linkedComponents: {
|
||||
id: string;
|
||||
linked: boolean;
|
||||
legalFiles: string[];
|
||||
}[];
|
||||
};
|
||||
expect(sourceManifest.buildSelection.exactLinkedArchives).toEqual(
|
||||
CPP_LOCK.linkedArchives,
|
||||
);
|
||||
expect(sourceManifest.sourceEvidence).toContainEqual({
|
||||
sourcePath: "system/lib/emmalloc.c",
|
||||
sourceSha256:
|
||||
"00eb577cbef51a3359c309f45a7c99a814b8c6151ab75c9a3c78a56f0169146b",
|
||||
});
|
||||
expect(
|
||||
sourceManifest.linkedComponents
|
||||
.filter(({ linked }) => linked)
|
||||
.map(({ id }) => id),
|
||||
).toEqual([
|
||||
"emscripten-runtime",
|
||||
"musl",
|
||||
"emmalloc",
|
||||
"compiler-rt",
|
||||
"libc++",
|
||||
"libc++abi",
|
||||
]);
|
||||
expect(
|
||||
sourceManifest.linkedComponents.find(({ id }) => id === "libunwind"),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
linked: false,
|
||||
legalFiles: ["LICENSE-libunwind.txt"],
|
||||
}),
|
||||
);
|
||||
|
||||
const module = await readFile(
|
||||
path.resolve("public", "engines", "cpp", "cpp-regex.mjs"),
|
||||
"utf8",
|
||||
);
|
||||
expect(module).not.toContain("new Function");
|
||||
expect(module).not.toMatch(/\beval\s*\(/u);
|
||||
});
|
||||
|
||||
it("rejects substituted legal text even when self-reported checksums are regenerated", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "regex-cpp-pack-"));
|
||||
temporaryDirectories.push(directory);
|
||||
const pack = path.join(directory, "cpp");
|
||||
await cp(path.resolve("public", "engines", "cpp"), pack, {
|
||||
recursive: true,
|
||||
});
|
||||
const replacement = Buffer.from("substituted legal text\n");
|
||||
await writeFile(path.join(pack, "LICENSE-Emscripten.txt"), replacement);
|
||||
const metadataFile = path.join(pack, "engine-metadata.json");
|
||||
const metadata = JSON.parse(await readFile(metadataFile, "utf8")) as {
|
||||
files: { path: string; sha256: string; bytes: number }[];
|
||||
};
|
||||
const record = metadata.files.find(
|
||||
({ path: name }) => name === "LICENSE-Emscripten.txt",
|
||||
);
|
||||
expect(record).toBeDefined();
|
||||
if (!record) return;
|
||||
record.sha256 = createHash("sha256").update(replacement).digest("hex");
|
||||
record.bytes = replacement.byteLength;
|
||||
await writeFile(metadataFile, `${JSON.stringify(metadata, null, 2)}\n`);
|
||||
await writeEngineChecksums(pack);
|
||||
|
||||
await expect(verifyCppPack(pack)).rejects.toThrow(
|
||||
/metadata drifted from its pinned sources/u,
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects a forged source inventory even when self-reported checksums are regenerated", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "regex-cpp-pack-"));
|
||||
temporaryDirectories.push(directory);
|
||||
const pack = path.join(directory, "cpp");
|
||||
await cp(path.resolve("public", "engines", "cpp"), pack, {
|
||||
recursive: true,
|
||||
});
|
||||
const sourceManifestFile = path.join(pack, "SOURCE-MANIFEST.json");
|
||||
const sourceManifest = JSON.parse(
|
||||
await readFile(sourceManifestFile, "utf8"),
|
||||
) as {
|
||||
linkedComponents: { id: string; linked: boolean }[];
|
||||
};
|
||||
const libunwind = sourceManifest.linkedComponents.find(
|
||||
({ id }) => id === "libunwind",
|
||||
);
|
||||
expect(libunwind).toBeDefined();
|
||||
if (!libunwind) return;
|
||||
libunwind.linked = true;
|
||||
const replacement = Buffer.from(
|
||||
`${JSON.stringify(sourceManifest, null, 2)}\n`,
|
||||
);
|
||||
await writeFile(sourceManifestFile, replacement);
|
||||
const metadataFile = path.join(pack, "engine-metadata.json");
|
||||
const metadata = JSON.parse(await readFile(metadataFile, "utf8")) as {
|
||||
files: { path: string; sha256: string; bytes: number }[];
|
||||
};
|
||||
const record = metadata.files.find(
|
||||
({ path: name }) => name === "SOURCE-MANIFEST.json",
|
||||
);
|
||||
expect(record).toBeDefined();
|
||||
if (!record) return;
|
||||
record.sha256 = createHash("sha256").update(replacement).digest("hex");
|
||||
record.bytes = replacement.byteLength;
|
||||
await writeFile(metadataFile, `${JSON.stringify(metadata, null, 2)}\n`);
|
||||
await writeEngineChecksums(pack);
|
||||
|
||||
await expect(verifyCppPack(pack)).rejects.toThrow(
|
||||
/metadata drifted from its pinned sources/u,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user