aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcody.yu@windriver.com <cody.yu@windriver.com>2020-02-02 23:00:58 +0000
committercody.yu@windriver.com <cody.yu@windriver.com>2020-02-02 23:00:58 +0000
commit6eec97690201b4136c0490fcfb92fb1c63165014 (patch)
tree1c0473c41ce0af5598962484e08a550d7be3432e
parent91a0a241372e683b611d5147ab87bd3a9458b2d1 (diff)
downloadsrtool-6eec97690201b4136c0490fcfb92fb1c63165014.zip
srtool-6eec97690201b4136c0490fcfb92fb1c63165014.tar.gz
srtool-6eec97690201b4136c0490fcfb92fb1c63165014.tar.bz2
srtool: extend 'Affected Components', add Error Log
* Add "Affected Components" to VUL/INV/DEF, with automatic inheritance on creation from respective parent records. With this is a one-time fixup routine to populate these new fields: ./bin/common/srtool_utils.py \ --fix-inherit-affected-components -f * Add "Error Log", to capture internal errors in a formal table and view. Management > Maintenance > Error Logs * Sort the Product list when add product investigation links to Vulnerability records. * Add Reports for Notification and Error Log * Other small fixes Signed-off-by: david.reyna@windriver.com <david.reyna@windriver.com>
-rwxr-xr-xbin/common/srtool_utils.py149
-rw-r--r--lib/orm/models.py34
-rw-r--r--lib/srtgui/api.py7
-rw-r--r--lib/srtgui/reports.py227
-rw-r--r--lib/srtgui/tables.py100
-rw-r--r--lib/srtgui/templates/defect.html3
-rw-r--r--lib/srtgui/templates/investigation.html5
-rwxr-xr-xlib/srtgui/templates/maintenance.html4
-rw-r--r--lib/srtgui/templates/management.html6
-rwxr-xr-xlib/srtgui/templates/srtool_metadata_include.html10
-rw-r--r--lib/srtgui/templates/vulnerability.html2
-rw-r--r--lib/srtgui/urls.py6
-rw-r--r--lib/srtgui/views.py59
13 files changed, 573 insertions, 39 deletions
diff --git a/bin/common/srtool_utils.py b/bin/common/srtool_utils.py
index 30ad1e9..4d9c27c 100755
--- a/bin/common/srtool_utils.py
+++ b/bin/common/srtool_utils.py
@@ -1731,6 +1731,101 @@ def fix_bad_score_date():
conn.commit()
#################################
+# fix_inherit_affected_components()
+#
+# Inherit the "Affected Components" from CVEs
+# to the new field of their children VUL/INV/DEF
+
+def fix_inherit_affected_components():
+
+ conn = sqlite3.connect(srtDbName)
+ cur_cve = conn.cursor()
+ cur_cve2vul = conn.cursor()
+ cur_vul = conn.cursor()
+ cur_vul2inv = conn.cursor()
+ cur_inv = conn.cursor()
+ cur_inv2def = conn.cursor()
+ cur_def = conn.cursor()
+ cur_write = conn.cursor()
+
+ def merge_affected_components(alist,blist):
+ affected_components = ''
+ affected_components_list = {}
+ for package in alist.split():
+ affected_components_list[package] = True
+ for package in blist.split():
+ affected_components_list[package] = True
+ if affected_components_list:
+ affected_components = ' '.join(affected_components_list)
+ return(affected_components)
+
+ updates = 0
+ cur_cve.execute('SELECT * FROM orm_cve')
+ for i,cve in enumerate(cur_cve):
+ cve_affect_components = cve[ORM.CVE_PACKAGES]
+ if not cve_affect_components:
+ continue
+ print("CVE:%s, '%s'" % (cve[ORM.CVE_NAME],cve_affect_components))
+
+ # Find all related Vulnerabilities
+ cur_cve2vul.execute('SELECT * FROM orm_cvetovulnerablility WHERE cve_id = %d' % cve[ORM.CVE_ID])
+ for cve2vul in cur_cve2vul:
+ # Update the Vulnerability status
+ cur_vul.execute('SELECT * FROM orm_vulnerability WHERE id = %d' % cve2vul[ORM.CVETOVULNERABLILITY_VULNERABILITY_ID])
+ for vul in cur_vul:
+ vul_affected_components = merge_affected_components(cve_affect_components,vul[ORM.VULNERABILITY_PACKAGES])
+ if vul_affected_components != vul[ORM.VULNERABILITY_PACKAGES]:
+ updates += 1
+ if force:
+ sql = ''' UPDATE orm_vulnerability
+ SET packages = ?
+ WHERE id = ?'''
+ cur_write.execute(sql, (vul_affected_components, vul[ORM.VULNERABILITY_ID],))
+ print(" Vul:%s, '%s' to '%s'" % (vul[ORM.VULNERABILITY_NAME],vul[ORM.VULNERABILITY_PACKAGES],vul_affected_components))
+
+ # Find all related Investigations
+ cur_vul2inv.execute('SELECT * FROM orm_vulnerabilitytoinvestigation WHERE vulnerability_id = %d' % vul[ORM.VULNERABILITY_ID])
+ for vul2inv in cur_vul2inv:
+ # Update the Investigation status
+ cur_inv.execute('SELECT * FROM orm_investigation WHERE id = %d' % vul2inv[ORM.VULNERABILITYTOINVESTIGATION_INVESTIGATION_ID])
+ for inv in cur_inv:
+ inv_affected_components = merge_affected_components(vul_affected_components,inv[ORM.INVESTIGATION_PACKAGES])
+ if inv_affected_components != inv[ORM.INVESTIGATION_PACKAGES]:
+ updates += 1
+ if force:
+ sql = ''' UPDATE orm_investigation
+ SET packages = ?
+ WHERE id = ?'''
+ cur_write.execute(sql, (inv_affected_components, inv[ORM.INVESTIGATION_ID],))
+ print(" Inv:%s, '%s' to '%s'" % (inv[ORM.INVESTIGATION_NAME],inv[ORM.INVESTIGATION_PACKAGES],inv_affected_components))
+
+ # Find all related Defects
+ cur_inv2def.execute('SELECT * FROM orm_investigationtodefect WHERE investigation_id = %d' % inv[ORM.INVESTIGATION_ID])
+ for inv2def in cur_inv2def:
+ # Update the Defect status
+ cur_def.execute('SELECT * FROM orm_defect WHERE id = %d' % inv2def[ORM.INVESTIGATIONTODEFECT_DEFECT_ID])
+ for defect in cur_def:
+ defect_affected_components = merge_affected_components(inv_affected_components,defect[ORM.DEFECT_PACKAGES])
+ if defect_affected_components != defect[ORM.DEFECT_PACKAGES]:
+ updates += 1
+ if force:
+ sql = ''' UPDATE orm_defect
+ SET packages = ?
+ WHERE id = ?'''
+ cur_write.execute(sql, (defect_affected_components, defect[ORM.DEFECT_ID],))
+ print(" Defect:%s, '%s' to '%s'" % (defect[ORM.DEFECT_NAME],defect[ORM.DEFECT_PACKAGES],defect_affected_components))
+
+ if 999 == (i % 1000) :
+ print("%7d: %-20s %6d\r" % (i+1,cve[ORM.CVE_NAME],updates),end='')
+ if force: conn.commit()
+# if 60000 < i:
+# break
+
+ if updates and force: conn.commit()
+ print("Affected Component Updates = %d" % updates)
+
+
+#################################
# report_cve_status_summary()
#
# Report the distribution of the CVE status and V3/V2
@@ -2027,13 +2122,13 @@ def report_db_status_summary():
cur_inv = conn.cursor()
cur_inv2def = conn.cursor()
cur_def = conn.cursor()
- cur_cve.execute('SELECT * FROM orm_cve')
#
# Year-specific table_status
#
i = 0
+ cur_cve.execute('SELECT * FROM orm_cve')
for count,cve in enumerate(cur_cve):
year = int(cve[ORM.CVE_NAME].split('-')[1])
@@ -2367,6 +2462,52 @@ def report_unattached_records():
# extract product,cve, defect [Defect Status,Defect Resolution]
# see if CVE has VUL has INV for the product
+#################################
+# fix_duplicate_notifications
+#
+# Remove older duplicate notifications
+#
+
+def fix_duplicate_notifications():
+
+ conn = sqlite3.connect(srtDbName)
+ cur = conn.cursor()
+ cur_del = conn.cursor()
+
+ notify_descriptions = {}
+ delete_list = []
+ delete_count = 0
+
+ cur.execute('SELECT * FROM orm_notify ORDER BY srt_created DESC;')
+ for i,notify in enumerate(cur):
+ description = notify[ORM.NOTIFY_DESCRIPTION]
+ if description in notify_descriptions:
+ delete_count += 1
+ delete_list.append(notify[ORM.NOTIFY_ID])
+ else:
+ notify_descriptions[description] = True
+
+ # Progress indicator support
+ if (0 == i % 5000):
+ print('%05d:%05d\r' % (i,delete_count), end='')
+
+ print("")
+ if force:
+ print("Deleting %d..." % len(delete_list))
+ for i,id in enumerate(delete_list):
+ sql = 'DELETE FROM orm_notify WHERE id=?'
+ ret = cur_del.execute(sql, (id,))
+ if (0 == i % 1000):
+ print('%05d:\r' % (i), end='')
+ if (0 == i % 10000):
+ time.sleep(0.1)
+ conn.commit()
+ conn.commit()
+
+ print("")
+ print('Delete count = %d of %d, Unique = %d' % (delete_count,i,len(notify_descriptions)))
+ #print(notify_descriptions)
+ conn.close()
#################################
# main loop
@@ -2401,11 +2542,13 @@ def main(argv):
parser.add_argument('--fix-bad-mitre-descr', dest='fix_bad_mitre_descr', help='Fix MITRE that were created with empty descriptions')
parser.add_argument('--fix-bad-score-date', action='store_const', const='fix_bad_score_date', dest='command', help='Clear score dates to fix obsolete formats')
parser.add_argument('--fix-trim-cve-scores', action='store_const', const='fix_trim_cve_scores', dest='command', help='Trim V3/V2 scores to one decimal place standard')
+ parser.add_argument('--fix-inherit-affected-components', action='store_const', const='fix_inherit_affected_components', dest='command', help='Inherit the affected components field from CVE to its children')
# Continuous maintenance validation and repair routines
parser.add_argument('--fix-bad-links', action='store_const', const='fix_bad_links', dest='command', help='Find bad links, e.g. "orm_cvesource" (add "-f" to fix)')
parser.add_argument('--fix-severity', dest='fix_severity', help='Find bad score/severity values, broken cve source links {ALL|"NIST 2020[,...]*"} (add "-f" to fix)')
+ parser.add_argument('--fix-duplicate-notifications', action='store_const', const='fix_duplicate_notifications', dest='command', help='Removed older duplicate notifications')
parser.add_argument('--report-multiple-defects', action='store_const', const='report_multiple_defects', dest='command', help='Report multiple defects per investigations')
parser.add_argument('--report-duplicate-names', action='store_const', const='report_duplicate_names', dest='command', help='Report duplicate names for CVE,VUL,INV,DEF')
@@ -2484,11 +2627,15 @@ def main(argv):
fix_bad_mitre_descr(args.fix_bad_mitre_descr)
elif 'fix_bad_score_date' == args.command:
fix_bad_score_date()
+ elif 'fix_inherit_affected_components' == args.command:
+ fix_inherit_affected_components()
elif args.fix_severity:
fix_severity(args.fix_severity)
elif 'fix_trim_cve_scores' == args.command:
fix_trim_cve_scores()
+ elif 'fix_duplicate_notifications' == args.command:
+ fix_duplicate_notifications()
elif 'report_multiple_defects' == args.command:
report_multiple_defects()
diff --git a/lib/orm/models.py b/lib/orm/models.py
index 47d5941..9b4f99c 100644
--- a/lib/orm/models.py
+++ b/lib/orm/models.py
@@ -553,6 +553,7 @@ class Cve(models.Model):
cvssV2_baseScore = models.CharField(max_length=50, blank=True)
cvssV2_severity = models.CharField(max_length=50, blank=True)
+ # AKA Affected Components
packages = models.TextField(blank=True)
score_date = models.DateField(null=True, blank=True)
@@ -949,6 +950,9 @@ class Vulnerability(models.Model):
outcome = models.IntegerField(choices=OUTCOME, default=OPEN)
priority = models.IntegerField(choices=PRIORITY, default=LOW)
+ # AKA Affected Components
+ packages = models.TextField(blank=True)
+
srt_updated = models.DateTimeField(auto_now=True, null=True)
srt_created = models.DateTimeField(auto_now_add=True, null=True)
@@ -1161,6 +1165,9 @@ class Defect(models.Model):
date_created = models.CharField(max_length=50)
date_updated = models.CharField(max_length=50)
+ # AKA Affected Components
+ packages = models.TextField(blank=True)
+
srt_updated = models.DateTimeField(auto_now=True)
# Methods
@@ -1292,6 +1299,9 @@ class Investigation(models.Model):
outcome = models.IntegerField(choices=OUTCOME, default=INVESTIGATE)
priority = models.IntegerField(choices=PRIORITY, default=LOW)
+ # AKA Affected Components
+ packages = models.TextField(blank=True)
+
srt_updated = models.DateTimeField(auto_now=True, null=True)
srt_created = models.DateTimeField(auto_now_add=True, null=True)
@@ -1415,8 +1425,6 @@ class Notify(models.Model):
priority = models.IntegerField(default=0)
url = models.TextField(blank=True)
author = models.TextField(blank=True)
-## srt_updated = models.DateTimeField(auto_now_add=True)
-## srt_created = models.DateTimeField(auto_now=True)
srt_updated = models.DateTimeField(auto_now=True, null=True)
srt_created = models.DateTimeField(auto_now_add=True, null=True)
@@ -1462,6 +1470,28 @@ class PublishSet(models.Model):
return self.PUBLISH_SET_STATE[self.PUBLISH_SET_ERROR][1]
return self.PUBLISH_SET_STATE[self.state][1]
+# Error Log
+class ErrorLog(models.Model):
+ search_allowed_fields = ['description']
+
+ # Severity
+ INFO = 0
+ WARNING = 1
+ ERROR = 2
+ SEVERITY = (
+ (INFO, 'Info'),
+ (WARNING, 'Warning'),
+ (ERROR, 'Error'),
+ )
+
+ severity = models.IntegerField(default=0)
+ description = models.TextField(blank=True)
+ srt_created = models.DateTimeField(auto_now_add=True, null=True)
+
+ @property
+ def get_severity_text(self):
+ return ErrorLog.SEVERITY[int(self.severity)][1]
+
#
# Database Cache Support
#
diff --git a/lib/srtgui/api.py b/lib/srtgui/api.py
index e84113a..761839a 100644
--- a/lib/srtgui/api.py
+++ b/lib/srtgui/api.py
@@ -47,6 +47,13 @@ def _log(msg):
f1.write("|" + msg + "|\n" )
f1.close()
+def error_log(severity,description):
+ from orm.models import ErrorLog
+ if (severity < ErrorLog.INFO) or (severity > ErrorLog.ERROR):
+ severity = ErrorLog.ERROR
+ error = ErrorLog.objects.create(severity=severity,description=description,)
+ error.save()
+
# Sub Process calls
def execute_process(*args):
cmd_list = []
diff --git a/lib/srtgui/reports.py b/lib/srtgui/reports.py
index a1f0de0..715c560 100644
--- a/lib/srtgui/reports.py
+++ b/lib/srtgui/reports.py
@@ -20,13 +20,14 @@
import os
import logging
-from datetime import datetime
+from datetime import datetime, timedelta
import csv
from orm.models import Cve, CveSource, Vulnerability, Investigation, Defect, Product
from orm.models import Package
from orm.models import SRTool, SrtSetting
from orm.models import PublishSet, DefectHistory
+from orm.models import Notify, ErrorLog
from srtgui.api import readCveDetails, summaryCveDetails
from django.db.models import Q
@@ -2273,7 +2274,7 @@ class HistoryDefectReport(Report):
separator = ";"
if csv_separator == 'comma': separator = ","
if csv_separator == 'tab': separator = "\t"
- writer = csv.writer(csvfile, delimiter=separator,
+ writer = csv.writer(report_name, delimiter=separator,
quotechar='"', quoting=csv.QUOTE_MINIMAL)
else:
separator = ","
@@ -2297,6 +2298,223 @@ class HistoryDefectReport(Report):
###############################################################################
#
+# Notifications reports
+#
+
+class NotificationsReport(Report):
+ """Report for the Notifications Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("WR_NOTIFICATION_INIT(%s)" % parent_page, *args, **kwargs)
+ super(NotificationsReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("WR_NOTIFICATION_CONTEXT", *args, **kwargs)
+ context = super(NotificationsReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Notification List</option> \
+ '
+
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV \
+ (Separator: \
+ <select name="csv_separator"> \
+ <option value="semi">Semi-colon</option> \
+ <option value="comma">Comma</option> \
+ <option value="tab">Tab</option> \
+ </select>) \
+ <br> \
+ '
+
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="all"> All<br> \
+ '
+
+ # Add a date range
+ date_start = datetime.today() - timedelta(days=30)
+ date_stop = datetime.today()
+ context['report_date_list'] = '\
+ Start: <input type="text" name="date_start" value="%s"><br> \
+ Stop: <input type="text" name="date_stop" value="%s"> \
+ ' % (date_start.strftime('%m/%d/%Y'),date_stop.strftime('%m/%d/%Y'))
+
+ # Done!
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("WR_NOTIFICATION_EXEC", *args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+# title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+ csv_separator = request_POST.get('csv_separator', 'semi')
+
+ # Dates (make as no timezone)
+ msg = ''
+ try:
+ msg = 'Start:%s' % request_POST.get('date_start', '')
+ date_start = datetime.strptime(request_POST.get('date_start', ''), '%m/%d/%Y')
+ msg = 'Stop:%s' % request_POST.get('date_stop', '')
+ date_stop = datetime.strptime(request_POST.get('date_stop', ''), '%m/%d/%Y')
+ if date_stop < date_start:
+ return 'Error:stop date is before start date',''
+ except Exception as e:
+ return 'Error:bad format for dates (must be mm/dd/yyyy) (%s)(%s)' % (msg,e),''
+
+ date_start = date_start.strftime('%Y-%m-%d')
+ date_stop = date_stop.strftime('%Y-%m-%d')
+
+ report_name = '%s/notifications_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d_%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ separator = ";"
+ if csv_separator == 'comma': separator = ","
+ if csv_separator == 'tab': separator = "\t"
+ writer = csv.writer(file, delimiter=separator,
+ quotechar='"', quoting=csv.QUOTE_MINIMAL)
+ else:
+ separator = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ writer.writerow(['Date','Category','Priority','Decription','URL','Author'])
+ if 'txt' == format:
+ file.write("Report : Notifications\n")
+ file.write("\n")
+ text_format='%02d) %-10s %-25s %-10s "%s",%s,%s\n'
+ file.write(text_format % (0,'Date','Category','Priority','Decription','URL','Author'))
+
+# for i,notify in enumerate(Notify.objects.filter(srt_updated__gte=date_start,srt_updated__lte=date_stop).order_by('-srt_updated')):
+ for i,notify in enumerate(Notify.objects.all().order_by('-srt_updated')):
+ srt_updated = notify.srt_updated.strftime('%Y-%m-%d')
+ if (date_start > srt_updated) or (date_stop < srt_updated):
+ continue
+
+ if 'csv' == format:
+ writer.writerow([i+1,srt_updated,notify.category,notify.get_priority_text,notify.description,notify.url,notify.author])
+ if 'txt' == format:
+ file.write(text_format % (i+1,srt_updated,notify.category,notify.get_priority_text,notify.description,notify.url,notify.author))
+
+ return report_name,os.path.basename(report_name)
+
+###############################################################################
+#
+# ErrorLogs reports
+#
+
+class ErrorLogsReport(Report):
+ """Report for the Error Logs Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("WR_ERRORLOGS_INIT(%s)" % parent_page, *args, **kwargs)
+ super(ErrorLogsReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("WR_ERRORLOGS_CONTEXT", *args, **kwargs)
+ context = super(ErrorLogsReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Error Log List</option> \
+ '
+
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV \
+ (Separator: \
+ <select name="csv_separator"> \
+ <option value="semi">Semi-colon</option> \
+ <option value="comma">Comma</option> \
+ <option value="tab">Tab</option> \
+ </select>) \
+ <br> \
+ '
+
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="all"> All<br> \
+ '
+
+ # Add a date range
+ date_start = datetime.today() - timedelta(days=30)
+ date_stop = datetime.today()
+ context['report_date_list'] = '\
+ Start: <input type="text" name="date_start" value="%s"><br> \
+ Stop: <input type="text" name="date_stop" value="%s"> \
+ ' % (date_start.strftime('%m/%d/%Y'),date_stop.strftime('%m/%d/%Y'))
+
+ # Done!
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("WR_ERRORLOGS_EXEC", *args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+# title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+ csv_separator = request_POST.get('csv_separator', 'semi')
+
+ # Dates (make as no timezone)
+ msg = ''
+ try:
+ msg = 'Start:%s' % request_POST.get('date_start', '')
+ date_start = datetime.strptime(request_POST.get('date_start', ''), '%m/%d/%Y')
+ msg = 'Stop:%s' % request_POST.get('date_stop', '')
+ date_stop = datetime.strptime(request_POST.get('date_stop', ''), '%m/%d/%Y')
+ if date_stop < date_start:
+ return 'Error:stop date is before start date',''
+ except Exception as e:
+ return 'Error:bad format for dates (must be mm/dd/yyyy) (%s)(%s)' % (msg,e),''
+
+ date_start = date_start.strftime('%Y-%m-%d')
+ date_stop = date_stop.strftime('%Y-%m-%d')
+
+ report_name = '%s/errorlogs_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d_%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ separator = ";"
+ if csv_separator == 'comma': separator = ","
+ if csv_separator == 'tab': separator = "\t"
+ writer = csv.writer(file, delimiter=separator,
+ quotechar='"', quoting=csv.QUOTE_MINIMAL)
+ else:
+ separator = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ writer.writerow(['Date','Severity','Decription'])
+ if 'txt' == format:
+ file.write("Report : Error Logs\n")
+ file.write("Start=%s,Stop=%s\n" % (date_start,date_stop))
+ text_format='%02d) %-10s %-10s "%s"\n'
+ file.write(text_format % (0,'Date','Severity','Decription'))
+
+# for i,notify in enumerate(ErrorLog.objects.filter(srt_created__gte=date_start,srt_created__lte=date_stop).order_by('-srt_created')):
+ for i,notify in enumerate(ErrorLog.objects.all().order_by('-srt_created')):
+ srt_created = notify.srt_created.strftime('%Y-%m-%d')
+ if (date_start > srt_created) or (date_stop < srt_created):
+ continue
+ if 'csv' == format:
+ writer.writerow([i+1,srt_created,notify.severity,notify.description])
+ if 'txt' == format:
+ file.write(text_format % (i+1,srt_created,notify.get_severity_text,notify.description))
+
+ return report_name,os.path.basename(report_name)
+
+###############################################################################
+#
class DefaultReport(Report):
"""Report for the Default Page"""
@@ -2377,6 +2595,11 @@ class ReportManager():
elif 'cpes_srtool' == parent_page:
return CpesSrtoolReport(parent_page, *args, **kwargs)
+ elif 'manage_notifications' == parent_page:
+ return NotificationsReport(parent_page, *args, **kwargs)
+ elif 'error_logs' == parent_page:
+ return ErrorLogsReport(parent_page, *args, **kwargs)
+
elif 'history_defect' == parent_page:
return HistoryDefectReport(parent_page, *args, **kwargs)
diff --git a/lib/srtgui/tables.py b/lib/srtgui/tables.py
index e0a6fb4..b8ff6f6 100644
--- a/lib/srtgui/tables.py
+++ b/lib/srtgui/tables.py
@@ -23,6 +23,7 @@ import re
import json
from srtgui.widgets import ToasterTable
+from orm.models import SRTool
from orm.models import Cve, Vulnerability, Investigation, CweTable, Product
from orm.models import Package
from orm.models import CpeTable, CpeFilter, Defect, DataSource, SrtSetting
@@ -30,6 +31,7 @@ from orm.models import PublishPending
from orm.models import Notify, NotifyCategories
from orm.models import CveHistory, VulnerabilityHistory, InvestigationHistory, DefectHistory
from orm.models import PublishSet
+from orm.models import ErrorLog
from users.models import UserSafe
from django.db.models import Q
@@ -593,31 +595,31 @@ class DefectsTable(ToasterTable):
# SRT Priority filter
is_srt_priority = TableFilter(name="is_srt_priority",
- title="Filter defects by 'Priority'")
- for priority in range(len(Defect.SRT_PRIORITY)):
- if Defect.PRIORITY_ERROR == Defect.SRT_PRIORITY[priority][0]:
+ title="Filter defects by 'SRT Priority'")
+ for priority in range(len(SRTool.SRT_PRIORITY)):
+ if SRTool.PRIORITY_ERROR == SRTool.SRT_PRIORITY[priority][0]:
continue
is_srt_priority.add_action(TableFilterActionToggle(
- Defect.SRT_PRIORITY[priority][1].lower().replace(' ','_'),
- Defect.SRT_PRIORITY[priority][1],
- Q(priority=Defect.SRT_PRIORITY[priority][0]))
+ SRTool.SRT_PRIORITY[priority][1].lower().replace(' ','_'),
+ SRTool.SRT_PRIORITY[priority][1],
+ Q(priority=SRTool.SRT_PRIORITY[priority][0]))
)
self.add_filter(is_srt_priority)
# SRTool Status filter
is_srt_status = TableFilter(name="is_srt_status",
- title="Filter defects by 'Status'")
- for status in range(len(Defect.SRT_STATUS)):
+ title="Filter defects by 'SRT Status'")
+ for status in range(len(SRTool.SRT_STATUS)):
is_srt_status.add_action(TableFilterActionToggle(
- Defect.SRT_STATUS[status][1].lower().replace(' ','_'),
- Defect.SRT_STATUS[status][1],
- Q(status=Defect.SRT_STATUS[status][0]))
+ SRTool.SRT_STATUS[status][1].lower().replace(' ','_'),
+ SRTool.SRT_STATUS[status][1],
+ Q(status=SRTool.SRT_STATUS[status][0]))
)
self.add_filter(is_srt_status)
# SRTool Outcome filter
is_srt_outcome = TableFilter(name="is_srt_outcome",
- title="Filter defects by 'Outcome'")
+ title="Filter defects by 'SRT Outcome'")
for status in range(len(Defect.SRT_OUTCOME)):
is_srt_outcome.add_action(TableFilterActionToggle(
Defect.SRT_OUTCOME[status][1].lower().replace(' ','_'),
@@ -2057,7 +2059,7 @@ class NotificationsTable(ToasterTable):
orderable=True,
field_name="srt_created",
static_data_name="srt_created",
- static_data_template='{{data.srt_updated | date:"m/d/y H:i"}}'
+ static_data_template='{{data.srt_created | date:"m/d/y H:i"}}'
)
self.add_column(title="Category",
@@ -2120,14 +2122,70 @@ class NotificationsTable(ToasterTable):
# static_data_template='''{{data.author.name}}''',
# )
- manage_link_template = '''
- <span class="glyphicon glyphicon-edit edit-notify" id="notify_edit_'+{{data.id}}+'" x-data="{{data.id}}"></span>
- '''
-# <span class="glyphicon glyphicon-trash trash-notify" id="notify_trash_'+{{data.id}}+'" x-data="{{data.id}}"></span>
- self.add_column(title="Manage",
- static_data_name="manage",
- static_data_template=manage_link_template,
- )
+ if False:
+ manage_link_template = '''
+ <span class="glyphicon glyphicon-edit edit-notify" id="notify_edit_'+{{data.id}}+'" x-data="{{data.id}}"></span>
+ '''
+# <span class="glyphicon glyphicon-trash trash-notify" id="notify_trash_'+{{data.id}}+'" x-data="{{data.id}}"></span>
+ self.add_column(title="Manage",
+ static_data_name="manage",
+ static_data_template=manage_link_template,
+ )
+
+
+class ErrorLogsTable(ToasterTable):
+ """Table of ErrorLogs in SRTool"""
+
+ def __init__(self, *args, **kwargs):
+ super(ErrorLogsTable, self).__init__(*args, **kwargs)
+ self.default_orderby = "-srt_created"
+
+ def get_context_data(self,**kwargs):
+ context = super(ErrorLogsTable, self).get_context_data(**kwargs)
+ return context
+
+ def setup_queryset(self, *args, **kwargs):
+ self.queryset = ErrorLog.objects.all()
+ self.queryset = self.queryset.order_by(self.default_orderby)
+
+ def setup_columns(self, *args, **kwargs):
+
+ self.add_column(title="Select",
+ field_name="Select",
+ hideable=False,
+ static_data_name="select",
+ static_data_template='<input type="checkbox" value="{{data.pk}}" name="select-notify" />',
+ )
+
+ self.add_column(title="SRT Created",
+ hideable=False,
+ orderable=True,
+ field_name="srt_created",
+ static_data_name="srt_created",
+ static_data_template='{{data.srt_created | date:"m/d/y H:i"}}'
+ )
+
+ self.add_column(title="Severity",
+ field_name="severity",
+ orderable=True,
+ static_data_name="severity",
+ static_data_template='''{{ data.get_severity_text }}''',
+ )
+
+ self.add_column(title="Description",
+ field_name="description",
+ hideable=False,
+ orderable=True,
+ )
+
+ if False:
+ manage_link_template = '''
+ <span class="glyphicon glyphicon-trash trash-errorlog" id="errorlog_trash_'+{{data.id}}+'" x-data="{{data.id}}"></span>
+ '''
+ self.add_column(title="Manage",
+ static_data_name="manage",
+ static_data_template=manage_link_template,
+ )
class PackageFilterTable(ToasterTable):
diff --git a/lib/srtgui/templates/defect.html b/lib/srtgui/templates/defect.html
index ed00fd9..2cae951 100644
--- a/lib/srtgui/templates/defect.html
+++ b/lib/srtgui/templates/defect.html
@@ -63,6 +63,9 @@
<dt>SRTool Outcome:</dt>
<dd>{{object.get_outcome_text}}</dd>
+ <dt>Affected Components:</dt>
+ <dd>{{object.packages}}</dd>
+
<dt>Publish:</dt>
<dd>{{object.publish}}</dd>
diff --git a/lib/srtgui/templates/investigation.html b/lib/srtgui/templates/investigation.html
index f934d05..c2bf92d 100644
--- a/lib/srtgui/templates/investigation.html
+++ b/lib/srtgui/templates/investigation.html
@@ -477,6 +477,9 @@ Created={{object.srt_created}} Updated={{object.srt_updated}}
alert("error on request:\n" + data.error);
return;
}
+ if (data.note.startsWith("DEFECT-")) {
+ alert("ERROR:Defect creation failed, temporary defect '" + data.note + "' created. See Error Log.");
+ }
// reload the page with the updated tables
location.reload(true);
}
@@ -745,6 +748,7 @@ Created={{object.srt_created}} Updated={{object.srt_updated}}
var priority=$('#select-priority-state').val();
var status=$('#select-status-state').val();
var outcome=$('#select-outcome-state').val();
+ var affected_components=$('#text-affected-components').val();
postCommitAjaxRequest({
"action" : 'submit-quickedit',
"priority" : priority,
@@ -753,6 +757,7 @@ Created={{object.srt_created}} Updated={{object.srt_updated}}
"private_note" : private_note,
"tags" : tags,
"outcome" : outcome,
+ "affected_components" : affected_components,
});
});
diff --git a/lib/srtgui/templates/maintenance.html b/lib/srtgui/templates/maintenance.html
index 63c60f3..a0bb184 100755
--- a/lib/srtgui/templates/maintenance.html
+++ b/lib/srtgui/templates/maintenance.html
@@ -25,6 +25,10 @@
</thead>
<tr>
+ <td><a class="btn btn-info btn-lg" href="{% url 'error_logs' %}">Error Logs</a></td>
+ <td>Examine Error Logs ({{errorlog_total}})</td>
+ </tr>
+ <tr>
<td><a class="btn btn-info btn-lg" href="{% url 'history_cve' %}">History CVE</a></td>
<td>Examine History for CVEs</td>
</tr>
diff --git a/lib/srtgui/templates/management.html b/lib/srtgui/templates/management.html
index 9b1e645..b99f461 100644
--- a/lib/srtgui/templates/management.html
+++ b/lib/srtgui/templates/management.html
@@ -26,12 +26,12 @@
<tr>
<td><a class="btn btn-info btn-lg" href="{% url 'triage_cves' %}">Triage CVE's</a></td>
- <td>Triage the CVE's</td>
+ <td>Triage the CVE's ({{cve_new}})</td>
</tr>
<tr>
<td><a class="btn btn-info btn-lg" href="{% url 'manage_notifications' %}">Pending notifications</a></td>
- <td>Triage the pending notifications</td>
+ <td>Triage the pending notifications ({{notification_total}})</td>
</tr>
<tr>
@@ -57,7 +57,7 @@
<tr>
<td><a class="btn btn-info btn-lg" href="{% url 'maintenance' %}?nocache=1">Maintenance</a></td>
- <td>Maintenance utilities</td>
+ <td>Maintenance utilities ({{errorlog_total}})</td>
</tr>
{% endif %}
diff --git a/lib/srtgui/templates/srtool_metadata_include.html b/lib/srtgui/templates/srtool_metadata_include.html
index eb83c05..05c62d3 100755
--- a/lib/srtgui/templates/srtool_metadata_include.html
+++ b/lib/srtgui/templates/srtool_metadata_include.html
@@ -30,11 +30,9 @@
<LI>
<i>Tags:</i> {{object.tags}}
</LI>
- {% if default_category == "CVE" %}
- <LI>
- <i>Affected Components:</i> {{object.packages}}
- </LI>
- {% endif %}
+ <LI>
+ <i>Affected Components:</i> {{object.packages}}
+ </LI>
</UL>
</fieldset>
@@ -92,8 +90,8 @@
<p>Private Comments: <input type="text" placeholder="Edit private comments" id="text-private-note" size="80" value="{{object.comments_private}}"></p>
{% endif %}
<p>Tags: <input type="text" placeholder="Edit tags" id="text-tags" size="80" value="{{object.tags}}"></p>
+ <p>Affected Components: <input type="text" placeholder="Edit affected components" id="text-affected-components" size="80" value="{{object.packages}}"></p>
{% if default_category == "CVE" %}
- <p>Affected Components: <input type="text" placeholder="Edit affected components" id="text-affected-components" size="80" value="{{object.packages}}"></p>
<i>Acknowledge Date</i> = <input type="text" placeholder="Acknowledge Date" id="text-acknowledge-date" size="40" value="{{object.acknowledge_date|date:'Y-m-d'}}"> (YYYY-MM-DD, or empty string for None)<p>
{% endif %}
<p><p>
diff --git a/lib/srtgui/templates/vulnerability.html b/lib/srtgui/templates/vulnerability.html
index 9290a1e..cd17473 100644
--- a/lib/srtgui/templates/vulnerability.html
+++ b/lib/srtgui/templates/vulnerability.html
@@ -716,6 +716,7 @@ Created={{object.srt_created}} Updated={{object.srt_updated}}
var priority=$('#select-priority-state').val();
var status=$('#select-status-state').val();
var outcome=$('#select-outcome-state').val();
+ var affected_components=$('#text-affected-components').val();
postCommitAjaxRequest({
"action" : 'submit-quickedit',
"note" : note,
@@ -724,6 +725,7 @@ Created={{object.srt_created}} Updated={{object.srt_updated}}
"status" : status,
"outcome" : outcome,
"priority" : priority,
+ "affected_components" : affected_components,
});
});
diff --git a/lib/srtgui/urls.py b/lib/srtgui/urls.py
index c0df1c8..ef91f16 100644
--- a/lib/srtgui/urls.py
+++ b/lib/srtgui/urls.py
@@ -126,6 +126,9 @@ urlpatterns = [
url(r'^xhr_notifications/$', views.xhr_notifications,
name='xhr_notifications'),
+ url(r'^xhr_errorlogs/$', views.xhr_errorlogs,
+ name='xhr_errorlogs'),
+
url(r'^xhr_packages/$', views.xhr_packages,
name='xhr_packages'),
@@ -153,6 +156,9 @@ urlpatterns = [
url(r'^publish_diff_history/$', views.publish_diff_history, name='publish_diff_history'),
url(r'^maintenance/$', views.maintenance, name='maintenance'),
+ url(r'^error_logs/$',
+ tables.ErrorLogsTable.as_view(template_name="errorlog-toastertable.html"),
+ name='error_logs'),
url(r'^history_cve/$',
tables.HistoryCveTable.as_view(template_name="history-cve-toastertable.html"),
name='history_cve'),
diff --git a/lib/srtgui/views.py b/lib/srtgui/views.py
index 7fdfad9..d360118 100644
--- a/lib/srtgui/views.py
+++ b/lib/srtgui/views.py
@@ -40,6 +40,7 @@ from orm.models import DataSource
from orm.models import Defect, DefectHistory, PublishPending, PublishSet
from orm.models import Notify, NotifyAccess, NotifyCategories
from orm.models import SRTool, Update
+from orm.models import ErrorLog
from users.models import SrtUser, UserSafe
@@ -59,7 +60,7 @@ SRT_BASE_DIR = os.environ['SRT_BASE_DIR']
logger = logging.getLogger("srt")
# quick development/debugging support
-from srtgui.api import _log
+from srtgui.api import error_log, _log
#
# ================= Helper Routines ============================================
@@ -494,6 +495,10 @@ def management(request):
'defect_p2' : defect_p2,
'package_total' : Package.objects.all().count(),
+
+ 'notification_total' : Notify.objects.all().count(),
+ 'errorlog_total' : ErrorLog.objects.all().count(),
+
}
return render(request, 'management.html', context)
@@ -503,6 +508,7 @@ def maintenance(request):
return redirect(landing)
context = {
+ 'errorlog_total' : ErrorLog.objects.all().count(),
'history_cve_total' : CveHistory.objects.all().count(),
'history_vulnerability_total' : VulnerabilityHistory.objects.all().count(),
'history_investigation_total' : InvestigationHistory.objects.all().count(),
@@ -668,7 +674,7 @@ def vulnerability(request, vulnerability_pk):
except:
return redirect(landing)
- products = Product.objects.all()
+ products = Product.objects.all().order_by('order')
# does this user have permission to see this record?
if (not vulnerability_object.public) and (not UserSafe.is_admin(request.user)):
@@ -756,12 +762,15 @@ def investigation(request, investigation_pk):
# Calculate the default 'affected_components' list, if any
affected_components = ''
- affected_components_list = []
+ affected_components_list = {}
+ for package in investigation_object.packages.split():
+ affected_components_list[package] = True
vulnerability = investigation_object.vulnerability
vc_list = vulnerability.vulnerability_to_cve.all()
for vc in vc_list:
if vc.cve.packages:
- affected_components_list.append(vc.cve.packages)
+ for package in vc.cve.packages.split():
+ affected_components_list[package] = True
if affected_components_list:
affected_components = ' '.join(affected_components_list)
@@ -1382,6 +1391,8 @@ def _create_defect(investigation,reason,defect_reason,domain_components,affected
d_name = params[0]
d_url = params[1]
_log("SRT_DEFECT3c|%s|%s|" % (d_name,d_url))
+ else:
+ error_log(ErrorLog.ERROR,"DEFECT_CREATION_FAIL(%d)'%s':'%s'" % (result_returncode,result_stdout,result_stderr))
### TO-DO: Trigger dialog in a production system if not defect created at this point
### For now provide a defect number simulation
if not d_name:
@@ -1407,6 +1418,7 @@ def _create_defect(investigation,reason,defect_reason,domain_components,affected
d.srt_status = Defect.VULNERABLE
d.srt_outcome = Defect.OPEN
d.url = d_url
+ d.packages = investigation.packages
d.save()
_log("NEW_DEFECT:%s|%s|%s|%s" % (d.name,summary,components,priority))
# Create Investigation to Defect
@@ -1606,6 +1618,7 @@ def xhr_triage_commit(request):
vulnerability.status = new_status
vulnerability.outcome = Vulnerability.OPEN
vulnerability.comments = reason
+ vulnerability.packages = cve.packages
vulnerability.save()
notify_message += " %s" % v_name
created_list += ' %s' % vulnerability.name
@@ -1645,6 +1658,7 @@ def xhr_triage_commit(request):
investigation = Investigation.objects.create(name=i_name,product=product,vulnerability = vulnerability)
investigation.priority = cve_priority
investigation.outcome = Investigation.OPEN
+ investigation.packages = cve.packages
# Check to see if product is active
_log("BOO1:")
if 'no' == product.get_product_tag('active','yes'):
@@ -1834,6 +1848,7 @@ def xhr_cve_commit(request):
status = cve.status,
priority = cve.priority,
comments = cve.comments,
+ packages = cve.packages,
)
vulnerability.save()
history_update.append(Update.ATTACH_INV % (vname))
@@ -1931,6 +1946,7 @@ def xhr_vulnerability_commit(request):
priority = int(request.POST['priority'])
status = int(request.POST['status'])
outcome = int(request.POST['outcome'])
+ affected_components = request.POST['affected_components'].strip()
v = Vulnerability.objects.get(id=v_id)
if (v.priority != priority):
history_update.append(Update.PRIORITY % (SRTool.priority_text(v.priority),SRTool.priority_text(priority)))
@@ -1950,6 +1966,9 @@ def xhr_vulnerability_commit(request):
if (tags != v.tags):
history_update.append(Update.TAG)
v.tags = tags
+ if (affected_components != v.packages):
+ history_update.append(Update.AFFECTED_COMPONENT % (v.packages,affected_components))
+ v.packages = affected_components
v.save()
if 'submit-addproduct' == action:
products = request.POST['products']
@@ -1968,6 +1987,7 @@ def xhr_vulnerability_commit(request):
priority = vulnerability_obj.priority,
product = product_obj,
comments = vulnerability_obj.comments,
+ packages = vulnerability_obj.packages,
)
vul2inv = VulnerabilityToInvestigation.objects.create(vulnerability=vulnerability_obj,investigation=investigation_obj)
vul2inv.save()
@@ -2118,6 +2138,30 @@ def xhr_notifications(request):
_log("xhr_notifications_commit:no(%s)" % e)
return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json")
+def xhr_errorlogs(request):
+ _log("xhr_errorlogs(%s)" % request.POST)
+ if not 'action' in request.POST:
+ return HttpResponse(json.dumps({"error":"missing action\n"}), content_type = "application/json")
+
+ action = request.POST['action']
+
+ _log("xhr_errorlogs1")
+
+ try:
+ results_msg = ''
+ if 'delete-errorlogs' == action:
+ log_list = request.POST['log_list']
+ for log_id in log_list.split(','):
+ ErrorLog.objects.get(pk=log_id).delete()
+ return_data = {
+ "error": "ok",
+ "results_msg": results_msg,
+ }
+ return HttpResponse(json.dumps( return_data ), content_type = "application/json")
+ except Exception as e:
+ _log("xhr_errorlogs_commit:ERROR(%s)" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json")
+
def xhr_packages(request):
_log("xhr_packages(%s)" % request.POST)
if not 'action' in request.POST:
@@ -2155,6 +2199,7 @@ def xhr_investigation_commit(request):
username = UserSafe.user_name(request.user)
try:
history_update = []
+ xhr_note = ''
if 'submit-quickedit' == action:
priority = int(request.POST['priority'])
status = int(request.POST['status'])
@@ -2162,6 +2207,7 @@ def xhr_investigation_commit(request):
note = request.POST['note'].strip()
private_note = request.POST['private_note'].strip()
tags = request.POST['tags'].strip()
+ affected_components = request.POST['affected_components'].strip()
invst = Investigation.objects.get(id=invst_id)
if (invst.priority != priority):
history_update.append(Update.PRIORITY % (SRTool.priority_text(invst.priority),SRTool.priority_text(priority)))
@@ -2181,6 +2227,9 @@ def xhr_investigation_commit(request):
if (invst.tags != tags):
invst.tags = tags
history_update.append(Update.TAG)
+ if (invst.packages != affected_components):
+ history_update.append(Update.AFFECTED_COMPONENT % (invst.packages,affected_components))
+ invst.packages = affected_components
invst.save()
if 'submit-attachdefectlist' == action:
defects = request.POST['defects']
@@ -2230,6 +2279,7 @@ def xhr_investigation_commit(request):
affected_components = request.POST['affected_components'].strip()
defect_name,created = _create_defect(investigation,'',defect_reason,components,affected_components,username)
history_update.append(Update.ATTACH_DEV % defect_name)
+ xhr_note = defect_name
if 'submit-detachdefect' == action:
defect_name = request.POST['defect']
product_id = Investigation.objects.get(id=invst_id).product_id
@@ -2293,6 +2343,7 @@ def xhr_investigation_commit(request):
InvestigationHistory.objects.create(investigation_id=invst_id, comment=update_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username)
return_data = {
"error": "ok",
+ "note": xhr_note,
}
return HttpResponse(json.dumps( return_data ), content_type = "application/json")