Skip to content

Commit 3b90fe7

Browse files
committed
[NVSHAS-8744] Add txt report and add file_name in html and txt report
1 parent 8f1fb03 commit 3b90fe7

File tree

2 files changed

+209
-79
lines changed

2 files changed

+209
-79
lines changed

src/main/java/neuvector/NeuVectorScannerTask.java

Lines changed: 200 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.HashSet;
2222
import java.util.Set;
2323
import java.util.LinkedHashMap;
24+
import java.util.stream.Collectors;
2425

2526
import neuvector.report.*;
2627
import 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("&", "&amp;")
370491
.replace("<", "&lt;")
371492
.replace(">", "&gt;")
372493
.replace("\"", "&quot;")
373494
.replace("'", "&#039;");
374-
}
375-
}
495+
}
496+
}

0 commit comments

Comments
 (0)