import { readFile, writeFile } from "node:fs/promises"; import { pathToFileURL } from "node:url"; export function matchReports(request) { const [a, b] = request.reports ?? []; if ( !a || !b || a.workerId !== "worker-a" || b.workerId !== "worker-b" || a.imageDigest === b.imageDigest || a.toolchain === b.toolchain || a.inputDigest !== b.inputDigest || a.checkId !== b.checkId || a.normalizedOutputDigest !== b.normalizedOutputDigest || JSON.stringify(a.normalizedMembers) !== JSON.stringify(b.normalizedMembers) || a.verdict !== "pass" || b.verdict !== "pass" ) throw new Error("Independent worker evidence does not agree and pass."); const rules = request.rules; if (!Array.isArray(rules) || rules.length === 0) throw new Error("Matcher rules are required."); const appliedRuleIds = rules .map((rule) => rule.id) .sort((left, right) => Buffer.from(left).compare(Buffer.from(right))); if ( new Set(appliedRuleIds).size !== appliedRuleIds.length || rules.some((rule) => !Array.isArray(rule.deniedMemberDigests)) ) throw new Error("Matcher rules are invalid."); const denied = new Set(rules.flatMap((rule) => rule.deniedMemberDigests)); if (a.normalizedMembers.some((member) => denied.has(member))) throw new Error("Privacy rule matched normalized evidence."); return { schema: "portfolio-privacy-matcher-result/v1", inputDigest: a.inputDigest, checkId: a.checkId, normalizedOutputDigest: a.normalizedOutputDigest, normalizedMembers: a.normalizedMembers, ruleSetDigest: request.ruleSetDigest, appliedRuleIds, verdict: "pass", workerImageDigests: [a.imageDigest, b.imageDigest], }; } async function main() { const result = matchReports( JSON.parse(await readFile("/input/request.json", "utf8")), ); await writeFile("/output/result.json", JSON.stringify(result), { flag: "wx", mode: 0o400, }); } if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) await main();