diff farolluz/cvrf.py @ 18:8a89b7a591e6

merged
author Benoît Allard <benoit.allard@greenbone.net>
date Tue, 14 Oct 2014 16:49:36 +0200
parents 90852c11fabd
children 4b53e7bcff0d
line wrap: on
line diff
--- a/farolluz/cvrf.py	Wed Sep 24 17:47:14 2014 +0200
+++ b/farolluz/cvrf.py	Tue Oct 14 16:49:36 2014 +0200
@@ -65,6 +65,9 @@
     def addAlias(self, alias):
         self._aliases.append(alias)
 
+    def getId(self):
+        return self._id
+
     def validate(self):
         if not self._id:
             raise ValidationError('Document ID cannot be left empty')
@@ -92,6 +95,9 @@
     def setGenerator(self, generator):
         self._generator = generator
 
+    def getId(self):
+        return self._identification.getId()
+
     def validate(self):
         if self._identification is None:
             raise ValidationError('Document Tracking needs to have an Identification')
@@ -225,18 +231,19 @@
 
 
 class CVRFAcknowledgment(object):
-    def __init__(self, name=None, organization=None, description=None,
+    def __init__(self, names=[], organizations=[], description=None,
                  url=None):
-        self._name = name
-        self._organization = organization
+        self._names = names
+        self._organizations = organizations
         self._description = description
         self._url = url
 
     def getTitle(self):
-        return "%s - %s" % (self._name, self._organization)
+        return "%s - %s" % (', '.join(self._names),
+                            ', '.join(self._organizations))
 
     def validate(self):
-        if (not self._name) and (not self._organization) and (not self._description):
+        if (not self._names) and (not self._organizations) and (not self._description):
             raise ValidationError('An Acknowledgment must have at least a Name, an Organization or a Description')
 
 
@@ -249,18 +256,9 @@
         self._products = []
         self._groups = []
 
-    def addBranch(self, branch):
-        parent = self.getBranch(branch.getParent().getPath())
-        if parent is self:
-            self._branches.append(branch)
-        else:
-            parent._childs.append(branch)
-
     def addProduct(self, product):
-        if product not in self._products:
-            self._products.append(product)
-        if product._parent is not self:
-            product._parent._product = product
+        """ Add to the product list """
+        self._products.append(product)
 
     def addRelationship(self, rel):
         self._relationships.append(rel)
@@ -396,9 +394,9 @@
     def __init__(self, _type, name, parentbranch):
         self._type = _type
         self._name = name
-        self._parentbranch = parentbranch
         self._childs = []
         self._product = None
+        self.link(parentbranch)
 
     def getParent(self):
         return self._parentbranch
@@ -455,6 +453,15 @@
             self.getParent()._childs.remove(self)
         self._parentbranch = None
 
+    def link(self, parent):
+        """ Actually, only set the parent """
+        self._parentbranch = parent
+        if self.isRoot():
+            parent._branches.append(self)
+        else:
+            parent._childs.append(self)
+
+
     def validate(self):
         if not self._type:
             raise ValidationError('A Branch must have a Type')
@@ -475,10 +482,10 @@
     def __init__(self, productid, name, parent, cpe=None):
         self._productid = productid
         self._name = name
+        self._cpe = cpe
         # Can be None (directly under the tree), a ProductBranch, or a
         # Relationship
-        self._parent = parent
-        self._cpe = cpe
+        self.link(parent)
 
     def isRoot(self):
         return isinstance(self._parent, CVRFProductTree)
@@ -502,13 +509,18 @@
         return None
 
     def unlink(self):
-        """ Unset our _parent, and remove us from the _parent._childs """
-        if self.isRoot():
-            self._parent._products.remove(self)
-        else:
+        """ Unset our _parent, and remove us from the _parent._childs
+        We are still in the product list.
+        """
+        if not self.isRoot():
             self._parent._product = None
         self._parent = None
 
+    def link(self, parent):
+        self._parent = parent
+        if not self.isRoot():
+            parent._product = self
+
     def validate(self):
         if not self._productid:
             raise ValidationError('A Product must have a ProductID')
@@ -655,6 +667,46 @@
             return self._id._value
         return "#%d" % self._ordinal
 
+    def getNote(self, ordinal):
+        for note in self._notes:
+            if note._ordinal == ordinal:
+                return note
+        return None
+
+    def mentionsProdId(self, productid):
+        """ Returns in which sub element, self is mentioning the productid """
+        for category in (self._productstatuses, self._threats, self._cvsss, self._remediations):
+            for subelem in category:
+                if productid in subelem._productids:
+                    yield subelem
+
+    def isMentioningProdId(self, productid):
+        """ Returns if self is mentioning the productid """
+        for e in self.mentionsProdId(productid):
+            # We only need to know if the generator yield at least one elem.
+            return True
+        return False
+
+    def mentionsGroupId(self, groupid):
+        for category in (self._threats, self._remediations):
+            for subelem in category:
+                if groupid in subelem._groupids:
+                    yield subelem
+
+    def isMentioningGroupId(self, groupids):
+        """ Make sure you call this with a list (not a generator or a tuple)
+        when wished """
+        if not isinstance(groupids, list):
+            groupids = [groupids]
+        for groupid in groupids:
+            print "testing GroupId: ", groupid
+            for _ in self.mentionsGroupId(groupid):
+                # We only need to know if the generator yield at least one elem.
+                print 'True'
+                return True
+        print 'False'
+        return False
+
     def validate(self, productids, groupids):
         if not self._ordinal:
             raise ValidationError('A Vulnerability must have an ordinal')
@@ -672,10 +724,22 @@
             cwe.validate()
         for status in self._productstatuses:
             status.validate(productids)
+        pids = set()
+        for status in self._productstatuses:
+            for pid in status._productids:
+                if pid in pids:
+                    raise ValidationError('ProductID %s mentionned in two different ProductStatuses for Vulnerability %d' % (pid, self._ordinal))
+                pids.add(pid)
         for threat in self._threats:
             threat.validate(productids, groupids)
         for cvss in self._cvsss:
             cvss.validate(productids)
+        pids = set()
+        for cvss in self._cvsss:
+            for pid in (cvss._productids or productids):
+                if pid in pids:
+                    raise ValidationError('ProductID %s mentionned in two different CVSS Score Sets for Vulnerability %d' % (pid, self._ordinal))
+                pids.add(pid)
         for remediation in self._remediations:
             remediation.validate(productids, groupids)
         for reference in self._references:
@@ -684,7 +748,6 @@
             acknowledgment.validate()
 
 
-
 class CVRFInvolvement(object):
     PARTIES = CVRFPublisher.TYPES
     STATUSES = ('Open', 'Disputed', 'In Progress', 'Completed',
@@ -726,6 +789,7 @@
 class CVRFProductStatus(object):
     TYPES = ('First Affected', 'Known Affected', 'Known Not Affected',
              'First Fixed', 'Fixed', 'Recommended', 'Last Affected')
+    NAME = "Product Status"
     def __init__(self, _type):
         self._type = _type
         self._productids = []
@@ -750,6 +814,7 @@
 
 class CVRFThreat(object):
     TYPES = ('Impact', 'Exploit Status', 'Target Set')
+    NAME = "Threat"
     def __init__(self, _type, description):
         self._type = _type
         self._description = description
@@ -792,6 +857,7 @@
               'C': {'N':0.0, 'P':0.275, 'C':0.66},
               'I': {'N':0.0, 'P':0.275, 'C':0.66},
               'A': {'N':0.0, 'P':0.275, 'C':0.66}}
+    NAME = "CVSS Score Set"
     def __init__(self, basescore):
         self._basescore = basescore
         self._temporalscore = None
@@ -844,6 +910,7 @@
 class CVRFRemediation(object):
     TYPES = ('Workaround', 'Mitigation', 'Vendor Fix', 'None Available',
              'Will Not Fix')
+    NAME = "Remediation"
     def __init__(self, _type, description):
         self._type = _type
         self._description = description
@@ -972,12 +1039,39 @@
                         products.add(productid)
         return set(self.getProductForID(p) for p in products)
 
+    def isProductOrphan(self, productid):
+        """ Returns if a productid is mentionned nowhere in the document """
+        # We first look at the ProductTree
+        ptree = self._producttree
+        for relation in ptree._relationships:
+            if productid == relation._productreference:
+                return False
+            if productid == relation._relatestoproductreference:
+                return False
+        groupids = [g._groupid for g in ptree._groups if productid in g._productids]
+        if len(groupids) > 0:
+            return False
+        # Go through all the Vulnerabilities
+        for vulnerability in self._vulnerabilities:
+            if vulnerability.isMentioningProdId(productid):
+                return False
+            for groupid in groupids:
+                if vulnerability.isMentioningGroupId(groupid):
+                    return False
+        return True
+
     def getNote(self, ordinal):
         for note in self._notes:
             if note._ordinal == ordinal:
                 return note
         return None
 
+    def getDocId(self):
+        if self._tracking is not None:
+            return self._tracking.getId()
+        # Make up something ...
+        return self._title.lower()
+
     def validate(self):
         if not self._title:
             raise ValidationError('Document Title cannot be empty')
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)