From 9eac07fa45dc0efe8a6e270b9c192156b3d3fc52 Mon Sep 17 00:00:00 2001 From: BradyMitch Date: Wed, 10 Jul 2024 09:36:47 -0700 Subject: [PATCH] Updated vul report --- .github/helpers/npm-audit/create-report.cjs | 27 +++-- .github/helpers/npm-audit/run-npm-audit.cjs | 106 ++++++++---------- ...json5-config.js => parse-json5-config.mjs} | 4 +- .github/workflows/npm-audit-report.yaml | 3 +- 4 files changed, 64 insertions(+), 76 deletions(-) rename .github/helpers/{parse-json5-config.js => parse-json5-config.mjs} (97%) diff --git a/.github/helpers/npm-audit/create-report.cjs b/.github/helpers/npm-audit/create-report.cjs index 4fed4f6bf..4c99f561d 100644 --- a/.github/helpers/npm-audit/create-report.cjs +++ b/.github/helpers/npm-audit/create-report.cjs @@ -79,11 +79,8 @@ const outputVulnerabilities = (vulnerabilitiesArray, dirPath) => { const { name, severity, - title, - cvss, range, - cwe, - url, + via, isDirect, fixAvailable, latestVersion, @@ -103,17 +100,23 @@ const outputVulnerabilities = (vulnerabilitiesArray, dirPath) => { results[dirPath] += `${lineBreak()}\n`; results[dirPath] += `${line(`![${name}_header]`)}\n\n`; - // Output summary. - results[dirPath] += `${line(`${title}.`)}`; - // Output details. results[dirPath] += `\n${line(`**Severity**: \`${severity}\``)}`; - results[dirPath] += `${line(`**CVSS Score**: \`${cvss} / 10\``)}`; results[dirPath] += `${line(`**Vulnerable Range**: \`${range}\``)}`; - results[dirPath] += `${line(`**Weaknesses**: \`${cwe}\``)}`; - // Output advisory link. - results[dirPath] += `\n${link('GitHub Advisory', url)}`; + if (via.length > 0) results[dirPath] += `${line(`**Via**:`)}`; + + //Output via details + via.forEach((v, index) => { + results[dirPath] += `\n${line(`${index + 1}: ${v.title}.`)}`; + + results[dirPath] += `\n${line(`**Severity**: \`${v.severity}\``)}`; + results[dirPath] += `${line(`**Vulnerable Range**: \`${v.range}\``)}`; + results[dirPath] += `${line(`**CVSS Score**: \`${v.cvss} / 10\``)}`; + results[dirPath] += `${line(`**Weaknesses**: \`${v.cwe}\``)}`; + + results[dirPath] += `\n${link('GitHub Advisory', v.url)}`; + }); // Output latest version. results[dirPath] += `\n${line(`**Latest Available Version**: \`${latestVersion}\``)}`; @@ -196,7 +199,7 @@ const escapeForGitHubActions = (str) => else if (highestSeverity === 'moderate') highestSeverityColor = yellow; // Moderate // Output summary. - if (total ? total === 0 : metadata.vulnerabilities === 0) { + if ((total && total === 0) || metadata.vulnerabilities === 0) { results[dirPath] += `${line(noVulnerabilities)}`; } else { // Output highest severity. diff --git a/.github/helpers/npm-audit/run-npm-audit.cjs b/.github/helpers/npm-audit/run-npm-audit.cjs index ce740ba0b..3281e5b36 100644 --- a/.github/helpers/npm-audit/run-npm-audit.cjs +++ b/.github/helpers/npm-audit/run-npm-audit.cjs @@ -1,6 +1,49 @@ const { execSync } = require('child_process'); const path = require('path'); +const parseDetails = (auditData) => { + if (!auditData.vulnerabilities) { + return { vulnerabilities: [], metadata: { vulnerabilities: 0 }, highestSeverity: 'none' }; + } + + const vulnerabilities = Object.keys(auditData.vulnerabilities).map((key) => { + const vuln = auditData.vulnerabilities[key]; + return { + name: key, + severity: vuln.severity, + isDirect: vuln.isDirect, + via: vuln.via.map((v) => { + return { + title: v.title, + severity: v.severity, + range: v.range, + url: v.url, + cwe: v.cwe, + cvss: v.cvss.score, + }; + }), + range: vuln.range, + fixAvailable: vuln.fixAvailable, + }; + }); + + const highestSeverity = + vulnerabilities.length === 0 + ? null + : vulnerabilities.reduce((max, vuln) => { + const severities = ['low', 'moderate', 'high', 'critical']; + return severities.indexOf(vuln.severity) > severities.indexOf(max) ? vuln.severity : max; + }, 'low'); + + return { + vulnerabilities, + metadata: { + vulnerabilities: auditData.metadata.vulnerabilities, + highestSeverity, + }, + }; +}; + // Runs 'npm audit --json' command and returns a modified output. const runNpmAudit = async (directoryPath) => { try { @@ -10,72 +53,15 @@ const runNpmAudit = async (directoryPath) => { stdio: ['pipe', 'pipe', 'ignore'], cwd: path.resolve(__dirname, `../../../${directoryPath}`), }); - const auditData = JSON.parse(stdout); - - if (!auditData.vulnerabilities) { - return { vulnerabilities: [], metadata: { vulnerabilities: 0 }, highestSeverity: 'none' }; - } - - const vulnerabilities = Object.keys(auditData.vulnerabilities).map((key) => { - const vuln = auditData.vulnerabilities[key]; - return { - name: key, - severity: vuln.severity, - isDirect: vuln.isDirect, - via: vuln.via, - range: vuln.range, - fixAvailable: vuln.fixAvailable, - }; - }); - - const highestSeverity = vulnerabilities.reduce((max, vuln) => { - const severities = ['low', 'moderate', 'high', 'critical']; - return severities.indexOf(vuln.severity) > severities.indexOf(max) ? vuln.severity : max; - }, 'low'); - return { - vulnerabilities, - metadata: { - vulnerabilities: vulnerabilities.length, - }, - highestSeverity, - }; + const auditData = JSON.parse(stdout); + return parseDetails(auditData); } catch (error) { if (error.stdout) { try { const auditData = JSON.parse(error.stdout); - if (!auditData.vulnerabilities) { - return { vulnerabilities: [], metadata: { vulnerabilities: 0 }, highestSeverity: 'none' }; - } - - const vulnerabilities = Object.keys(auditData.vulnerabilities).map((key) => { - const vuln = auditData.vulnerabilities[key]; - return { - name: key, - severity: vuln.severity, - isDirect: vuln.isDirect, - title: vuln.via[0].title, - url: vuln.via[0].url, - cwe: vuln.via[0].cwe, - cvss: vuln.via[0].cvss.score, - range: vuln.range, - fixAvailable: vuln.fixAvailable, - }; - }); - - const highestSeverity = vulnerabilities.reduce((max, vuln) => { - const severities = ['low', 'moderate', 'high', 'critical']; - return severities.indexOf(vuln.severity) > severities.indexOf(max) ? vuln.severity : max; - }, 'low'); - - return { - vulnerabilities, - metadata: { - vulnerabilities: auditData.metadata.vulnerabilities, - highestSeverity, - }, - }; + return parseDetails(auditData); } catch (parseError) { console.error('JSON parse error:', parseError); throw parseError; diff --git a/.github/helpers/parse-json5-config.js b/.github/helpers/parse-json5-config.mjs similarity index 97% rename from .github/helpers/parse-json5-config.js rename to .github/helpers/parse-json5-config.mjs index 76df02251..99f9a593c 100644 --- a/.github/helpers/parse-json5-config.js +++ b/.github/helpers/parse-json5-config.mjs @@ -1,5 +1,5 @@ -const fs = require("fs"); -const json5 = require("json5"); +import fs from "fs"; +import json5 from "json5"; /** * THIS FILE DOES NOT REQUIRE ANY EDITING. diff --git a/.github/workflows/npm-audit-report.yaml b/.github/workflows/npm-audit-report.yaml index 209697dc9..ad5e563b5 100644 --- a/.github/workflows/npm-audit-report.yaml +++ b/.github/workflows/npm-audit-report.yaml @@ -47,7 +47,7 @@ jobs: # Run script to convert json5 config to Output Vars. - name: Run Script id: parse_config - run: node .github/helpers/parse-json5-config .github/config/vulnerability-report.json5 + run: node .github/helpers/parse-json5-config.mjs .github/config/vulnerability-report.json5 # Check package versions for updates. parse-vulnerabilities: @@ -70,7 +70,6 @@ jobs: run: | npm i -D semver node .github/helpers/npm-audit/parse-npm-vulnerabilities.cjs > vulnerabilities.json - cat vulnerabilities.json # Upload the output as an artifact. - name: Upload output