diff options
Diffstat (limited to 'lib/srtgui/reports.py')
-rw-r--r-- | lib/srtgui/reports.py | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/lib/srtgui/reports.py b/lib/srtgui/reports.py index e282a8d0..c207bd84 100644 --- a/lib/srtgui/reports.py +++ b/lib/srtgui/reports.py @@ -1919,6 +1919,198 @@ class PackageFiltersReport(Report): return report_name,os.path.basename(report_name) +############################################################################### +# +# PublishSummaryReport: Publish CVE status summary across products +# + +class PublishSummaryReport(PublishListReport): + """Report for the Publish Cve Page""" + + def __init__(self, parent_page, *args, **kwargs): + _log_args("REPORT_PUBLISHSUMMARY_INIT(%s)" % parent_page, *args, **kwargs) + super(PublishSummaryReport, self).__init__(parent_page, *args, **kwargs) + + def get_context_data(self, *args, **kwargs): + _log_args("REPORT_PUBLISHSUMMARY_CONTEXT", *args, **kwargs) + context = super(PublishSummaryReport, self).get_context_data(*args, **kwargs) + + # Add a custom extension report type + context['report_type_list'] = '\ + <option value="publish_summary">CVE Summary Report</option> \ + ' + + context['report_custom_list'] = '' + # Add scope + context['report_custom_list'] += '\ + <input type="checkbox" id="new" name="new" checked> New CVEs</input> <br>\ + <input type="checkbox" id="investigate" name="investigate" checked> Investigate CVEs</input> <br>\ + <input type="checkbox" id="vulnerable" name="vulnerable" checked> Vulnerable CVEs</input> <br>\ + <input type="checkbox" id="not-vulnerable" name="not-vulnerable" checked> Not Vulnerable CVEs</input> <br>\ + <input type="checkbox" id="new-reserved" name="new-reserved" > New-Reserved CVEs</input> <br>\ + <input type="checkbox" id="historical" name="historical" > Historical CVEs</input> <br>\ + ' + # Add extra + context['report_custom_list'] += '<br>' + context['report_custom_list'] += '\ + <input type="checkbox" id="truncate" name="truncate" checked> Truncate fields (for simple text reports)</input> <BR>\ + ' + + return context + + def get_product_status_matrix(self,product_list,cve): + # Preset the default product status labels + status_table = {} + product_top_order = 99 + product_top_defect = [] + # Default all product status to the CVE's status + for product in product_list: + status_table[product.key] = SRTool.status_text(SRTool.NOT_VULNERABLE) + # Set the specific status for the child investigations + for cv in cve.cve_to_vulnerability.all(): + #status_text = cv.vulnerability.get_status_text + for investigation in cv.vulnerability.vulnerability_investigation.all(): +# product_key = investigation.product.key + release_version_list = [] + # Gather release versions, find the highest product's respective defect + for id in investigation.investigation_to_defect.all(): + # Find defect(s) for higest ordered product + if product_top_order > investigation.product.order: + product_top_order = investigation.product.order + product_top_defect = [] + if product_top_order == investigation.product.order: + product_top_defect.append(id.defect.name) + # Gather the status or release version + if id.defect.release_version: + release_version_list.append(id.defect.release_version) + release_version = '/'.join(release_version_list) + # Set investigation status, unless there are release versions + status_table[investigation.product.key] = investigation.get_status_text + if release_version: + status_table[investigation.product.key] = release_version + return status_table,product_top_defect + + def exec_report(self, *args, **kwargs): + _log_args("REPORT_PUBLISHSUMMARY_EXEC", *args, **kwargs) + super(PublishSummaryReport, self).exec_report(*args, **kwargs) + + request_POST = self.request.POST + format = request_POST.get('format', '') + report_type = request_POST.get('report_type', '') + csv_separator = request_POST.get('csv_separator', 'semi') + truncate = ('on' == request_POST.get('truncate', 'off')) + status_list = [] + if ('on' == request_POST.get('new', 'off')): status_list.append(Cve.NEW) + if ('on' == request_POST.get('investigate', 'off')): status_list.append(Cve.INVESTIGATE) + if ('on' == request_POST.get('vulnerable', 'off')): status_list.append(Cve.VULNERABLE) + if ('on' == request_POST.get('not-vulnerable', 'off')): status_list.append(Cve.NOT_VULNERABLE) + if ('on' == request_POST.get('new-reserved', 'off')): status_list.append(Cve.NEW_RESERVED) + if ('on' == request_POST.get('historical', 'off')): status_list.append(Cve.HISTORICAL) + + # Default to the regular report output if not our custom extension + if not report_type in ('publish_summary'): + return(super(PublishSummaryReport, self).exec_report(*args, **kwargs)) + + if 'csv' == format: + separator = ';' + if csv_separator == 'comma': separator = ',' + if csv_separator == 'tab': separator = '\t' + report_name = '%s/cve-svns-srtool-%s.csv' % (SRT_REPORT_DIR,datetime.today().strftime('%Y_%m_%d')) + else: + separator = "," + report_name = '%s/cve-svns-srtool-%s.txt' % (SRT_REPORT_DIR,datetime.today().strftime('%Y_%m_%d')) + + # Get the desired product list + product_list = Product.objects.order_by('-order') + + if 'publish_summary' == report_type: + with open(report_name, 'w', newline='') as csvfile: + writer = None + + # Assemble the header + text_format = '%-18s,%16s,%-8s,%-8s,%-15s,%-15s,%-30s,%-25s,%15s,%15s,%20s,' + header = [ + 'CVE Number', + 'Status', + 'CVSSv2_Severity', + 'CVSSv2_Score', + 'CVSSv3_Severity', + 'CVSSv3_Score', + 'CVE Description', + 'YP Comments', + 'Created Date', + 'Modified Date', + 'YP Acknowledged Date', + ] + # Assemble the product column namess + for product in product_list: + product_title = product.key + header.append(product_title) + min_len = max(16,len(product_title)+1) + str_format = "%s%ds," % ('%',min_len) + text_format += str_format +# # Add Top Defect +# header.append('Top Defect') +# text_format += '%s' + + # Print the header + if 'csv' == format: + writer = csv.writer(csvfile, delimiter=separator, quotechar='"', quoting=csv.QUOTE_MINIMAL) + writer.writerow(header) + else: + writer = csvfile + print(text_format % tuple(header), file=csvfile) + + for i,cve in enumerate(Cve.objects.filter(status__in=status_list).order_by('name_sort')): + # Compute the product columns + status_table,product_top_defect = self.get_product_status_matrix(product_list,cve) + # Assemble the row data + if cve.description: + if truncate: + description = cve.description[:26] + '...' + else: + description = cve.description + else: + description = '' + + # Use publish date if acknowledge date not available + try: + acknowledge_date = cve.acknowledge_date + if not acknowledge_date: + acknowledge_date = datetime.strptime(cve.publishedDate, '%Y-%m-%d') + acknowledge_date = acknowledge_date.strftime('%m/%d/%Y') + except: + acknowledge_date = '' + _log("NO ACK:%s,%s" % (cve.acknowledge_date,cve.publishedDate)) + + row = [ + cve.name, + cve.get_status_text, + cve.cvssV2_severity, + cve.cvssV2_baseScore, + cve.cvssV3_baseSeverity, + cve.cvssV3_baseScore, + description, + cve.get_public_comments[:20] if truncate else cve.get_public_comments, + cve.srt_created.strftime('%Y/%m/%d') if cve.srt_created else '', + cve.srt_updated.strftime('%Y/%m/%d') if cve.srt_updated else '', + acknowledge_date, + ] + # Append the product columns + for product in product_list: + # Show inactive status as normal status + row.append(status_table[product.key].replace('(','').replace(')','')) +# row.append('/'.join(product_top_defect)) + # Print the row + if 'csv' == format: + writer.writerow(row) + else: + print(text_format % tuple(row), file=writer) + + + return report_name,os.path.basename(report_name) + + class CpesSrtoolReport(Report): """Report for the Publish Cve Page""" @@ -2177,6 +2369,8 @@ class ReportManager(): return PublishListReport(parent_page, *args, **kwargs) elif 'publish-list' == parent_page: return PublishListReport(parent_page, *args, **kwargs) + elif 'publish-summary' == parent_page: + return PublishSummaryReport(parent_page, *args, **kwargs) elif 'package-filters' == parent_page: return PackageFiltersReport(parent_page, *args, **kwargs) |