2121import java .util .HashSet ;
2222import java .util .Set ;
2323import java .util .LinkedHashMap ;
24+ import java .util .stream .Collectors ;
2425
2526import neuvector .report .*;
2627import neuvector .scanner .*;
@@ -123,6 +124,7 @@ private void processScanReport(ProcessResult processResult) throws TaskException
123124 vulnerability .setScore (Float .valueOf (vulnerabilityObject .get ("score" ).getAsString ()));
124125 vulnerability .setPackage_name (vulnerabilityObject .get ("package_name" ).getAsString ());
125126 vulnerability .setPackage_version (vulnerabilityObject .get ("package_version" ).getAsString ());
127+ vulnerability .setFile_name (vulnerabilityObject .get ("file_name" ).getAsString ());
126128 vulnerability .setFixed_version (vulnerabilityObject .get ("fixed_version" ).getAsString ());
127129 vulnerability .setVectors (vulnerabilityObject .get ("vectors" ).getAsString ());
128130 vulnerability .setDescription (vulnerabilityObject .get ("description" ).getAsString ());
@@ -159,6 +161,7 @@ private void processScanReport(ProcessResult processResult) throws TaskException
159161
160162 if (scanConfig .isScanLayers ()) {
161163 if (reportJson .has ("layers" )) {
164+ scanResult .setScanLayerSupported (true );
162165 JsonArray layerArray = reportJson .getAsJsonArray ("layers" );
163166 LinkedHashMap <String , Set <Vulnerability >> layeredVulnerabilityMap = new LinkedHashMap <String , Set <Vulnerability >>();
164167 for (int i = 0 ; i < layerArray .size (); i ++) {
@@ -181,6 +184,7 @@ private void processScanReport(ProcessResult processResult) throws TaskException
181184 vulnerability .setScore (Float .valueOf (layerVulnerabilityObject .get ("score" ).getAsString ()));
182185 vulnerability .setPackage_name (layerVulnerabilityObject .get ("package_name" ).getAsString ());
183186 vulnerability .setPackage_version (layerVulnerabilityObject .get ("package_version" ).getAsString ());
187+ vulnerability .setFile_name (layerVulnerabilityObject .get ("file_name" ).getAsString ());
184188 vulnerability .setFixed_version (layerVulnerabilityObject .get ("fixed_version" ).getAsString ());
185189 vulnerability .setLink (layerVulnerabilityObject .get ("link" ).getAsString ());
186190 vulnerability .setFeed_rating (layerVulnerabilityObject .get ("feed_rating" ).getAsString ());
@@ -242,8 +246,9 @@ private void makeIfFailDecision(ProcessResult processResult) {
242246 }
243247
244248 private void writeReport (final TaskContext taskContext , ProcessResult processResult ) throws IOException , InterruptedException {
245- writeHTMLReport (taskContext , processResult );
246249 writeJsonReport (taskContext , processResult );
250+ writeTxtReport (taskContext , processResult );
251+ writeHTMLReport (taskContext , processResult );
247252 }
248253
249254 public void writeJsonReport (final TaskContext taskContext , ProcessResult processResult ) throws IOException {
@@ -258,118 +263,234 @@ public void writeJsonReport(final TaskContext taskContext, ProcessResult process
258263 }
259264 }
260265
266+ public void writeTxtReport (final TaskContext taskContext , ProcessResult processResult ) throws IOException {
267+ ScanResult scanResult = processResult .getScanResult ();
268+ File reportFile = new File (taskContext .getWorkingDirectory (), "neuvector-report.txt" );
269+
270+ try (BufferedWriter writer = new BufferedWriter (new FileWriter (reportFile ))) {
271+ // Report header
272+ writer .write ("************************ Scan Report ************************\n " );
273+ if (!scanResult .isLocalScan ()) {
274+ writer .write ("Registry URL: " + scanResult .getRegistry () + "\n " );
275+ }
276+ writer .write ("Repository: " + scanResult .getRepository () + "\n " );
277+ writer .write ("Tag: " + scanResult .getTag () + "\n " );
278+ writer .write ("High severity vulnerabilities: " + scanResult .getHighSeverityNumber () + "\n " );
279+ writer .write ("Medium severity vulnerabilities: " + scanResult .getMediumSeverityNumber () + "\n " );
280+ writer .write ("Total vulnerabilities: " + scanResult .getTotalVulnerabilityNumber () + "\n " );
281+ writer .write ("********************** Vulnerabilities **********************\n \n " );
282+
283+ // Handling if no vulnerabilities are found
284+ if (scanResult .getTotalVulnerabilityNumber () == 0 ) {
285+ writer .write ("Scanned. No vulnerabilities found.\n " );
286+ } else {
287+ // Detailed vulnerabilities
288+ for (Vulnerability vulnerability : scanResult .getHighVulnerabilitySet ()) {
289+ writeTxtReportVulnerabilityDetails (writer , vulnerability , "High" );
290+ }
291+ for (Vulnerability vulnerability : scanResult .getMediumVulnerabilitySet ()) {
292+ writeTxtReportVulnerabilityDetails (writer , vulnerability , "Medium" );
293+ }
294+ }
295+
296+ // Layer Vulnerability History
297+ if (scanResult .isScanLayerSupported ()) {
298+ writer .write ("\n **************** Layer Vulnerability History ****************\n " );
299+ Set <String > keys = scanResult .getLayeredVulsMap ().keySet ();
300+ for (String key : keys ){
301+ Set <Vulnerability > vulSet = scanResult .getLayeredVulsMap ().get (key );
302+ writer .write ("Layer digest " + key + " contains " + vulSet .size () + " vulnerabilities.\n " );
303+ for (Vulnerability vulnerability : vulSet ){
304+ writeTxtReportVulnerabilityDetails (writer , vulnerability , vulnerability .getSeverity ()); // Assuming getSeverity() method exists
305+ }
306+ }
307+ } else if (scanResult .isScanLayerConfigured ()) {
308+ writer .write ("\n *** Your Controller Does Not Support Layer Vulnerability Scan ***\n " );
309+ }
310+
311+ // Exempted Vulnerabilities
312+ if (scanResult .isWhiteListVulExisted ()) {
313+ writer .write ("\n ********************** Exempt Vulnerability **********************\n " );
314+ for (String exemptedVul : scanResult .getExistedWhiteListVulSet ()){
315+ writer .write ("The vulnerability " + exemptedVul .toUpperCase () + " is exempt.\n " );
316+ }
317+ }
318+
319+ } catch (IOException e ) {
320+ System .err .println ("IOException: " + e .getMessage ());
321+ e .printStackTrace ();
322+ }
323+ }
324+
325+ // Helper method to write vulnerability details
326+ private void writeTxtReportVulnerabilityDetails (BufferedWriter writer , Vulnerability vulnerability , String severity ) throws IOException {
327+ writer .write ("Name: " + vulnerability .getName ().toUpperCase () + "\n " );
328+ writer .write ("Severity: " + severity + "\n " );
329+ writer .write ("Score: " + vulnerability .getScore () + "\n " );
330+ writer .write ("Package: " + vulnerability .getPackage_name () + ":" + vulnerability .getPackage_version () + "\n " );
331+ writer .write ("Filename: " + vulnerability .getFile_name () + "\n " );
332+ writer .write ("Fixed version: " + vulnerability .getFixed_version () + "\n " );
333+ writer .write ("Vectors: " + vulnerability .getVectors () + "\n " );
334+ writer .write ("Description: " + vulnerability .getDescription () + "\n " );
335+ writer .write ("Link: " + vulnerability .getLink () + "\n \n " );
336+ }
337+
261338 public void writeHTMLReport (final TaskContext taskContext , ProcessResult processResult ) throws IOException {
262339 ScanResult scanResult = processResult .getScanResult ();
263340 File reportFile = new File (taskContext .getWorkingDirectory (), "neuvector-report.html" );
264-
265- // Basic CSS styles. Replace with your actual CSS if needed.
341+
342+ StringBuilder htmlContent = new StringBuilder ();
343+
344+ // Basic CSS styles
266345 String cssStyles = "<style>" +
267346 "body { font-family: Arial, sans-serif; }" +
268347 "table { border-collapse: collapse; width: 100%; }" +
269348 "th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }" +
270349 "th { background-color: #f2f2f2; }" +
271350 "</style>" ;
272-
273- // The HTML content should be well-formed. Close all opened tags.
274- String htmlContent = "<!DOCTYPE html>\n " +
275- "<html lang=\" en\" >\n " +
276- "<head>\n " +
277- "<meta charset=\" UTF-8\" >\n " +
278- "<title>NeuVector Scan Report</title>\n " +
279- cssStyles + // Include the CSS styles.
280- "</head>\n " +
281- "<body>\n " +
282- "<h1>Scan Report</h1>\n " +
283- "<h3>Summary</h3>\n " +
284- "<table>\n " +
285- "<tr>\n " +
286- "<th>Registry URL</th>\n " +
287- "<th>Repository</th>\n " +
288- "<th>Tag</th>\n " +
289- "<th>High severity VULs</th>\n " +
290- "<th>High severity threshold</th>\n " +
291- "<th>Medium severity VULs</th>\n " +
292- "<th>Medium severity threshold</th>\n " +
293- "<th>VULs to fail the build</th>\n " +
294- "<th>Total VULs</th>\n " +
295- "</tr>\n " +
296- "<tr>\n " +
297- "<td>" + escapeHtml (scanResult .getRegistry ()) + "</td>\n " +
298- "<td>" + escapeHtml (scanResult .getRepository ()) + "</td>\n " +
299- "<td>" + escapeHtml (scanResult .getTag ()) + "</td>\n " +
300- "<td>" + scanResult .getHighVulnerabilitySet ().size () + "</td>\n " +
301- "<td>" + (scanResult .getHighSeverityThreshold () != 0 ? scanResult .getHighSeverityThreshold () : "No Limit" ) + "</td>\n " +
302- "<td>" + scanResult .getMediumVulnerabilitySet ().size () + "</td>\n " +
303- "<td>" + (scanResult .getMediumSeverityThreshold () != 0 ? scanResult .getMediumSeverityThreshold () : "No Limit" ) + "</td>\n " +
304- "<td>" + escapeHtml (String .join (", " , scanResult .getExistedBlackListVulSet ())) + "</td>\n " +
305- "<td>" + scanResult .getTotalVulnerabilityNumber () + "</td>\n " +
306- "</tr>\n " +
307- "</table>\n " +
308- "<h3>Vulnerabilities</h3>\n " ;
309-
310- // If no vulnerabilities found, display a message
311- if (scanResult .getTotalVulnerabilityNumber () == 0 ) {
312- htmlContent += "<p>Scanned. No vulnerabilities found.</p>\n " ;
313- } else {
314- htmlContent += "<table>\n " +
315- "<tr>\n " +
316- "<th>Name</th>\n " +
317- "<th>Severity</th>\n " +
318- "<th>Score</th>\n " +
319- "<th>Package</th>\n " +
320- "<th>Fixed_version</th>\n " +
321- "<th>Vectors</th>\n " +
322- "<th>Description</th>\n " +
323- "<th>Feed_rating</th>\n " +
324- "</tr>\n " ;
325-
326- // Add rows for high vulnerabilities
351+
352+ // Start building the HTML content
353+ htmlContent .append ("<!DOCTYPE html>\n " )
354+ .append ("<html lang=\" en\" >\n " )
355+ .append ("<head>\n " )
356+ .append ("<meta charset=\" UTF-8\" >\n " )
357+ .append ("<title>NeuVector Scan Report</title>\n " )
358+ .append (cssStyles )
359+ .append ("</head>\n " )
360+ .append ("<body>\n " )
361+ .append ("<h1>Scan Report</h1>\n " )
362+ .append ("<h3>Summary</h3>\n " )
363+ .append ("<table>\n " )
364+ .append ("<tr>\n " )
365+ .append ("<th>Registry URL</th>\n " )
366+ .append ("<th>Repository</th>\n " )
367+ .append ("<th>Tag</th>\n " )
368+ .append ("<th>High severity VULs</th>\n " )
369+ .append ("<th>High severity threshold</th>\n " )
370+ .append ("<th>Medium severity VULs</th>\n " )
371+ .append ("<th>Medium severity threshold</th>\n " )
372+ .append ("<th>VULs to fail the build</th>\n " )
373+ .append ("<th>Total VULs</th>\n " )
374+ .append ("</tr>\n " )
375+ .append ("<tr>\n " )
376+ .append ("<td>" ).append (escapeHtml (scanResult .getRegistry ())).append ("</td>\n " )
377+ .append ("<td>" ).append (escapeHtml (scanResult .getRepository ())).append ("</td>\n " )
378+ .append ("<td>" ).append (escapeHtml (scanResult .getTag ())).append ("</td>\n " )
379+ .append ("<td>" ).append (Integer .toString (scanResult .getHighVulnerabilitySet ().size ())).append ("</td>\n " )
380+ .append ("<td>" ).append (scanResult .getHighSeverityThreshold () != 0 ? Integer .toString (scanResult .getHighSeverityThreshold ()) : "No Limit" ).append ("</td>\n " )
381+ .append ("<td>" ).append (Integer .toString (scanResult .getMediumVulnerabilitySet ().size ())).append ("</td>\n " )
382+ .append ("<td>" ).append (scanResult .getMediumSeverityThreshold () != 0 ? Integer .toString (scanResult .getMediumSeverityThreshold ()) : "No Limit" ).append ("</td>\n " )
383+ .append ("<td>" ).append (escapeHtml (String .join (", " , scanResult .getExistedBlackListVulSet ()))).append ("</td>\n " )
384+ .append ("<td>" ).append (Integer .toString (scanResult .getTotalVulnerabilityNumber ())).append ("</td>\n " )
385+ .append ("</tr>\n " )
386+ .append ("</table>\n " );
387+
388+ // Append vulnerabilities section
389+ if (scanResult .getTotalVulnerabilityNumber () > 0 ) {
390+ htmlContent .append ("<h3>Vulnerabilities</h3>\n " )
391+ .append ("<table>\n " )
392+ .append ("<tr>\n " )
393+ .append ("<th>Name</th>\n " )
394+ .append ("<th>Severity</th>\n " )
395+ .append ("<th>Score</th>\n " )
396+ .append ("<th>Package</th>\n " )
397+ .append ("<th>Filename</th>\n " )
398+ .append ("<th>Fixed_version</th>\n " )
399+ .append ("<th>Vectors</th>\n " )
400+ .append ("<th>Description</th>\n " )
401+ .append ("<th>Feed_rating</th>\n " )
402+ .append ("</tr>\n " );
403+ // High vulnerabilities
327404 for (Vulnerability vulnerability : scanResult .getHighVulnerabilitySet ()) {
328- htmlContent += getVulnerabilityRowHtml (vulnerability , "High" );
405+ htmlContent . append ( getVulnerabilityRowHtml (vulnerability , "High" ) );
329406 }
330-
331- // Add rows for medium vulnerabilities
407+ // Medium vulnerabilities
332408 for (Vulnerability vulnerability : scanResult .getMediumVulnerabilitySet ()) {
333- htmlContent += getVulnerabilityRowHtml (vulnerability , "Medium" );
409+ htmlContent . append ( getVulnerabilityRowHtml (vulnerability , "Medium" ) );
334410 }
335-
336- htmlContent += "</table>\n " ;
411+ htmlContent .append ("</table>\n " );
412+ } else {
413+ htmlContent .append ("<p>No vulnerabilities found.</p>\n " );
337414 }
338-
339- // Closing tags for HTML document
340- htmlContent += "</body>\n " +
341- "</html>" ;
342-
343- // Writing the file with UTF-8 encoding.
415+
416+ if (scanResult .isScanLayerSupported ()){
417+ htmlContent .append ("<h3> Layer Vulnerability History </h3>\n " );
418+ Set <String > keys = scanResult .getLayeredVulsMap ().keySet ();
419+ for (String key : keys ){
420+ Set <Vulnerability > vulSet = scanResult .getLayeredVulsMap ().get (key );
421+ htmlContent .append ("<p>Layer digest " ).append (key ).append (" contains " ).append (vulSet .size ()).append (" vulnerabilities.</p>\n " );
422+ if (!vulSet .isEmpty ()){
423+ htmlContent .append ("<table>\n " )
424+ .append (" <tr>\n " )
425+ .append (" <th>Name</th>\n " )
426+ .append (" <th>Score</th>\n " )
427+ .append (" <th>Package</th>\n " )
428+ .append (" <th>Filename</th>\n " )
429+ .append (" <th>Fixed_version</th>\n " )
430+ .append (" <th>Link</th>\n " )
431+ .append (" <th>Feed_rating</th>\n " )
432+ .append (" </tr>\n " );
433+
434+ for (Vulnerability vulnerability : vulSet ) {
435+ htmlContent .append ("<tr>\n " )
436+ .append ("<td><a target=\" _parent\" href=\" " ).append (escapeHtml (vulnerability .getLink ())).append ("\" >" ).append (escapeHtml (vulnerability .getName ())).append ("</a></td>\n " )
437+ .append ("<td>" ).append (vulnerability .getScore ()).append ("</td>\n " )
438+ .append ("<td>" ).append (escapeHtml (vulnerability .getPackage_name ())).append (":" ).append (escapeHtml (vulnerability .getPackage_version ())).append ("</td>\n " )
439+ .append ("<td>" ).append (escapeHtml (vulnerability .getFile_name ())).append ("</td>\n " )
440+ .append ("<td>" ).append (escapeHtml (vulnerability .getFixed_version ())).append ("</td>\n " )
441+ .append ("<td><a href=\" " ).append (escapeHtml (vulnerability .getLink ())).append ("\" target=\" _blank\" >Link</a></td>\n " )
442+ .append ("<td>" ).append (escapeHtml (vulnerability .getFeed_rating ())).append ("</td>\n " )
443+ .append ("</tr>\n " );
444+ }
445+ htmlContent .append ("</table>\n " );
446+ }
447+ }
448+ }else {
449+ htmlContent .append ("<p> Your Controller Does Not Support Layer Vulnerability Scan </p>\n " );
450+ }
451+
452+ // Output the found exempted vulnerabilities
453+ if (scanResult .isWhiteListVulExisted ()){
454+ htmlContent .append ("<h3>Exempted Vulnerabilities</h3>\n " );
455+ if (scanResult .getExistedWhiteListVulSet ().size () == 1 ){
456+ htmlContent .append ("<p> " ).append (escapeHtml (scanResult .getExistedWhiteListVulSet ().iterator ().next ().toUpperCase ())).append (" </p>\n " );
457+ }else {
458+ htmlContent .append ("<p> " ).append (String .join (", " , scanResult .getExistedWhiteListVulSet ().stream ().map (this ::escapeHtml ).collect (Collectors .toList ()))).append (" </p>\n " );
459+ }
460+ }
461+
462+ // Close the HTML content
463+ htmlContent .append ("</body>\n </html>" );
464+
465+ // Write the HTML content to file
344466 try (BufferedWriter writer = new BufferedWriter (new FileWriter (reportFile ))) {
345- writer .write (htmlContent );
467+ writer .write (htmlContent . toString () );
346468 }
347- // No need for catch block here if you're just throwing the exceptions
348469 }
349-
470+
350471 private String getVulnerabilityRowHtml (Vulnerability vulnerability , String severity ) {
351472 return "<tr>\n " +
352473 "<td><a target=\" _blank\" href=\" " + escapeHtml (vulnerability .getLink ()) + "\" >" +
353474 escapeHtml (vulnerability .getName ()).toUpperCase () + "</a></td>\n " +
354475 "<td>" + severity + "</td>\n " +
355476 "<td>" + vulnerability .getScore () + "</td>\n " +
356- "<td>" + escapeHtml (vulnerability .getPackage_name () + ":" + vulnerability .getPackage_version ()) + "</td>\n " +
477+ "<td>" + escapeHtml (vulnerability .getPackage_name ()) + ":" + escapeHtml (vulnerability .getPackage_version ()) + "</td>\n " +
478+ "<td>" + escapeHtml (vulnerability .getFile_name ()) + "</td>\n " +
357479 "<td>" + escapeHtml (vulnerability .getFixed_version ()) + "</td>\n " +
358480 "<td>" + escapeHtml (vulnerability .getVectors ()) + "</td>\n " +
359481 "<td>" + escapeHtml (vulnerability .getDescription ()) + "</td>\n " +
360482 "<td>" + escapeHtml (vulnerability .getFeed_rating ()) + "</td>\n " +
361483 "</tr>\n " ;
362484 }
363-
485+
364486 private String escapeHtml (String text ) {
365487 if (text == null ) {
366- return null ; // Return null if the input string is null
488+ return "" ; // Return an empty string if the input string is null
367489 }
368-
369490 return text .replace ("&" , "&" )
370491 .replace ("<" , "<" )
371492 .replace (">" , ">" )
372493 .replace ("\" " , """ )
373494 .replace ("'" , "'" );
374- }
375- }
495+ }
496+ }
0 commit comments