1
0
This repository has been archived on 2026-08-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
tera/scripts/check-dependency-licenses.mjs
T

65 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
/**
* Lockfile license gate for every installed package, including workspaces.
*
* The allowed set is intentionally small and explicit. A new license is a
* review event, not a string this script tries to interpret optimistically.
* This does not replace third-party notices; it prevents a dependency update
* from quietly introducing terms outside Tera's permissive distribution model.
*/
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const lock = JSON.parse(readFileSync(resolve(root, "package-lock.json"), "utf8"));
const allowed = new Set(["Apache-2.0", "BSD-3-Clause", "ISC", "MIT"]);
const problems = [];
const counts = new Map();
for (const [path, entry] of Object.entries(lock.packages ?? {})) {
if (path === "") continue;
let license = entry.license;
if (!license && entry.link === true && typeof entry.resolved === "string") {
try {
const workspace = JSON.parse(
readFileSync(resolve(root, entry.resolved, "package.json"), "utf8"),
);
license = workspace.license;
} catch (error) {
problems.push(`${path}: could not read linked workspace license (${String(error)})`);
continue;
}
}
if (typeof license !== "string" || license.length === 0) {
problems.push(`${path}: no license recorded in the lockfile or linked workspace`);
continue;
}
if (!allowed.has(license)) {
problems.push(`${path}: ${license} is not in the reviewed allowlist`);
continue;
}
counts.set(license, (counts.get(license) ?? 0) + 1);
const resolved = entry.resolved;
if (typeof resolved === "string" && /^(?:git\+|github:|gitlab:|bitbucket:)/i.test(resolved)) {
problems.push(`${path}: source dependency ${resolved} is not a registry artifact`);
}
}
if (problems.length > 0) {
console.error("\ncheck-dependency-licenses: FAIL\n");
for (const problem of problems) console.error(` ${problem}`);
console.error(`\nReviewed allowlist: ${[...allowed].join(", ")}\n`);
process.exit(1);
}
const total = [...counts.values()].reduce((sum, count) => sum + count, 0);
console.log(`check-dependency-licenses: ok — ${total} locked packages reviewed.`);
for (const license of [...counts.keys()].sort()) {
console.log(` ${license}: ${counts.get(license)}`);
}