#!/usr/bin/env node
/**
* License compliance checker for Abysius Codium build.
* Scans extension and vscode dependencies for GPL/copyleft licenses.
* Exit code 0 = clean, 1 = violations found.
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const BANNED_LICENSES = [
'GPL-2.0',
'GPL-3.0',
'AGPL-3.0',
'LGPL-2.1',
'LGPL-3.0',
'GPL',
'AGPL',
'LGPL'
];
const PERMISSIVE_LICENSES = [
'MIT',
'Apache-2.0',
'BSD-2-Clause',
'BSD-3-Clause',
'ISC',
'0BSD',
'CC0-1.0',
'Unlicense'
];
const ALLOWED_COPYLEFT_PACKAGES = new Set([
// jschardet is LGPL, but currently comes from upstream VS Code deps.
// Keep this exception only if legal/compliance approves it.
'jschardet@3.1.4'
]);
function normalizeLicense(license) {
return String(license || '').trim();
}
function hasPermissiveOption(license) {
const normalized = normalizeLicense(license).toUpperCase();
return PERMISSIVE_LICENSES.some(allowed =>
normalized.includes(allowed.toUpperCase())
);
}
function hasBannedLicense(license) {
const normalized = normalizeLicense(license).toUpperCase();
return BANNED_LICENSES.some(banned =>
normalized.includes(banned.toUpperCase())
);
}
function isViolation(pkgName, license) {
if (!license) {
return false;
}
if (ALLOWED_COPYLEFT_PACKAGES.has(pkgName)) {
return false;
}
// Handles dual-license expressions like:
// "(MIT OR GPL-3.0-or-later)"
// Since MIT is available, it should not be treated as a violation.
if (hasPermissiveOption(license)) {
return false;
}
return hasBannedLicense(license);
}
function scanDir(scanPath) {
if (!fs.existsSync(path.join(scanPath, 'node_modules'))) {
console.error(`[LICENSE] No node_modules found in ${scanPath}, skipping...`);
return [];
}
let output;
try {
output = execSync('npx license-checker --json --start .', {
cwd: scanPath,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe']
});
} catch (err) {
console.warn('[LICENSE] license-checker failed or not installed; install with: npm install -g license-checker');
return [];
}
const packages = JSON.parse(output);
const violations = [];
for (const [pkgName, info] of Object.entries(packages)) {
const licenses = Array.isArray(info.licenses) ? info.licenses : [info.licenses];
for (const lic of licenses) {
if (isViolation(pkgName, lic)) {
violations.push({
package: pkgName,
license: lic,
path: info.path
});
}
}
}
return violations;
}
function main() {
const root = process.cwd();
console.log('[LICENSE] Scanning for open-source license compliance...');
const extDir = path.join(root, 'extensions', 'abysius-ai');
const vscodeDir = path.join(root, 'work', 'vscode');
const allViolations = [];
if (fs.existsSync(extDir)) {
allViolations.push(...scanDir(extDir));
}
if (fs.existsSync(vscodeDir)) {
allViolations.push(...scanDir(vscodeDir));
}
if (allViolations.length === 0) {
console.log('[LICENSE] No copyleft license violations detected.');
process.exit(0);
}
console.error(`[LICENSE] Found ${allViolations.length} potential license violation(s):`);
for (const v of allViolations) {
console.error(` - ${v.package}: ${v.license}`);
}
console.error('[LICENSE] Remove, replace, or explicitly allowlist these dependencies before distributing binaries.');
process.exit(1);
}
main();