Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 5x 5x 5x 2x 2x 2x 2x 4x 4x 3x 2x 1x 1x 2x 4x 4x 4x 4x 4x 4x 1x 3x 2x 1x 4x 4x 2x 5x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x | import { promisify } from 'util';
import { Command } from 'commander';
import * as licenseChecker from 'license-checker';
export interface BomAgentOptions {}
export interface BomPackage {
name: string;
version: string;
license: string;
risk: 'Low' | 'Medium' | 'High' | 'Unknown';
}
export interface BomAgentResult {
packages: BomPackage[];
}
/**
* Génère le Bill Of Materials (liste des packages et licences).
*/
/**
* Exécute license-checker pour récupérer la liste des dépendances et licences,
* et évalue le risque associé à chaque licence.
*/
export async function bomAgent(
_opts?: BomAgentOptions,
): Promise<BomAgentResult> {
// Programmatic retrieval via license-checker
const initChecker = promisify(licenseChecker.init);
const data = (await initChecker({
start: process.cwd(),
production: true,
json: true,
})) as Record<string, { licenses?: string | string[] }>;
const results: BomPackage[] = [];
// Risk evaluation function
const evaluateRisk = (lic: string): BomPackage['risk'] => {
const l = lic.toLowerCase();
// Copyleft strong licenses
if (l.includes('agpl') || (l.includes('gpl') && !l.includes('lgpl'))) return 'High';
// Lesser copyleft
if (l.includes('lgpl')) return 'Medium';
// Permissive licenses
if (
l.includes('mit') ||
l.includes('bsd') ||
l.includes('apache') ||
l.includes('isc')
) {
return 'Low';
}
return 'Unknown';
};
for (const key of Object.keys(data)) {
const info = data[key] as { licenses?: string | string[] };
// key format: 'name@version'
const at = key.lastIndexOf('@');
const name = key.substring(0, at);
const version = key.substring(at + 1);
let license = '';
if (Array.isArray(info.licenses)) {
license = info.licenses.join(', ');
} else if (typeof info.licenses === 'string') {
license = info.licenses;
} else {
license = String(info.licenses || 'Unknown');
}
const risk = evaluateRisk(license);
results.push({ name, version, license, risk });
}
return { packages: results };
}
export const cli = {
command: 'qualimetrie:bom',
description: 'Génère le Bill Of Materials des licences',
builder: (cmd: Command) => cmd,
handler: async (_opts: unknown) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { bomAgent: run } = require('./bomAgent');
const res: BomAgentResult = await run();
// Report header
const date = new Date().toISOString().split('T')[0];
console.log('# 📜 Bill Of Materials Report');
console.log(`Date: ${date}`);
// Executive summary
const total = res.packages.length;
const counts = res.packages.reduce(
(acc, pkg) => {
acc[pkg.risk] = (acc[pkg.risk] || 0) + 1;
return acc;
}, {} as Record<string, number>,
);
console.log('## 🔎 Executive Summary');
console.log(`- Total packages: ${total}`);
console.log(`- High risk: ${counts['High'] || 0}`);
console.log(`- Medium risk: ${counts['Medium'] || 0}`);
console.log(`- Low risk: ${counts['Low'] || 0}`);
console.log(`- Unknown risk: ${counts['Unknown'] || 0}\n`);
// Detailed table
console.log('## 📜 Details');
console.log('| Package | Version | License | Risk |');
console.log('|---|---|---|---|');
res.packages.forEach((pkg) => {
console.log(`| ${pkg.name} | ${pkg.version} | ${pkg.license} | ${pkg.risk} |`);
});
},
};
|