Spaces:
Running
Running
| /** | |
| * Native/WASM module supply-chain gate. | |
| * | |
| * Verifies the trust invariants documented in .github/SECURITY.md for the | |
| * project's native and WebAssembly dependencies: | |
| * | |
| * 1. Every tracked module is pinned to an exact version in package.json | |
| * (no caret/tilde range a later publish could slide into). | |
| * 2. package-lock.json resolves it to that exact version with an | |
| * integrity hash. | |
| * 3. Every package in the lockfile that ships an install script has an | |
| * explicit entry in package.json#allowScripts β no unreviewed script, | |
| * whether allowed or denied. | |
| * 4. `npm audit signatures` reports no invalid or missing registry | |
| * signature for a tracked module. | |
| * | |
| * Fails loudly (non-zero exit, one line per problem) on a missing or | |
| * mismatched entry. | |
| */ | |
| const { spawnSync } = require("node:child_process"); | |
| const fs = require("node:fs"); | |
| const path = require("node:path"); | |
| /** | |
| * Direct dependencies whose payload is native code or WebAssembly rather | |
| * than auditable JavaScript. Kept in sync with the inventory table in | |
| * .github/SECURITY.md. | |
| */ | |
| const NATIVE_MODULES = [ | |
| "@huggingface/tokenizers", | |
| "@moonshine-ai/moonshine-wasm", | |
| "@wllama/wllama", | |
| "hash-wasm", | |
| "onnxruntime-node", | |
| ]; | |
| // A single exact version, optionally with a prerelease tag. Anything with a | |
| // range operator is rejected: native/WASM deps must be reviewed per version. | |
| const EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; | |
| // The two key shapes `npm approve-scripts` / `npm deny-scripts` write: | |
| // a bare name (covers every version) or an exact `name@version` pin. | |
| function policyCovers(allowScripts, name, version) { | |
| return ( | |
| Object.hasOwn(allowScripts, name) || | |
| Object.hasOwn(allowScripts, `${name}@${version}`) | |
| ); | |
| } | |
| function checkPins(pkg, problems) { | |
| for (const name of NATIVE_MODULES) { | |
| const spec = pkg.dependencies?.[name]; | |
| if (spec === undefined) { | |
| problems.push(`${name}: not a direct dependency of this project`); | |
| } else if (!EXACT_VERSION.test(spec)) { | |
| problems.push( | |
| `${name}: "${spec}" is not an exact pin; native/WASM deps must declare a single version`, | |
| ); | |
| } | |
| } | |
| } | |
| function checkLock(lock, pkg, problems) { | |
| for (const name of NATIVE_MODULES) { | |
| const spec = pkg.dependencies?.[name]; | |
| if (typeof spec !== "string" || !EXACT_VERSION.test(spec)) { | |
| continue; // already reported by checkPins | |
| } | |
| const entry = lock.packages?.[`node_modules/${name}`]; | |
| if (!entry) { | |
| problems.push(`${name}@${spec}: missing from package-lock.json`); | |
| continue; | |
| } | |
| if (entry.version !== spec) { | |
| problems.push( | |
| `${name}: package.json pins ${spec} but the lockfile resolves ${entry.version}`, | |
| ); | |
| } | |
| if (!entry.integrity) { | |
| problems.push( | |
| `${name}@${entry.version}: lockfile entry has no integrity hash`, | |
| ); | |
| } | |
| } | |
| } | |
| function checkInstallScriptPolicy(lock, allowScripts, problems) { | |
| for (const [key, entry] of Object.entries(lock.packages ?? {})) { | |
| if (key === "" || !entry.hasInstallScript) continue; | |
| const name = key.split("node_modules/").pop(); | |
| if (!policyCovers(allowScripts, name, entry.version)) { | |
| problems.push( | |
| `${name}@${entry.version}: ships an install script with no entry in package.json#allowScripts ` + | |
| `(review it, then \`npm approve-scripts ${name}\` or \`npm deny-scripts ${name}\`)`, | |
| ); | |
| } | |
| } | |
| } | |
| function checkRegistrySignatures(rootDir, problems) { | |
| const res = spawnSync("npm", ["audit", "signatures", "--json"], { | |
| cwd: rootDir, | |
| encoding: "utf8", | |
| maxBuffer: 64 * 1024 * 1024, | |
| }); | |
| if (res.error) { | |
| problems.push( | |
| `npm audit signatures could not be run: ${res.error.message}`, | |
| ); | |
| return; | |
| } | |
| let report; | |
| try { | |
| report = JSON.parse(res.stdout); | |
| } catch { | |
| problems.push( | |
| `npm audit signatures produced no parseable report (exit ${res.status}); ` + | |
| "the registry may be unreachable β treat as unverified", | |
| ); | |
| return; | |
| } | |
| for (const [kind, items] of [ | |
| ["invalid", report.invalid ?? []], | |
| ["missing", report.missing ?? []], | |
| ]) { | |
| for (const item of items) { | |
| if (NATIVE_MODULES.includes(item.name)) { | |
| problems.push( | |
| `${item.name}@${item.version}: ${kind} registry signature`, | |
| ); | |
| } else { | |
| console.log( | |
| `note: ${item.name}@${item.version} has a ${kind} registry signature ` + | |
| "(outside this gate's native/WASM scope; see `npm audit signatures`)", | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * Runs every check against a project root and returns the process exit code. | |
| * | |
| * @param {string} rootDir Project root containing package.json, | |
| * package-lock.json and an installed node_modules tree. | |
| * @returns {number} 0 when all invariants hold, 1 otherwise. | |
| */ | |
| function run(rootDir) { | |
| const pkg = JSON.parse( | |
| fs.readFileSync(path.join(rootDir, "package.json"), "utf8"), | |
| ); | |
| const lock = JSON.parse( | |
| fs.readFileSync(path.join(rootDir, "package-lock.json"), "utf8"), | |
| ); | |
| const problems = []; | |
| checkPins(pkg, problems); | |
| checkLock(lock, pkg, problems); | |
| checkInstallScriptPolicy(lock, pkg.allowScripts ?? {}, problems); | |
| if (fs.existsSync(path.join(rootDir, "node_modules"))) { | |
| checkRegistrySignatures(rootDir, problems); | |
| } else { | |
| problems.push( | |
| "node_modules is missing; run `npm ci` before the integrity check", | |
| ); | |
| } | |
| if (problems.length > 0) { | |
| for (const problem of problems) { | |
| console.log(`β ${problem}`); | |
| } | |
| console.log( | |
| `\n${problems.length} native-module integrity problem(s) found (of ${NATIVE_MODULES.length} tracked modules)`, | |
| ); | |
| return 1; | |
| } | |
| console.log( | |
| `β All ${NATIVE_MODULES.length} tracked native/WASM modules are exactly pinned, locked with integrity hashes, covered by the install-script policy, and free of invalid or missing registry signatures`, | |
| ); | |
| return 0; | |
| } | |
| if (require.main === module) { | |
| const rootDirArg = process.argv[2]; | |
| const usage = "Usage: node scripts/native-module-integrity.cjs [rootDir]"; | |
| if (rootDirArg?.startsWith("-")) { | |
| console.error(`β Unknown option: ${rootDirArg}\n ${usage}`); | |
| process.exit(1); | |
| } | |
| if (rootDirArg && !fs.existsSync(rootDirArg)) { | |
| console.error(`β Directory not found: ${rootDirArg}`); | |
| process.exit(1); | |
| } | |
| process.exit(run(rootDirArg || path.resolve(__dirname, ".."))); | |
| } | |
| module.exports = { run, NATIVE_MODULES }; | |