Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/output/multi-folder-html-reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import type { SerializedFinding } from "./html-reporter.js";
import { loadLogoDataUri } from "./logos.js";
import { pluralize } from "../utils/string.js";
import type { SeverityLabel } from "../types.js";
import { renderOverrideFindingsHtml } from "./override-findings-html.js";
import { renderMaintenanceFindingsHtml } from "./maintenance-findings-html.js";

type SevCounts = Record<SeverityLabel, number>;

Expand Down Expand Up @@ -158,6 +160,16 @@ export async function writeMultiFolderHtmlReport(params: {
})
.join("\n");

const allOverrideFindings = params.results.flatMap(r => r.overrideFindings.map(of => ({ ...of, subfolder: r.subfolder })));
const allMaintenanceFindings = params.results.flatMap(r => r.maintenanceFindings.map(mf => ({ ...mf, subfolder: r.subfolder })));

const overrideHtml = allOverrideFindings.length > 0
? renderOverrideFindingsHtml(allOverrideFindings)
: "";
const maintenanceHtml = allMaintenanceFindings.length > 0
? renderMaintenanceFindingsHtml(allMaintenanceFindings)
: "";

// The OWASP SVG inline icon used in the header link
const owaspSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.49332 261.50668" width="16" height="16" style="flex-shrink:0"><g transform="matrix(1.3333333,0,0,-1.3333333,0,261.50667)"><g transform="scale(0.1)"><path fill="#F68B1F" d="M 980.629,0 C 439.043,0 0,439.051 0,980.637 0,1522.22 439.043,1961.27 980.629,1961.27 1522.2,1961.27 1961.25,1522.22 1961.25,980.637 1961.25,439.051 1522.2,0 980.629,0 m -0.008,1810.35 c -458.226,0 -829.707,-371.48 -829.707,-829.705 0,-458.235 371.481,-829.715 829.707,-829.715 458.219,0 829.699,371.48 829.699,829.715 0,458.225 -371.48,829.705 -829.699,829.705"/><path fill="#F68B1F" d="m 1299.1,285.75 c -31.36,0.02 -145.64,203.41 -161,261.398 -32.11,121.411 -25.2,172.704 -23.28,189.102 5.88,50.07 54.46,75.09 57.4,142.801 0.91,20.91 11.47,125.449 19.9,207.109 -20.8,4.07 -41.52,13.45 -59.94,28 55.3,-74.17 -26.09,-163.058 -144.352,-281.332 C 862.305,707.309 583.695,590.809 583.695,590.809 c 0,0 116.508,278.613 242.024,404.132 92.269,92.259 166.636,162.079 230.101,162.079 17.89,0 34.92,-5.55 51.23,-17.7 -14.56,18.41 -23.93,39.12 -28.01,59.92 -81.661,-8.45 -186.208,-18.99 -207.106,-19.91 -67.719,-2.94 -92.743,-51.52 -142.782,-57.39 -5.761,-0.68 -15.828,-1.98 -31.722,-1.98 -29.367,0 -78.629,4.42 -157.387,25.27 -63.07,16.68 -298.078,150.37 -256.512,167.17 21.196,8.58 88.75,14.38 177.715,14.38 85.559,0 190.922,-5.36 293.844,-18.77 128.328,-16.72 246,-37.87 326.19,-53.6 1.3,4.31 2.86,8.5 4.73,12.57 l -81.98,39.29 c 0,0 -65.479,75.14 -58.487,80.32 0.27,0.2 0.613,0.3 1.023,0.3 10.27,0 62.654,-59.89 67.694,-66.71 3.88,-1.29 26.09,-8.7 49.45,-16.47 l -23.19,20.28 c 0,0 -31.74,117.55 -23.47,120.32 0.1,0.03 0.21,0.05 0.33,0.05 8.71,0 37.51,-102.22 39.98,-109.56 5.66,-4.96 24.78,-12.41 48.67,-26.19 l -25.12,64.62 c 0,0 11.37,106.61 19.88,106.61 0.07,0 0.13,-0.01 0.2,-0.02 8.57,-1.71 -1.68,-88.92 -3.85,-99.78 3.11,-4.77 22.38,-34.33 41.7,-63.97 11.89,4.48 24.68,6.69 37.81,6.69 15.07,0 30.57,-2.92 45.61,-8.67 -19.26,41.01 -17.8,83.75 7.74,109.27 8.08,8.1 17.9,13.75 28.84,17.1 1.32,7.46 4.78,14.54 10.45,20.22 7.39,7.38 17.12,11.05 26.97,11.05 10.31,0 20.76,-4.03 28.76,-12.04 7.67,-7.65 11.65,-17.54 11.99,-27.39 12.33,25.41 26.88,59.7 25.86,70.81 -2.37,25.14 -31.53,69.64 -31.8,70.09 -1.9,2.87 -1.11,6.75 1.78,8.66 1.05,0.69 2.24,1.02 3.42,1.02 2.03,0 4.02,-0.99 5.21,-2.82 1.29,-1.92 31.17,-47.54 33.83,-75.79 1.48,-16.16 -17.07,-56.88 -27.18,-77.68 14.2,-7.77 28.04,-18.03 40.68,-30.67 12.63,-12.63 22.89,-26.47 30.67,-40.68 20.01,9.73 58.4,27.26 75.71,27.26 0.69,0 1.35,-0.02 1.97,-0.08 28.24,-2.66 73.87,-32.54 75.78,-33.81 2.88,-1.89 3.68,-5.77 1.78,-8.65 -1.2,-1.82 -3.19,-2.81 -5.22,-2.81 -1.17,0 -2.36,0.33 -3.41,1.03 -0.45,0.29 -44.94,29.44 -70.09,31.79 -0.38,0.04 -0.79,0.05 -1.22,0.05 -12.23,0 -45.07,-13.97 -69.61,-25.89 9.87,-0.33 19.76,-4.33 27.4,-12 15.67,-15.65 16.1,-40.59 0.99,-55.7 -5.67,-5.68 -12.74,-9.17 -20.2,-10.47 -3.37,-10.95 -9.03,-20.77 -17.11,-28.85 -14.08,-14.09 -33.38,-20.84 -54.76,-20.84 -17.38,0 -36.13,4.47 -54.52,13.1 10.77,-28.12 11.59,-57.89 1.99,-83.41 29.62,-19.32 59.22,-38.6 63.96,-41.71 7.78,1.55 54.5,7.22 81.17,7.22 10.66,0 18.13,-0.9 18.61,-3.34 1.73,-8.56 -106.57,-20.12 -106.57,-20.12 l -64.63,25.15 c 13.79,-23.91 21.21,-43.02 26.18,-48.69 7.47,-2.5 112.26,-32.04 109.5,-40.31 -0.31,-0.96 -2.15,-1.37 -5.16,-1.37 -23.1,0 -115.14,24.85 -115.14,24.85 l -20.3,23.19 c 7.79,-23.37 15.18,-45.56 16.49,-49.45 7.1,-5.25 71.57,-61.7 66.4,-68.708 -0.27,-0.363 -0.71,-0.524 -1.32,-0.524 -11.31,0 -78.99,58.992 -78.99,58.992 l -39.3,81.99 c -4.06,-1.88 -8.26,-3.42 -12.58,-4.73 15.73,-80.19 36.89,-197.861 53.63,-326.181 27.34,-209.949 21.19,-429.969 4.39,-471.571 -1.35,-3.347 -3.46,-4.898 -6.2,-4.898"/></g></g></svg>`;

Expand Down Expand Up @@ -222,6 +234,8 @@ details[open] .folder-summary::before{transform:rotate(90deg)}
</div>

${folderSectionsHtml}
${overrideHtml}
${maintenanceHtml}

<div class="report-footer">
<span>Generated by <strong>cve-lite v${escapeHtml(params.cliVersion)}</strong></span>
Expand Down Expand Up @@ -360,6 +374,22 @@ document.addEventListener('click', function(e) {
const indexPath = path.join(params.outputDir, "index.html");
fs.writeFileSync(indexPath, html, "utf8");

const allFindingsArray = params.results.flatMap(r =>
r.sorted.map(f => ({ ...serializeHtmlFinding(f, r.suggestedFixCommands), subfolder: r.subfolder }))
);
const jsonPayload = {
multiFolder: true as const,
projectPath: params.projectPath,
folders: params.results.map(r => r.subfolder),
findingCount: allFindingsArray.length,
findings: allFindingsArray,
...(allOverrideFindings.length > 0 ? { overrideFindings: allOverrideFindings } : {}),
...(allMaintenanceFindings.length > 0 ? { maintenanceFindings: allMaintenanceFindings } : {}),
scannedAt: new Date().toISOString(),
};
const jsonPath = path.join(params.outputDir, "report.json");
fs.writeFileSync(jsonPath, JSON.stringify(jsonPayload, null, 2), "utf8");

if (params.autoOpen) openInBrowser(indexPath);

return { reportPath: indexPath };
Expand Down