135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
// @vitest-environment node
|
|
|
|
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 { verifyPythonPack } from "./python-engine-pack.mjs";
|
|
import {
|
|
PYTHON_LEGAL_RESOURCES,
|
|
PYTHON_SOURCE_MANIFEST_BASE,
|
|
} from "./python-engine-provenance.mjs";
|
|
|
|
const temporaryDirectories: string[] = [];
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
temporaryDirectories
|
|
.splice(0)
|
|
.map((directory) => rm(directory, { recursive: true, force: true })),
|
|
);
|
|
});
|
|
|
|
describe("Python engine-pack provenance gate", () => {
|
|
it("pins the complete base-runtime source, patch, and legal closure", () => {
|
|
expect(PYTHON_LEGAL_RESOURCES.map(({ output }) => output)).toEqual([
|
|
"LICENSE.pyodide.txt",
|
|
"LICENSE.pyodide-stacktrace-vendors.txt",
|
|
"LICENSE.cpython.txt",
|
|
"NOTICE.cpython-bundled.rst",
|
|
"LICENSE.expat.txt",
|
|
"LICENSE.libmpdec.txt",
|
|
"LICENSE.hacl-mit.txt",
|
|
"LICENSE.libffi.txt",
|
|
"LICENSE.hiwire.txt",
|
|
"LICENSE.xz.txt",
|
|
"LICENSE.zstd.txt",
|
|
"LICENSE.sqlite.txt",
|
|
"LICENSE.bzip2.txt",
|
|
"LICENSE.zlib.txt",
|
|
"LICENSE.emscripten.txt",
|
|
"NOTICE.emscripten-dlmalloc.txt",
|
|
"NOTICE.emscripten-musl.txt",
|
|
"LICENSE.llvm-compiler-rt.txt",
|
|
"LICENSE.llvm-libcxx.txt",
|
|
"LICENSE.llvm-libcxxabi.txt",
|
|
"LICENSE.llvm-libunwind.txt",
|
|
"LICENSE.emscripten-mini-lz4.txt",
|
|
]);
|
|
expect(PYTHON_SOURCE_MANIFEST_BASE.patches.cpython).toHaveLength(9);
|
|
expect(PYTHON_SOURCE_MANIFEST_BASE.patches.emscripten).toHaveLength(5);
|
|
expect(
|
|
PYTHON_SOURCE_MANIFEST_BASE.sourceInputs.map(({ id }) => id),
|
|
).toEqual([
|
|
"pyodide",
|
|
"pyodide-build",
|
|
"error-stack-parser",
|
|
"stackframe",
|
|
"cpython",
|
|
"libffi",
|
|
"hiwire",
|
|
"xz-liblzma",
|
|
"zstandard",
|
|
"sqlite",
|
|
"bzip2",
|
|
"zlib",
|
|
"emscripten",
|
|
"hacl-star-preferred-source",
|
|
]);
|
|
});
|
|
|
|
it("verifies the installed runtime and independently anchored inventory", async () => {
|
|
await expect(
|
|
verifyPythonPack(
|
|
path.resolve("public", "engines", "python"),
|
|
path.resolve(),
|
|
),
|
|
).resolves.toEqual(
|
|
expect.objectContaining({
|
|
engineVersion: "CPython 3.14.2 re",
|
|
runtime: "Pyodide 314.0.3",
|
|
source: expect.objectContaining({
|
|
manifest: expect.objectContaining({
|
|
path: "SOURCE-MANIFEST.json",
|
|
}),
|
|
}),
|
|
}),
|
|
);
|
|
}, 30_000);
|
|
|
|
it("rejects substituted legal material before runtime startup", async () => {
|
|
const directory = await mkdtemp(path.join(tmpdir(), "regex-python-pack-"));
|
|
temporaryDirectories.push(directory);
|
|
const pack = path.join(directory, "python");
|
|
await cp(path.resolve("public", "engines", "python"), pack, {
|
|
recursive: true,
|
|
});
|
|
await writeFile(
|
|
path.join(pack, "LICENSE.libffi.txt"),
|
|
"substituted legal text\n",
|
|
);
|
|
|
|
await expect(verifyPythonPack(pack, path.resolve())).rejects.toThrow(
|
|
/libffi legal material SHA-256 mismatch/u,
|
|
);
|
|
});
|
|
|
|
it("ships a manifest whose legal records match every pinned output", async () => {
|
|
const manifest = JSON.parse(
|
|
await readFile(
|
|
path.resolve("public", "engines", "python", "SOURCE-MANIFEST.json"),
|
|
"utf8",
|
|
),
|
|
) as {
|
|
legalFiles: {
|
|
path: string;
|
|
sha256: string;
|
|
sourceSha256: string;
|
|
}[];
|
|
};
|
|
expect(
|
|
manifest.legalFiles.map(({ path: file, sha256, sourceSha256 }) => ({
|
|
file,
|
|
sha256,
|
|
sourceSha256,
|
|
})),
|
|
).toEqual(
|
|
PYTHON_LEGAL_RESOURCES.map(({ output, outputSha256, sourceSha256 }) => ({
|
|
file: output,
|
|
sha256: outputSha256,
|
|
sourceSha256,
|
|
})),
|
|
);
|
|
});
|
|
});
|