license-compatibility
Forhindre copyleft- eller inkompatible lisenser fra å komme inn i avhengighetstreet ditt.
Regeldetaljer
Section titled “Regeldetaljer”Når du kompilerer eller bundler avhengigheter inn i applikasjonen din, gjelder lisensvilkårene deres for det kombinerte verket. En enkelt GPL-avhengighet i et permissivt (MIT/Apache-2.0) prosjekt kan tvinge hele prosjektet til å ta i bruk copyleft-vilkår. Denne regelen sjekker alle direkte avhengigheter mot en tillatt-liste med permissive lisenser.
Eksempler på feil kode
Section titled “Eksempler på feil kode”{ "dependencies": { "zod": "^3.23.0" }, "devDependencies": { "readline-sync": "^1.4.10" }}Hvis readline-sync bruker GPL-3.0, utløses et brudd selv som devDependency.
Eksempler på riktig kode
Section titled “Eksempler på riktig kode”{ "dependencies": { "zod": "^3.23.0" }, "devDependencies": { "fast-check": "^4.7.0" }}Både zod (MIT) og fast-check (MIT) er på den permissive tillatt-listen.
Regelimplementasjon
Section titled “Regelimplementasjon”/// <reference path="../rules.d.ts" />
const ALLOWED_LICENSES = new Set([ "MIT", "Apache-2.0", "ISC", "BSD-2-Clause", "BSD-3-Clause", "0BSD", "CC0-1.0", "Unlicense", "BlueOak-1.0.0",]);
function isAllowed(license: string | undefined): boolean { if (!license) return false; if (ALLOWED_LICENSES.has(license)) return true;
// Handle SPDX OR expressions: at least one option must be allowed const normalized = license.trim().replace(/^\(/u, "").replace(/\)$/u, ""); if (ALLOWED_LICENSES.has(normalized)) return true;
if (normalized.includes(" OR ")) { return normalized.split(" OR ").some((l) => ALLOWED_LICENSES.has(l.trim())); }
return false;}
/** * Extract package name from a node_modules path. * Handles both regular and scoped (@scope/name) packages. */function extractPackageName(path: string): string { const parts = path.replaceAll("\\", "/").split("/"); const nmIdx = parts.lastIndexOf("node_modules"); if (nmIdx === -1) return path; const afterNm = parts.slice(nmIdx + 1); if (afterNm[0]?.startsWith("@") && afterNm.length >= 2) { return `${afterNm[0]}/${afterNm[1]}`; } return afterNm[0] ?? path;}
export default { rules: { "no-copyleft-deps": { description: "All dependencies (including transitive) must use permissive licenses", async check(ctx) { // Scan ALL packages in node_modules, direct AND transitive. // Brace expansion covers both regular and scoped packages. const pkgFiles = await ctx.glob("node_modules/{*,@*/*}/package.json");
const depResults = await Promise.all( pkgFiles.map(async (pkgPath) => { try { const depPkg = (await ctx.readJSON(pkgPath)) as { license?: string; }; return { dep: extractPackageName(pkgPath), license: depPkg.license, }; } catch { return null; } }) );
for (const result of depResults) { if (result === null) continue; if (!isAllowed(result.license)) { ctx.report.violation({ message: `Dependency "${result.dep}" has disallowed license: "${result.license ?? "(none)"}".`, file: "package.json", fix: `Remove "${result.dep}" or find an alternative with a permissive license.`, }); } } }, }, },} satisfies RuleSet;Tilpasning
Section titled “Tilpasning”- Endre tillatt-listen: Legg til eller fjern lisensidentifikatorer basert på prosjektets lisens. GPL-prosjekter kan tillate GPL-avhengigheter; Apache-2.0-prosjekter bør blokkere dem.
- Skann transitive avhengigheter (standard her): globben ovenfor går gjennom hver pakke installert på toppnivået av
node_modules/, inkludert scoped pakker — med npms eller Buns flate layout dekker det også transitive avhengigheter som er heist opp. To krav: ADR-en som inneholder regelen må setterespectGitignore: false, fordinode_modules/normalt er gitignorert ogctx.globrespekterer.gitignoresom standard; og nestedenode_modules-trær (pnpm-layouter, versjonskonflikter) krysses ikke — bytt mønsteret tilnode_modules/**/package.jsonfor å inkludere dem, på bekostning av atpackage.json-filer som leveres inne i pakker også matches. - Sjekk kun produksjonsavhengigheter: Les rot-
package.jsonmedctx.readJSON("package.json")og filtrerpkgFilesned til navnene som finnes i densdependencies-felt hvis du bare vil beskytte bundlet/levert kode, ikkedevDependencies. Merk at dette bare beholder direkte produksjonsavhengigheter — de transitive pakkene de drar inn faller ut av skanningen; å dekke hele produksjonsgrafen krever en lockfile-basert oppløsning.
Når bør du bruke den
Section titled “Når bør du bruke den”Når prosjektet ditt bruker en permissiv lisens (MIT, Apache-2.0, ISC, BSD) og du vil forhindre copyleft-kontaminering, spesielt i kompilerte/bundlede distribusjoner.
Når bør du ikke bruke den
Section titled “Når bør du ikke bruke den”I GPL-lisensierte prosjekter (der copyleft-avhengigheter er kompatible), eller når du har et dedikert lisensskanningsverktøy (FOSSA, Snyk) som allerede beskytter CI-pipelinen din.