UNPKG

yarn-audit-html

Version:

Generate a HTML report for Yarn Audit

117 lines (116 loc) 4.22 kB
#!/usr/bin/env node import { fstatSync } from 'node:fs'; import { spawnSync } from 'node:child_process'; import process from 'node:process'; import { program, Option } from 'commander'; import { bailWithError, generateReport, parseAdvisory } from './index.js'; async function run(argv, input) { program .option('-o, --output [output path]', 'output file', 'yarn-audit.html') .option('-t, --template [ejs path]', 'ejs template path', new URL('../templates/template.ejs', import.meta.url).pathname) .addOption(new Option('--theme [theme name]', 'Bootswatch theme. see https://bootswatch.com/#:~:text=Cerulean') .default('materia') .choices([ 'cerulean', 'cosmo', 'cyborg', 'darkly', 'flatly', 'journal', 'litera', 'lumen', 'lux', 'materia', 'minty', 'morph', 'pulse', 'quartz', 'sandstone', 'simplex', 'sketchy', 'slate', 'solar', 'spacelab', 'superhero', 'united', 'vapor', 'yeti', 'zephyr', ])) .option('--fatal-exit-code', 'exit with code 1 if vulnerabilities were found', false) .parse(argv); console.info('Checking audit logs...'); let summary = { vulnerabilities: { info: 0, low: 0, moderate: 0, high: 0, critical: 0 }, dependencies: 0, devDependencies: 0, optionalDependencies: 0, totalDependencies: 0, }; const options = program.opts(); const vulnerabilities = new Map(); const { stdout } = spawnSync('yarn', ['--version']); const yarnMajorVersion = Number.parseInt(stdout.toString()); // Determine if cli is piped *in* const stats = fstatSync(0); if (!stats.isFIFO()) { program.outputHelp(); return process.exit(1); } let text = ''; input.on('readable', function () { try { const chunk = this.read(); if (chunk !== null) { text += chunk; const lines = text.split('\n'); if (lines.length > 1) { text = lines.splice(-1, 1)[0]; lines.forEach((line) => { if (yarnMajorVersion >= 2) { const auditAdvisoryData = JSON.parse(line); Object.values(auditAdvisoryData.advisories).forEach((rawAdvisory) => { advisoryToVulnerabilities(rawAdvisory); }); summary = auditAdvisoryData.metadata; } else { const auditAdvisoryData = JSON.parse(line); if (auditAdvisoryData.type === 'auditAdvisory') { advisoryToVulnerabilities(auditAdvisoryData.data.advisory); } else if (auditAdvisoryData.type === 'auditSummary') { summary = auditAdvisoryData.data; } } }); } } } catch (error) { bailWithError('Failed to parse YARN Audit JSON!', error, options.fatalExitCode); } }); input.on('end', async function () { try { await generateReport(Array.from(vulnerabilities.values()), summary, options); } catch (error) { bailWithError('Failed to generate report! Please report this issue to https://github.com/davityavryan/yarn-audit-html/issues', error, options.fatalExitCode); } }); function advisoryToVulnerabilities(advisory) { const newVulnerabilities = parseAdvisory(advisory); newVulnerabilities.forEach((newVulnerability) => { const { key } = newVulnerability; if (!vulnerabilities.has(key)) { vulnerabilities.set(key, newVulnerability); } }); } } /* istanbul ignore if */ if (process.env.NODE_ENV !== 'test') { run(process.argv, process.stdin); } export { run };