42 lines
2.2 KiB
JavaScript
42 lines
2.2 KiB
JavaScript
// An independent package check witnesses its contract and bytes, without
|
|||
|
|
// inventing a workspace or granting installation/activation authority.
|
||
|
|
import { readFile, writeFile } from "node:fs/promises";
|
||
|
|
import { createHash } from "node:crypto";
|
||
|
|
import { pathToFileURL } from "node:url";
|
||
|
|
import { join } from "node:path";
|
||
|
|
const [compilerPath, schemaPath, checksPath, output] = process.argv.slice(2);
|
||
|
|
const compiler = await import(pathToFileURL(compilerPath));
|
||
|
|
const schema = JSON.parse(await readFile(schemaPath, "utf8"));
|
||
|
|
const checks = JSON.parse(await readFile(checksPath, "utf8"));
|
||
|
|
const generator = createHash("sha256")
|
||
|
|
.update(await readFile(compilerPath))
|
||
|
|
.digest("hex");
|
||
|
|
const evidence = [];
|
||
|
|
for (const check of checks) {
|
||
|
|
const pkg = schema.packages.find((pkg) => pkg.revisionId === check.packageRevisionId);
|
||
|
|
if (!pkg) throw Error("Unknown checked package");
|
||
|
|
const contract = compiler.packageBuildContract(schema, pkg.revisionId);
|
||
|
|
const sourceDigest = compiler.hexDigest({ revision: pkg.revisionId, source: pkg.source });
|
||
|
|
const manifest = compiler.parsePackageArtifacts(
|
||
|
|
JSON.parse(await readFile(join(check.artifactPath, "share/quixos/package-artifacts.json"), "utf8")),
|
||
|
|
);
|
||
|
|
compiler.checkPackageCoverage(
|
||
|
|
{ ...contract.definition.package, bindingDigest: contract.digest, sourceDigest },
|
||
|
|
manifest,
|
||
|
|
);
|
||
|
|
const receipt = JSON.parse(await readFile(join(check.artifactPath, "share/quixos/build-receipt.json"), "utf8"));
|
||
|
|
const expected = compiler.expectedPackageReceipt(contract, manifest, sourceDigest, generator);
|
||
|
|
if (compiler.hexDigest(receipt) !== compiler.hexDigest(expected.receipt))
|
||
|
|
throw Error("Invalid package build receipt");
|
||
|
|
const read = await compiler.artifactFileReader({ [pkg.revisionId]: check.artifactPath });
|
||
|
|
await compiler.checkArtifactFiles(manifest, read);
|
||
|
|
for (const [file, bytes] of expected.sources)
|
||
|
|
if (!Buffer.from(bytes).equals(await read(pkg.revisionId, file, bytes.length)))
|
||
|
|
throw Error("Modified generated binding " + file);
|
||
|
|
evidence.push({ ...check, contract: contract.digest, sourceDigest, receipt });
|
||
|
|
}
|
||
|
|
await writeFile(
|
||
|
|
join(output, "package-checks.json"),
|
||
|
|
JSON.stringify({ codec: "camino-package-checks-v1", generator, packages: evidence }),
|
||
|
|
);
|