Files
brainwave/scripts/verify-dependency-licenses.mjs
T
QiuSW de480ee9bb
verify / harness (push) Has been cancelled
chore: verify dependency licenses
2026-08-04 23:32:44 +08:00

76 lines
3.3 KiB
JavaScript

import { readFile } from "node:fs/promises";
import path from "node:path";
import { repositoryRoot } from "./repository-files.mjs";
const manifestPath = path.join(repositoryRoot, "config", "dependency-licenses.json");
const catalogPath = path.join(repositoryRoot, "gradle", "libs.versions.toml");
const wrapperPath = path.join(repositoryRoot, "gradle", "wrapper", "gradle-wrapper.properties");
const documentationPath = path.join(repositoryRoot, "docs", "dependency-licenses.md");
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
const catalog = await readFile(catalogPath, "utf8");
const wrapper = await readFile(wrapperPath, "utf8");
const documentation = await readFile(documentationPath, "utf8");
const failures = [];
if (manifest.schemaVersion !== 1) failures.push("manifest schemaVersion must be 1");
if (!Array.isArray(manifest.components) || manifest.components.length === 0) {
failures.push("manifest components must not be empty");
}
const allowedLicenses = new Set(["Apache-2.0", "BSD-3-Clause", "EPL-1.0"]);
const ids = new Set();
const coordinates = new Set();
for (const [index, component] of (manifest.components ?? []).entries()) {
const prefix = `components[${index}]`;
for (const field of ["id", "version", "scope", "license", "source"]) {
if (typeof component[field] !== "string" || component[field].trim() === "") {
failures.push(`${prefix}.${field} must be non-blank text`);
}
}
if (ids.has(component.id)) failures.push(`${prefix}.id must be unique`);
ids.add(component.id);
if (component.coordinates !== null) {
if (typeof component.coordinates !== "string" || component.coordinates.split(":").length !== 3) {
failures.push(`${prefix}.coordinates must be group:name:version or null`);
} else if (coordinates.has(component.coordinates)) {
failures.push(`${prefix}.coordinates must be unique`);
}
coordinates.add(component.coordinates);
}
if (!allowedLicenses.has(component.license)) failures.push(`${prefix}.license is not reviewed`);
try {
const url = new URL(component.source);
if (url.protocol !== "https:") throw new Error("not HTTPS");
} catch {
failures.push(`${prefix}.source must be an absolute HTTPS URL`);
}
if (!documentation.includes(component.id) ||
!documentation.includes(component.version) ||
!documentation.includes(component.license)) {
failures.push(`${prefix} is not represented in docs/dependency-licenses.md`);
}
}
const version = (name) => new RegExp(`^${name}\\s*=\\s*"([^"]+)"`, "mu").exec(catalog)?.[1];
const expectedVersions = new Map([
["gradle-wrapper", /gradle-([\d.]+)-bin\.zip/u.exec(wrapper)?.[1]],
["kotlin-gradle-plugin", version("kotlin")],
["kotlin-stdlib", version("kotlin")],
["junit4", version("junit")],
]);
for (const [id, expectedVersion] of expectedVersions) {
const component = manifest.components.find((candidate) => candidate.id === id);
if (!component || component.version !== expectedVersion) {
failures.push(`${id} license entry must match pinned version ${expectedVersion ?? "<missing>"}`);
}
}
if (failures.length > 0) {
console.error("Dependency-license verification failed:");
for (const failure of failures) console.error(`- ${failure}`);
process.exitCode = 1;
} else {
console.log(`Dependency-license manifest passed (${manifest.components.length} reviewed components).`);
}