Files

42 lines
2.2 KiB
JavaScript
Raw Permalink Normal View History

// 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 }),
);