diff options
Diffstat (limited to 'lib/orm/models.py')
-rw-r--r-- | lib/orm/models.py | 677 |
1 files changed, 562 insertions, 115 deletions
diff --git a/lib/orm/models.py b/lib/orm/models.py index 0f6cfb17..0dd73ba4 100644 --- a/lib/orm/models.py +++ b/lib/orm/models.py @@ -114,6 +114,266 @@ def GitURLField(**kwargs): # Core Classes +# Helper class to common mappings +class SRTool(): + + # Global date format + DATE_FORMAT = '%Y-%m-%d' + DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' + + # SRTool Priority + UNDEFINED = 0 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 99 + SRT_PRIORITY = ( + (UNDEFINED, 'Undefined'), + (LOW, 'Low'), + (MEDIUM, 'Medium'), + (HIGH, 'High'), + (CRITICAL, 'Critical'), + ) + @staticmethod + def priority_text(index): + if (0 > index) or (index >= len(SRTool.SRT_PRIORITY)): + return 'PRIORITY_ERROR' + return SRTool.SRT_PRIORITY[index][1] + @staticmethod + def priority_index(value): + for item in SRTool.SRT_PRIORITY: + if value == item[1]: + return item[0] + return SRTool.PRIORITY_ERROR + + # SRTool Severity (same integer values as prority) + SRT_SEVERITY = ( + (UNDEFINED, 'UNDEFINED'), + (LOW, 'LOW'), + (MEDIUM, 'MEDIUM'), + (HIGH, 'HIGH'), + (CRITICAL, 'CRITICAL'), + ) + @staticmethod + def severity_text(index): + if (0 > index) or (index >= len(SRTool.SRT_SEVERITY)): + return 'SEVERITY_ERROR' + return SRTool.SRT_SEVERITY[index][1] + @staticmethod + def severity_index(value): + for item in SRTool.SRT_SEVERITY: + if value == item[1]: + return item[0] + return SRTool.PRIORITY_ERROR + + # SRTool Status + HISTORICAL = 0 + NEW = 1 + NEW_RESERVED = 2 + INVESTIGATE = 3 + VULNERABLE = 4 + NOT_VULNERABLE = 5 + NEW_INACTIVE = 6 + INVESTIGATE_INACTIVE = 7 + VULNERABLE_INACTIVE = 8 + NOT_VULNERABLE_INACTIVE = 9 + STATUS_ERROR = 99 + SRT_STATUS = ( + (HISTORICAL, 'Historical'), + (NEW, 'New'), + (NEW_RESERVED, 'New-Reserved'), + (INVESTIGATE, 'Investigate'), + (VULNERABLE, 'Vulnerable'), + (NOT_VULNERABLE, 'Not Vulnerable'), + (NEW_INACTIVE, '(New)'), + (INVESTIGATE_INACTIVE, '(Investigate)'), + (VULNERABLE_INACTIVE, '(Vulnerable)'), + (NOT_VULNERABLE_INACTIVE, '(Not Vulnerable)'), + ) + @staticmethod + def status_text(index): + if (0 > index) or (index >= len(SRTool.SRT_STATUS)): + return 'STATUS_ERROR' + return SRTool.SRT_STATUS[index][1] + @staticmethod + def status_index(value): + for item in SRTool.SRT_STATUS: + if value == item[1]: + return item[0] + return SRTool.STATUS_ERROR + @staticmethod + def status_to_inactive(value): + if SRTool.NEW == value: + return SRTool.NEW_INACTIVE + elif SRTool.INVESTIGATE == value: + return SRTool.INVESTIGATE_INACTIVE + elif SRTool.VULNERABLE == value: + return SRTool.VULNERABLE_INACTIVE + elif SRTool.NOT_VULNERABLE == value: + return SRTool.NOT_VULNERABLE_INACTIVE + else: + return value + @staticmethod + def status_to_active(value): + if SRTool.NEW_INACTIVE == value: + return SRTool.NEW + elif SRTool.INVESTIGATE_INACTIVE == value: + return SRTool.INVESTIGATE + elif SRTool.VULNERABLE_INACTIVE == value: + return SRTool.VULNERABLE + elif SRTool.NOT_VULNERABLE_INACTIVE == value: + return SRTool.NOT_VULNERABLE + else: + return value + + OPEN = 0 + CLOSED = 1 + FIXED = 2 + NOT_FIX = 3 + OUTCOME_ERROR = 4 + SRT_OUTCOME = ( + (OPEN, 'Open'), + (CLOSED, 'Closed (Not Vulnerable)'), + (FIXED, 'Closed (Fixed)'), + (NOT_FIX, "Closed (Won't Fix)"), + ) + @staticmethod + def outcome_text(index): + if (0 > index) or (index >= len(SRTool.SRT_OUTCOME)): + return "OUTCOME_ERROR" + return SRTool.SRT_OUTCOME[index][1] + @staticmethod + def outcome_index(value): + for item in SRTool.SRT_OUTCOME: + if value == item[1]: + return item[0] + return SRTool.OUTCOME_ERROR + + # Publish state + PUBLISH_UNPUBLISHED = 0 + PUBLISH_NOPUBLISH = 1 + PUBLISH_PUBLISHED = 2 + PUBLISH_REQUEST = 3 + PUBLISH_UPDATE = 4 + PUBLISH_SUBMITTED = 5 + PUBLISH_ERROR = 99 + SRT_PUBLISH_STATE = ( + (PUBLISH_UNPUBLISHED, 'Unpublished'), + (PUBLISH_NOPUBLISH, 'Not to be Published'), + (PUBLISH_PUBLISHED, 'Published'), + (PUBLISH_REQUEST, 'Publish Request (New)'), + (PUBLISH_UPDATE, 'Publish Request (Update)'), + (PUBLISH_SUBMITTED, 'Publish Submitted'), + ) + @staticmethod + def publish_text(index): + if (0 > index) or (index >= len(SRTool.SRT_PUBLISH_STATE)): + return SRTool.SRT_PUBLISH_STATE[SRTool.PUBLISH_ERROR][1] + return 'PUBLISH_ERROR' + @staticmethod + def publish_index(value): + for item in SRTool.SRT_PUBLISH_STATE: + if value == item[1]: + return item[0] + return SRTool.PUBLISH_ERROR + + # Normalize displayed dates + @staticmethod + def date_ymd_text(value): + if isinstance(value,datetime): + return(value.strftime("%Y-%m-%d")) + return(value) + + # Extract dictionary tag values + @staticmethod + def get_dict_tag(tag,dict_str,default=None): + dict = json.loads(dict_str) + if tag in dict: + return dict[tag] + return default + + +# Helper class to format and track updates +# Enforce strict formatting and content to enable reporting, change filtering, pretty printing +class Update(): + # General history prefix format (type,source,semicolon-joined changes): + # UPDATE(User):Priority(%s,%s);Tag();Status(%s,%s) {helpful text} + # CREATE(Defect): {Created from defect ABCD-1234} + # Update report check strings: 'UPDATE(','Priority(','Status(' + + # General update label + UPDATE_STR = "UPDATE(%s):" + CREATE_STR = "CREATE(%s):" + UPDATE_PREFIX_STR = "UPDATE(" + CREATE_PREFIX_STR = "CREATE(" + + # Update sources + SOURCE_USER = "User" + SOURCE_TRIAGE = "Triage" + SOURCE_CVE = "CVE" + SOURCE_DEFECT = "Defect" + + # Update labels (no string overlaps allowed) + NEW_NAME = "New_Name(%s,%s)" + PRIORITY = "Priority(%s,%s)" + STATUS = "Status(%s,%s)" + SEVERITY_V3 = "Severity_V3(%s,%s)" + SEVERITY_V2 = "Severity_V2(%s,%s)" + OUTCOME = "Outcome(%s,%s)" + RELEASE = "Release(%s,%s)" + DESCRIPTION = "Description()" + LASTMODIFIEDDATE = "LastModifiedDate(%s,%s)" + NOTE = "User_Note()" + PRIVATE_NOTE = "Private_Note()" + TAG = "Tag()" + PUBLISH_STATE = "Publish_State(%s,%s)" + PUBLISH_DATE = "Publish_Date(%s,%s)" + AFFECTED_COMPONENT = "Affected_Component(%s,%s)" + ACKNOWLEDGE_DATE = "AcknowledgeDate(%s,%s)" + ATTACH_CVE = "Attach_CVE(%s)" + DETACH_CVE = "Detach_CVE(%s)" + ATTACH_VUL = "Attach_Vulnerability(%s)" + DETACH_VUL = "Detach_Vulnerability(%s)" + ATTACH_INV = "Attach_Investigration(%s)" + DETACH_INV = "Detach_Investigration(%s)" + ATTACH_DEV = "Attach_Defect(%s)" + DETACH_DEV = "Detach_Defect(%s)" + ATTACH_DOC = "Attach_Document(%s)" + DETACH_DOC = "Detach_Document(%s)" + ATTACH_USER_NOTIFY = "Attach_User_Notify(%s)" + DETACH_USER_NOTIFY = "Detach_User_Notify(%s)" + ATTACH_ACCESS = "Attach_Access(%s)" + DETACH_ACCESS = "Detach_Access(%s)" + ATTACH_PRODUCT = "Attach_Product(%s)" + DETACH_PRODUCT = "Detach_Product(%s)" + MARK_NEW = "Mark_New(%s)" + MARK_UPDATED = "Mark_Updated(%s)" + MARK_PREFIX = "Mark_" + MARK_NEW_PREFIX = "Mark_New" + MARK_UPDATED_PREFIX = "Mark_Updated" + MARK_UNMARK = "Mark_Unmark()" + + # Update Report list + UPDATE_CHECK_LIST = ( + PRIORITY, + STATUS, + SEVERITY_V3, + SEVERITY_V2, + RELEASE, + MARK_NEW, + MARK_UPDATED, + ) + + #Any matching string for the period indicates reportable change + @staticmethod + def get_check_list(): + check_list = [] + for check in UPDATE_CHECK_LIST: + simple_check = re.sub(r'(.*', '(', check) + check_list.append(simple_check) + return(check_list) + class SrtSetting(models.Model): name = models.CharField(max_length=63) helptext = models.TextField() @@ -128,6 +388,11 @@ class SrtSetting(models.Model): return(SrtSetting.objects.get(name=key).value) except: return(default) + @staticmethod + def set_setting(key,value): + obj,created = SrtSetting.objects.get_or_create(name=key) + obj.value = value + obj.save() class HelpText(models.Model): @@ -163,6 +428,10 @@ class DataSource(models.Model): DATE_FORMAT = '%Y-%m-%d' DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' + # Metadata + LOOKUP_MISSING = 'LOOKUP-MISSING' + PREVIEW_SOURCE = 'PREVIEW-SOURCE' + key = models.CharField(max_length=20) data = models.CharField(max_length=20) source = models.CharField(max_length=20) @@ -194,20 +463,22 @@ class CweTable(models.Model): class Cve(models.Model): search_allowed_fields = ['name', 'description', 'publishedDate', - 'lastModifiedDate', 'comments', 'comments_private'] + 'lastModifiedDate', 'comments', 'comments_private', 'tags', 'packages'] # SRTool Priority UNDEFINED = 0 - MINOR = 1 - LOW = 2 - MEDIUM = 3 - HIGH = 4 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 5 PRIORITY = ( (UNDEFINED, 'Undefined'), - (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), + (CRITICAL, 'Critical'), + (PRIORITY_ERROR, 'PRIORITY_ERROR'), ) # WR Status @@ -256,6 +527,7 @@ class Cve(models.Model): status = models.IntegerField(choices=STATUS, default=NEW) comments = models.TextField(blank=True) comments_private = models.TextField(blank=True) + tags = models.TextField(blank=True, default='', null=True) cve_data_type = models.CharField(max_length=100, blank=True) cve_data_format = models.CharField(max_length=50, blank=True) @@ -264,6 +536,7 @@ class Cve(models.Model): public = models.BooleanField(default=True) publish_state = models.IntegerField(choices=PUBLISH_STATE, default=PUBLISH_UNPUBLISHED) publish_date = models.CharField(max_length=50, blank=True) + acknowledge_date = models.DateTimeField(null=True) description = models.TextField(blank=True) publishedDate = models.CharField(max_length=50, blank=True) @@ -281,25 +554,41 @@ class Cve(models.Model): packages = models.TextField(blank=True) score_date = models.DateField(null=True, blank=True) - srt_updated = models.DateTimeField(auto_now=True) + srt_updated = models.DateTimeField(auto_now=True, null=True) + srt_created = models.DateTimeField(auto_now_add=True, null=True) @property def get_priority_text(self): - return Cve.PRIORITY[int(self.priority)][1] + return SRTool.priority_text(self.priority) + @property + def get_status_text(self): + return SRTool.status_text(self.status) @property def get_publish_text(self): return Cve.PUBLISH_STATE[int(self.publish_state)][1] @property - def get_status_text(self): - return Cve.STATUS[int(self.status)][1] - @property def is_local(self): try: CveLocal.objects.get(name=self.name) return True except: return False - + @property + def get_publishset_state(self): + try: + obj = PublishSet.objects.get(cve=self) + return obj.state_text + except: + return PublishSet.PUBLISH_SET_STATE[PublishSet.PUBLISH_SET_NONE][1] + @property + def get_public_comments(self): + the_comments = self.comments.strip() + the_packages = self.packages.strip() + if not the_comments or not the_packages: + return '%s%s' % (the_comments,the_packages) + if the_comments == the_packages: + return the_comments + return '%s' % (the_comments) class CveDetail(): # CPE item list @@ -317,6 +606,7 @@ class CveDetail(): description = '' publishedDate = '' + acknowledge_date = '' lastModifiedDate = '' url_title = '' url = '' @@ -431,11 +721,12 @@ class CveLocal(models.Model): # Map of all sources for the given CVE class CveSource(models.Model): - cve = models.ForeignKey(Cve,related_name="cve_parent",on_delete=models.CASCADE,) + cve = models.ForeignKey(Cve,related_name="cve_parent",blank=True, null=True,on_delete=models.CASCADE,) datasource = models.ForeignKey(DataSource,related_name="cve_datasource", blank=True, null=True,on_delete=models.CASCADE,) class CveHistory(models.Model): - cve = models.ForeignKey(Cve,related_name="cve_history",on_delete=models.CASCADE,) + search_allowed_fields = ['cve__name', 'comment', 'date', 'author'] + cve = models.ForeignKey(Cve,related_name="cve_history",default=None, null=True, on_delete=models.CASCADE,) comment = models.TextField(blank=True) date = models.DateField(null=True, blank=True) author = models.TextField(blank=True) @@ -485,12 +776,12 @@ class Package(models.Model): @staticmethod def update_computed_counts(package_name=None): # A 'None' indicates all packages - _log("update_computed_counts0:%s" % package_name) +# _log("update_computed_counts0:%s" % package_name) if package_name: package_list = Package.objects.filter(name=package_name) else: package_list = Package.objects.all() - _log("update_computed_counts:p:%s" % len(package_list)) +# _log("update_computed_counts:p:%s" % len(package_list)) for package in package_list: try: state = "p" @@ -498,7 +789,7 @@ class Package(models.Model): package.vulnerability_count = 0 package.investigation_count = 0 package.defect_count = 0 - _log("update_computed_counts2:c:%s" % len(package.package2cve.all())) +# _log("update_computed_counts2:c:%s" % len(package.package2cve.all())) for pc in package.package2cve.all(): cve = pc.cve package.cve_count += 1 @@ -559,7 +850,7 @@ class CveToCwe(models.Model): class CveReference(models.Model): cve = models.ForeignKey(Cve,related_name="references",on_delete=models.CASCADE,) - hyperlink = models.CharField(max_length=100) + hyperlink = models.CharField(max_length=100, null=True) resource = models.CharField(max_length=100, null=True) type = models.CharField(max_length=100, null=True) source = models.CharField(max_length=100, null=True) @@ -586,26 +877,20 @@ class Product(models.Model): def long_name(self): long_name = '%s %s %s' % (self.name,self.version,self.profile) return long_name.strip() - def get_defect_tag(self,tag): - dict = json.loads(self.defect_tags) - try: - return dict[tag] - except: - _log("ERROR:get_defect_tag:%s[%s]" % (dict,tag)) - return '' - def get_product_tag(self,tag): - dict = json.loads(self.product_tags) - try: - return dict[tag] - except: - _log("ERROR:get_product_tags:%s[%s]" % (dict,tag)) - return '' + def get_defect_tag(self,tag,default=None): + return SRTool.get_dict_tag(tag,self.defect_tags,default) + def get_product_tag(self,tag,default=None): + return SRTool.get_dict_tag(tag,self.product_tags,default) + def get_defect_str(self): + return self.defect_tags.replace('"','') + def get_product_str(self): + return self.product_tags.replace('"','') # VULNERABILITY # Company-level Vulnerablility Record class Vulnerability(models.Model): - search_allowed_fields = ['name', 'comments', 'comments_private'] + search_allowed_fields = ['name', 'comments', 'comments_private', 'tags'] HISTORICAL = 0 NEW = 1 @@ -632,18 +917,21 @@ class Vulnerability(models.Model): (FIXED, 'Closed (Fixed)'), (NOT_FIX, "Closed (Won't Fix)"), ) - # SRTool Severity, matched with Cve/Defect Priority with placeholder for 'minor' + + # SRTool Priority UNDEFINED = 0 - MINOR = 1 - LOW = 2 - MEDIUM = 3 - HIGH = 4 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 5 PRIORITY = ( (UNDEFINED, 'Undefined'), - (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), + (CRITICAL, 'Critical'), + (PRIORITY_ERROR, 'PRIORITY_ERROR'), ) name = models.CharField(max_length=50) @@ -653,21 +941,26 @@ class Vulnerability(models.Model): public = models.BooleanField(default=True) comments = models.TextField(blank=True, default='') comments_private = models.TextField(blank=True, default='') + tags = models.TextField(blank=True, default='') status = models.IntegerField(choices=STATUS, default=INVESTIGATE) outcome = models.IntegerField(choices=OUTCOME, default=OPEN) priority = models.IntegerField(choices=PRIORITY, default=LOW) + srt_updated = models.DateTimeField(auto_now=True, null=True) + srt_created = models.DateTimeField(auto_now_add=True, null=True) + + @property + def get_priority_text(self): + return SRTool.priority_text(self.priority) @property def get_status_text(self): - return Vulnerability.STATUS[int(self.status)][1] + return SRTool.status_text(self.status) @property def get_outcome_text(self): + return SRTool.outcome_text(self.outcome) return Vulnerability.OUTCOME[int(self.outcome)][1] @property - def get_priority_text(self): - return Vulnerability.PRIORITY[int(self.priority)][1] - @property def get_long_name(self): if self.cve_primary_name: return "%s (%s)" % (self.name,self.cve_primary_name) @@ -698,6 +991,9 @@ class Vulnerability(models.Model): print("Error in new_vulnerability_name") raise return "VUL-%05d" % index + @property + def investigation_list(self): + return VulnerabilityToInvestigation.objects.filter(vulnerability_id=self.id).order_by('investigation__product__order') class VulnerabilityComments(models.Model): vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_comments",on_delete=models.CASCADE,) @@ -706,6 +1002,7 @@ class VulnerabilityComments(models.Model): author = models.TextField(blank=True) class VulnerabilityHistory(models.Model): + search_allowed_fields = ['vulnerability__name', 'comment', 'date', 'author'] vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_history",on_delete=models.CASCADE,) comment = models.TextField(blank=True) date = models.DateField(null=True, blank=True) @@ -733,58 +1030,62 @@ class Defect(models.Model): #Issue Type,Key,Summary,Priority,Status,Resolution,Publish To OLS,Fix Version #Bug,LIN10-2031,Security Advisory - libvorbis - CVE-2017-14633,P3,Closed,Fixed,Reviewed - Publish,10.17.41.3 - NONE = 0 - MINOR = 1 - LOW = 2 - MEDIUM = 3 - HIGH = 4 - Priority = ( - (NONE, 'None'), - (MINOR, 'P4'), - (LOW, 'P3'), - (MEDIUM, 'P2'), - (HIGH, 'P1'), + # Defect/SRTool Priority + DEFECT_UNDEFINED = 0 + DEFECT_LOW = 1 + DEFECT_MEDIUM = 2 + DEFECT_HIGH = 3 + DEFECT_CRITICAL = 4 + DEFECT_PRIORITY_ERROR = 5 + DEFECT_PRIORITY = ( + (DEFECT_UNDEFINED, 'Undefined'), + (DEFECT_LOW, 'Low'), + (DEFECT_MEDIUM, 'Medium'), + (DEFECT_HIGH, 'High'), + (DEFECT_CRITICAL, 'Critical'), + (DEFECT_PRIORITY_ERROR, 'PRIORITY_ERROR'), ) - OPEN = 0 - IN_PROGRESS = 1 - ON_HOLD = 2 - CHECKED_IN = 3 - RESOLVED = 4 - CLOSED = 5 - Status = ( - (OPEN, 'Open'), - (IN_PROGRESS, 'In progress'), - (ON_HOLD, 'On Hold'), - (CHECKED_IN, 'Checked In'), - (RESOLVED, 'Resolved'), - (CLOSED, 'Closed'), + DEFECT_STATUS_OPEN = 0 + DEFECT_STATUS_IN_PROGRESS = 1 + DEFECT_STATUS_ON_HOLD = 2 + DEFECT_STATUS_CHECKED_IN = 3 + DEFECT_STATUS_RESOLVED = 4 + DEFECT_STATUS_CLOSED = 5 + DEFECT_STATUS = ( + (DEFECT_STATUS_OPEN, 'Open'), + (DEFECT_STATUS_IN_PROGRESS, 'In progress'), + (DEFECT_STATUS_ON_HOLD, 'On Hold'), + (DEFECT_STATUS_CHECKED_IN, 'Checked In'), + (DEFECT_STATUS_RESOLVED, 'Resolved'), + (DEFECT_STATUS_CLOSED, 'Closed'), ) - UNRESOLVED = 0 - RESOLVED = 1 - FIXED = 2 - WILL_NOT_FIX = 3 - WITHDRAWN = 4 - REJECTED = 5 - DUPLICATE = 6 - NOT_APPLICABLE = 7 - REPLACED_BY_REQUIREMENT = 8 - CANNOT_REPRODUCE = 9 - DONE = 10 - Resolution = ( - (UNRESOLVED, 'Unresolved'), - (RESOLVED, 'Resolved'), - (FIXED, 'Fixed'), - (WILL_NOT_FIX, 'Won\'t Fix'), - (WITHDRAWN, 'Withdrawn'), - (REJECTED, 'Rejected'), - (DUPLICATE, 'Duplicate'), - (NOT_APPLICABLE, 'Not Applicable'), - (REPLACED_BY_REQUIREMENT, 'Replaced By Requirement'), - (CANNOT_REPRODUCE, 'Cannot Reproduce'), - (DONE, 'Done'), + DEFECT_UNRESOLVED = 0 + DEFECT_RESOLVED = 1 + DEFECT_FIXED = 2 + DEFECT_WILL_NOT_FIX = 3 + DEFECT_WITHDRAWN = 4 + DEFECT_REJECTED = 5 + DEFECT_DUPLICATE = 6 + DEFECT_NOT_APPLICABLE = 7 + DEFECT_REPLACED_BY_REQUIREMENT = 8 + DEFECT_CANNOT_REPRODUCE = 9 + DEFECT_DONE = 10 + DEFECT_RESOLUTION = ( + (DEFECT_UNRESOLVED, 'Unresolved'), + (DEFECT_RESOLVED, 'Resolved'), + (DEFECT_FIXED, 'Fixed'), + (DEFECT_WILL_NOT_FIX, 'Won\'t Fix'), + (DEFECT_WITHDRAWN, 'Withdrawn'), + (DEFECT_REJECTED, 'Rejected'), + (DEFECT_DUPLICATE, 'Duplicate'), + (DEFECT_NOT_APPLICABLE, 'Not Applicable'), + (DEFECT_REPLACED_BY_REQUIREMENT, 'Replaced By Requirement'), + (DEFECT_CANNOT_REPRODUCE, 'Cannot Reproduce'), + (DEFECT_DONE, 'Done'), ) + Components = ( 'BSP', 'Kernel', @@ -796,12 +1097,62 @@ class Defect(models.Model): 'Test', ) + HISTORICAL = 0 + NEW = 1 + NEW_RESERVED = 2 + INVESTIGATE = 3 + VULNERABLE = 4 + NOT_VULNERABLE = 5 + SRT_STATUS = ( + (HISTORICAL, 'Historical'), + (NEW, 'New'), + (NEW_RESERVED, 'New-Reserved'), + (INVESTIGATE, 'Investigate'), + (VULNERABLE, 'Vulnerable'), + (NOT_VULNERABLE, 'Not Vulnerable'), + ) + + OPEN = 0 + CLOSED = 1 + FIXED = 2 + NOT_FIX = 3 + SRT_OUTCOME = ( + (OPEN, 'Open'), + (CLOSED, 'Closed (Not Vulnerable)'), + (FIXED, 'Closed (Fixed)'), + (NOT_FIX, "Closed (Won't Fix)"), + ) + + # SRTool Priority + UNDEFINED = 0 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 5 + SRT_PRIORITY = ( + (UNDEFINED, 'Undefined'), + (LOW, 'Low'), + (MEDIUM, 'Medium'), + (HIGH, 'High'), + (CRITICAL, 'Critical'), + (PRIORITY_ERROR, 'PRIORITY_ERROR'), + ) + name = models.CharField(max_length=50) summary = models.TextField(blank=True) url = models.TextField(blank=True) - priority = models.IntegerField(choices=Priority, default=MINOR) - status = models.IntegerField(choices=Status, default=OPEN) - resolution = models.IntegerField(choices=Resolution, default=UNRESOLVED) + duplicate_of = models.CharField(max_length=50, blank=True, default='') + + # External defect specific values + priority = models.IntegerField(choices=DEFECT_PRIORITY, default=DEFECT_LOW) + status = models.IntegerField(choices=DEFECT_STATUS, default=DEFECT_STATUS_OPEN) + resolution = models.IntegerField(choices=DEFECT_RESOLUTION, default=DEFECT_UNRESOLVED) + # SRTool compatible values + srt_priority = models.IntegerField(choices=SRT_PRIORITY, default=LOW) + srt_status = models.IntegerField(choices=SRT_STATUS, default=INVESTIGATE) + srt_outcome = models.IntegerField(choices=SRT_OUTCOME, default=OPEN) + publish = models.TextField(blank=True) release_version = models.CharField(max_length=50) product = models.ForeignKey(Product,related_name="product_defect",on_delete=models.CASCADE,) @@ -812,25 +1163,77 @@ class Defect(models.Model): # Methods @property + def get_defect_priority_text(self): + return Defect.DEFECT_PRIORITY[int(self.priority)][1] + @property + def get_defect_status_text(self): + return Defect.DEFECT_STATUS[int(self.status)][1] + @property + def get_defect_resolution_text(self): + return Defect.DEFECT_RESOLUTION[int(self.resolution)][1] + @property def get_priority_text(self): - return Defect.Priority[int(self.priority)][1] + return SRTool.priority_text(self.srt_priority) @property def get_status_text(self): - return Defect.Status[int(self.status)][1] + return SRTool.status_text(self.srt_status) + @property + def get_outcome_text(self): + return SRTool.outcome_text(self.srt_outcome) + @property + def get_date_created_text(self): + return re.sub(r"T.*", "", self.date_created) + @property + def get_date_updated_text(self): + return re.sub(r"T.*", "", self.date_updated) @property - def get_resolution_text(self): - return Defect.Resolution[int(self.resolution)][1] def get_long_name(self): if self.release_version: return "%s (%s)" % (self.name,self.release_version) return "%s" % (self.name) + @property + def get_cve_names(self): + cve_list = [] + for di in InvestigationToDefect.objects.filter(defect = self): + for i2v in VulnerabilityToInvestigation.objects.filter(investigation = di.investigation): + for v2c in CveToVulnerablility.objects.filter(vulnerability = i2v.vulnerability): + cve_list.append(v2c.cve.name) + return ','.join(cve_list) + @property + def get_cve_ids(self): + cve_list = [] + for di in InvestigationToDefect.objects.filter(defect = self): + for i2v in VulnerabilityToInvestigation.objects.filter(investigation = di.investigation): + for v2c in CveToVulnerablility.objects.filter(vulnerability = i2v.vulnerability): + cve_list.append(str(v2c.cve.id)) + return ','.join(cve_list) + @property + def get_publishset_state(self): + pub_list = [] + cve_list = self.get_cve_names + if not cve_list: + return PublishSet.PUBLISH_SET_STATE[PublishSet.PUBLISH_SET_NONE][1] + for cve_name in cve_list.split(','): + try: + cve = Cve.objects.get(name = cve_name) + pub_list.append(cve.get_publishset_state) + except Exception as e: + pass + return ','.join(pub_list) + +class DefectHistory(models.Model): + search_allowed_fields = ['defect__name', 'comment', 'date', 'author'] + defect = models.ForeignKey(Defect,related_name="defect_history",on_delete=models.CASCADE,) + comment = models.TextField(blank=True) + date = models.DateField(null=True, blank=True) + author = models.TextField(blank=True) # INVESTIGATION # Product-level Vulnerablility Investigation Record class Investigation(models.Model): - search_allowed_fields = ['name', 'comments', 'comments_private'] + search_allowed_fields = ['name', 'comments', 'comments_private', 'tags'] HISTORICAL = 0 NEW = 1 @@ -858,18 +1261,22 @@ class Investigation(models.Model): (NOT_FIX, "Closed (Won't Fix)"), ) + # SRTool Priority UNDEFINED = 0 - MINOR = 1 - LOW = 2 - MEDIUM = 3 - HIGH = 4 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 5 PRIORITY = ( (UNDEFINED, 'Undefined'), - (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), + (CRITICAL, 'Critical'), + (PRIORITY_ERROR, 'PRIORITY_ERROR'), ) + name = models.CharField(max_length=50) vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_investigation",on_delete=models.CASCADE,) product = models.ForeignKey(Product,related_name="product_investigation",on_delete=models.CASCADE,) @@ -877,21 +1284,25 @@ class Investigation(models.Model): public = models.BooleanField(default=True) comments = models.TextField(blank=True) comments_private = models.TextField(blank=True) + tags = models.TextField(blank=True, default='') status = models.IntegerField(choices=STATUS, default=OPEN) outcome = models.IntegerField(choices=OUTCOME, default=INVESTIGATE) priority = models.IntegerField(choices=PRIORITY, default=LOW) + srt_updated = models.DateTimeField(auto_now=True, null=True) + srt_created = models.DateTimeField(auto_now_add=True, null=True) + # Methods @property + def get_priority_text(self): + return SRTool.priority_text(self.priority) + @property def get_status_text(self): - return Investigation.STATUS[int(self.status)][1] + return SRTool.status_text(self.status) @property def get_outcome_text(self): - return Investigation.OUTCOME[int(self.outcome)][1] - @property - def get_priority_text(self): - return Investigation.PRIORITY[int(self.priority)][1] + return SRTool.outcome_text(self.outcome) @property def get_long_name(self): if self.vulnerability and self.vulnerability.cve_primary_name: @@ -920,6 +1331,7 @@ class InvestigationComments(models.Model): author = models.TextField(blank=True) class InvestigationHistory(models.Model): + search_allowed_fields = ['investigation__name', 'comment', 'date', 'author'] investigation = models.ForeignKey(Investigation,related_name="investigation_history",on_delete=models.CASCADE,) comment = models.TextField(blank=True) date = models.DateField(null=True, blank=True) @@ -979,17 +1391,21 @@ def _log_args(msg, *args, **kwargs): # Action items waiting class Notify(models.Model): search_allowed_fields = ['category','description','url'] + + # SRTool Priority UNDEFINED = 0 - MINOR = 1 - LOW = 2 - MEDIUM = 3 - HIGH = 4 + LOW = 1 + MEDIUM = 2 + HIGH = 3 + CRITICAL = 4 + PRIORITY_ERROR = 5 PRIORITY = ( (UNDEFINED, 'Undefined'), - (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), + (CRITICAL, 'Critical'), + (PRIORITY_ERROR, 'PRIORITY_ERROR'), ) category = models.CharField(max_length=50) @@ -997,8 +1413,10 @@ 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_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) @property def get_priority_text(self): @@ -1013,6 +1431,35 @@ class NotifyAccess(models.Model): class NotifyCategories(models.Model): category = models.CharField(max_length=50) +class PublishSet(models.Model): + search_allowed_fields = ['cve__name','cve__description','cve__status','cve__publishedDate','cve__lastModifiedDate'] + + # Publish state + PUBLISH_SET_NONE = 0 + PUBLISH_SET_NEW = 1 + PUBLISH_SET_MODIFIED = 2 + PUBLISH_SET_NEW_USER = 3 + PUBLISH_SET_MODIFIED_USER = 4 + PUBLISH_SET_ERROR = 5 + PUBLISH_SET_STATE = ( + (PUBLISH_SET_NONE, 'Skip'), + (PUBLISH_SET_NEW, 'New'), + (PUBLISH_SET_MODIFIED, 'Modified'), + (PUBLISH_SET_NEW_USER, 'New_User'), + (PUBLISH_SET_MODIFIED_USER, 'Modified_User'), + (PUBLISH_SET_ERROR, 'PUBLISH_SET_ERROR'), + ) + + cve = models.ForeignKey(default=None, to='orm.cve', null=True, on_delete=models.CASCADE,) + state = models.IntegerField(choices=PUBLISH_SET_STATE, default=PUBLISH_SET_NONE) + reason = models.TextField(blank=True) + + @property + def state_text(self): + if (0 > self.state) or (self.state >= len(self.PUBLISH_SET_STATE)): + return self.PUBLISH_SET_STATE[self.PUBLISH_SET_ERROR][1] + return self.PUBLISH_SET_STATE[self.state][1] + # # Database Cache Support # |