1
0

feat: complete actor handoff and piloted aircraft presence

This commit is contained in:
2026-08-11 22:17:06 -07:00
parent 655c383061
commit 3326d2e6d0
20 changed files with 907 additions and 41 deletions
+8
View File
@@ -48,6 +48,14 @@ for (const [path, entry] of Object.entries(lock.packages ?? {})) {
if (typeof resolved === "string" && /^(?:git\+|github:|gitlab:|bitbucket:)/i.test(resolved)) {
problems.push(`${path}: source dependency ${resolved} is not a registry artifact`);
}
if (path.startsWith("node_modules/") && entry.link !== true) {
if (typeof resolved !== "string" || !/^https:\/\/registry\.npmjs\.org\//.test(resolved)) {
problems.push(`${path}: dependency is not pinned to the npm registry in package-lock.json`);
}
if (typeof entry.integrity !== "string" || !/^sha(?:256|384|512)-/.test(entry.integrity)) {
problems.push(`${path}: dependency has no recognized lockfile integrity hash`);
}
}
}
if (problems.length > 0) {
+6
View File
@@ -44,6 +44,9 @@ const DENIED_EXTENSIONS = new Set([
".jpg",
".jpeg",
".webp",
".gif",
".svg",
".ico",
".hdr",
".exr",
".ttf",
@@ -52,6 +55,9 @@ const DENIED_EXTENSIONS = new Set([
".woff2",
".mp3",
".wav",
".ogg",
".mp4",
".webm",
".fbx",
".obj",
]);
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env node
/**
* Distribution provenance gate.
*
* Every tracked media/model/font artifact must be listed exactly once in
* PROVENANCE.json and match its recorded SHA-256. Original generated artifacts
* must name a tracked generator and lineage note. A copied item additionally
* needs an immutable upstream revision, exact upstream path, and intake record.
*/
import { createHash } from "node:crypto";
import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { dirname, extname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const manifestPath = resolve(root, "PROVENANCE.json");
const ARTIFACT_EXTENSIONS = new Set([
".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg", ".ico",
".glb", ".gltf", ".fbx", ".obj", ".hdr", ".exr",
".ttf", ".otf", ".woff", ".woff2",
".mp3", ".wav", ".ogg", ".mp4", ".webm",
]);
const FONT_EXTENSIONS = new Set([".ttf", ".otf", ".woff", ".woff2"]);
const ALLOWED_ARTIFACT_LICENSES = new Set([
"Apache-2.0", "BSD-3-Clause", "CC0-1.0", "CC-BY-4.0", "ISC", "MIT",
]);
const problems = [];
function trackedFiles() {
try {
return execFileSync("git", ["ls-files", "-z"], {
cwd: root,
encoding: "utf8",
maxBuffer: 64 * 1024 * 1024,
}).split("\0").filter(Boolean);
} catch {
console.error("check-provenance: FAIL — run this gate inside a git checkout.");
process.exit(1);
}
}
function nonEmpty(value) {
return typeof value === "string" && value.trim().length > 0;
}
function validDate(value) {
return typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value);
}
function hash(path) {
return createHash("sha256").update(readFileSync(resolve(root, path))).digest("hex");
}
function pathIsCovered(path, tracked) {
if (path.endsWith("/")) return [...tracked].some((candidate) => candidate.startsWith(path));
return tracked.has(path);
}
let manifest;
try {
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
} catch (error) {
console.error(`check-provenance: FAIL — cannot parse PROVENANCE.json (${String(error)}).`);
process.exit(1);
}
const tracked = new Set(trackedFiles());
const artifacts = [...tracked].filter((path) => ARTIFACT_EXTENSIONS.has(extname(path).toLowerCase()));
const records = Array.isArray(manifest.distributedArtifacts) ? manifest.distributedArtifacts : [];
const recordCounts = new Map();
if (manifest.schemaVersion !== 1) problems.push("schemaVersion must be 1");
if (!nonEmpty(manifest.projectLicense)) problems.push("projectLicense is required");
for (const [index, record] of records.entries()) {
const at = `distributedArtifacts[${index}]`;
if (!nonEmpty(record?.path)) {
problems.push(`${at}: path is required`);
continue;
}
recordCounts.set(record.path, (recordCounts.get(record.path) ?? 0) + 1);
if (!tracked.has(record.path)) problems.push(`${at}: ${record.path} is not a tracked file`);
if (!ARTIFACT_EXTENSIONS.has(extname(record.path).toLowerCase())) {
problems.push(`${at}: ${record.path} is not a recognized distribution artifact`);
}
if (!nonEmpty(record.kind)) problems.push(`${at}: kind is required`);
if (!ALLOWED_ARTIFACT_LICENSES.has(record.license)) {
problems.push(`${at}: license ${String(record.license)} is not in the reviewed allowlist`);
}
if (!/^[a-f0-9]{64}$/.test(record.sha256 ?? "")) problems.push(`${at}: sha256 must be 64 lowercase hex characters`);
else if (tracked.has(record.path) && hash(record.path) !== record.sha256) problems.push(`${at}: SHA-256 mismatch for ${record.path}`);
if (!validDate(record.intakeDate)) problems.push(`${at}: intakeDate must be YYYY-MM-DD`);
if (!nonEmpty(record.intakeNote)) problems.push(`${at}: intakeNote is required`);
if (record.origin === "repository-generated") {
if (!nonEmpty(record.generator) || !tracked.has(record.generator)) {
problems.push(`${at}: repository-generated artifact requires a tracked generator`);
}
if (!Array.isArray(record.inputs) || record.inputs.length === 0 ||
record.inputs.some((input) => !nonEmpty(input) || !tracked.has(input))) {
problems.push(`${at}: repository-generated artifact requires non-empty tracked inputs`);
}
if (record.source !== undefined) problems.push(`${at}: repository-generated artifact must not claim an upstream source`);
} else if (record.origin === "copied") {
const source = record.source;
if (!nonEmpty(source?.url) || !/^https:\/\//.test(source.url)) problems.push(`${at}: copied item requires an HTTPS source URL`);
if (!nonEmpty(source?.upstreamPath)) problems.push(`${at}: copied item requires its exact upstreamPath`);
if (!nonEmpty(source?.revision) || !/^[a-f0-9]{40,64}$/i.test(source.revision)) {
problems.push(`${at}: copied item requires an immutable 40-64 hex upstream revision`);
} else if (nonEmpty(source?.url) && !source.url.toLowerCase().includes(source.revision.toLowerCase())) {
problems.push(`${at}: copied item source URL must be pinned to its recorded revision`);
}
} else {
problems.push(`${at}: origin must be repository-generated or copied`);
}
}
for (const artifact of artifacts) {
const count = recordCounts.get(artifact) ?? 0;
if (count !== 1) problems.push(`${artifact}: expected exactly one manifest record, found ${count}`);
}
for (const [path, count] of recordCounts) {
if (count !== 1) problems.push(`${path}: duplicate manifest records (${count})`);
}
const lineage = Array.isArray(manifest.proceduralLineage) ? manifest.proceduralLineage : [];
if (lineage.length === 0) problems.push("proceduralLineage must contain at least one original-source record");
for (const [index, record] of lineage.entries()) {
const at = `proceduralLineage[${index}]`;
if (!nonEmpty(record?.path) || !pathIsCovered(record.path, tracked)) problems.push(`${at}: path must identify tracked source`);
if (record?.origin !== "original") problems.push(`${at}: origin must be original`);
if (!nonEmpty(record?.kind)) problems.push(`${at}: kind is required`);
if (record?.sourceLicense !== "Apache-2.0") problems.push(`${at}: sourceLicense must be Apache-2.0`);
if (!nonEmpty(record?.lineage)) problems.push(`${at}: lineage is required`);
}
const trackedFonts = artifacts.filter((path) => FONT_EXTENSIONS.has(extname(path).toLowerCase()));
const codeFiles = [...tracked].filter((path) =>
path !== "scripts/check-provenance.mjs" && /\.(?:css|html|js|mjs|ts|tsx)$/.test(path)
);
for (const path of codeFiles) {
const text = readFileSync(resolve(root, path), "utf8");
if (/@font-face\b/i.test(text) || /fonts\.(?:googleapis|gstatic)\.com/i.test(text)) {
problems.push(`${path}: bundled/remote web fonts are forbidden by the system-font policy`);
}
}
if (problems.length > 0) {
console.error("\ncheck-provenance: FAIL\n");
for (const problem of problems) console.error(` ${problem}`);
console.error("");
process.exit(1);
}
console.log(`check-provenance: ok — ${artifacts.length} tracked distribution artifacts are hash-manifested.`);
console.log(` ${records.filter((record) => record.origin === "copied").length} copied items; ${lineage.length} original procedural/data lineage records.`);
console.log(` ${trackedFonts.length} bundled fonts; system-font/no-remote-font policy verified.`);