Mercurial > farol > farolluz
annotate farolluz/document.py @ 30:b15022ae484a
Fix isProductOrphan
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Mon, 27 Oct 2014 12:29:37 +0100 |
parents | 809db989cac5 |
children | 1ea1a3c3c790 |
rev | line source |
---|---|
0 | 1 # -*- coding: utf-8 -*- |
2 # | |
3 # Authors: | |
4 # BenoƮt Allard <benoit.allard@greenbone.net> | |
5 # | |
6 # Copyright: | |
7 # Copyright (C) 2014 Greenbone Networks GmbH | |
8 # | |
9 # This program is free software; you can redistribute it and/or | |
10 # modify it under the terms of the GNU General Public License | |
11 # as published by the Free Software Foundation; either version 2 | |
12 # of the License, or (at your option) any later version. | |
13 # | |
14 # This program is distributed in the hope that it will be useful, | |
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 # GNU General Public License for more details. | |
18 # | |
19 # You should have received a copy of the GNU General Public License | |
20 # along with this program; if not, write to the Free Software | |
21 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
22 | |
23 """\ | |
24 Objects related to CVRF Documents | |
25 """ | |
26 | |
26
809db989cac5
Reorganize the code in smaller mpodules
Benoît Allard <benoit.allard@greenbone.net>
parents:
22
diff
changeset
|
27 from .common import ValidationError |
809db989cac5
Reorganize the code in smaller mpodules
Benoît Allard <benoit.allard@greenbone.net>
parents:
22
diff
changeset
|
28 from .producttree import CVRFProductTree, CVRFRelationship |
0 | 29 |
30 class CVRFPublisher(object): | |
31 TYPES = ('Vendor', 'Discoverer', 'Coordinator', 'User', 'Other') | |
32 def __init__(self, _type, vendorid=None): | |
33 self._type = _type | |
34 self._vendorid = vendorid | |
35 self._contact = None | |
36 self._authority = None | |
37 | |
38 def setContact(self, contact): | |
39 self._contact = contact | |
40 | |
41 def setAuthority(self, authority): | |
42 self._authority = authority | |
43 | |
44 def validate(self): | |
45 if not self._type: | |
46 raise ValidationError('Document Publisher needs to have a type') | |
47 if self._type not in self.TYPES: | |
48 raise ValidationError('Document Publisher Type needs to be one of %s' % ', '.join(self.TYPES)) | |
49 | |
50 def __str__(self): | |
51 s = 'CVRFPublisher: %s' % self._type | |
52 if self._vendorid is not None: | |
53 s += ' ID: %s' % self._vendorid | |
54 if self._contact is not None: | |
55 s += ' Contact: "%s"' % self._contact | |
56 if self._authority is not None: | |
57 s += ' Authority: "%s"' % self._authority | |
58 return s | |
59 | |
60 | |
61 class CVRFTrackingID(object): | |
62 def __init__(self, _id): | |
63 self._id = _id | |
64 self._aliases = [] | |
65 | |
66 def addAlias(self, alias): | |
67 self._aliases.append(alias) | |
68 | |
6
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
69 def getId(self): |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
70 return self._id |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
71 |
0 | 72 def validate(self): |
73 if not self._id: | |
74 raise ValidationError('Document ID cannot be left empty') | |
75 | |
76 def __str__(self): | |
77 if self._aliases: | |
78 return "%s (%s)" % (self._id, ', '.join(self._aliases)) | |
79 return self._id | |
80 | |
81 | |
82 class CVRFTracking(object): | |
83 STATUSES = ('Draft', 'Interim', 'Final') | |
84 def __init__(self, _id, status, version, initial, current): | |
85 self._identification = _id | |
86 self._status = status | |
87 self._version = version | |
88 self._history = [] | |
89 self._initialDate = initial | |
90 self._currentDate = current | |
91 self._generator = None | |
92 | |
93 def addRevision(self, revision): | |
94 self._history.append(revision) | |
95 | |
96 def setGenerator(self, generator): | |
97 self._generator = generator | |
98 | |
6
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
99 def getId(self): |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
100 return self._identification.getId() |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
101 |
0 | 102 def validate(self): |
103 if self._identification is None: | |
104 raise ValidationError('Document Tracking needs to have an Identification') | |
105 self._identification.validate() | |
106 if not self._status: | |
107 raise ValidationError('Document status must be set') | |
108 if self._status not in self.STATUSES: | |
109 raise ValidationError('Document Status must be one of %s' % ', '.join(self.STATUSES)) | |
110 if not self._version: | |
111 raise ValidationError('Document Version must be set') | |
112 if len(self._version) > 4: | |
113 raise ValidationError('Document Version must be comprised between `nn` and `nn.nn.nn.nn`') | |
114 if not self._history: | |
115 raise ValidationError('Document must have at least a revision') | |
116 if not self._initialDate: | |
117 raise ValidationError('Document must have an initial Release date set') | |
118 prev_date = self._initialDate | |
119 if self._history[0]._date < self._initialDate: | |
120 # Documents could have revisions before being released | |
121 prev_date = self._history[0]._date | |
122 prev = () | |
123 for revision in self._history: | |
124 revision.validate() | |
125 if revision._number <= prev: | |
126 raise ValidationError('Revision numbers must always be increasing') | |
127 if revision._date < prev_date: | |
128 raise ValidationError('Revision dates must always be increasing') | |
129 prev = revision._number | |
130 prev_date = revision._date | |
131 if not self._currentDate: | |
132 raise ValidationError('Document must have a Current Release Date set') | |
133 if self._currentDate != self._history[-1]._date: | |
134 raise ValidationError('Current Release Date must be the same as the Date from the last Revision') | |
135 if self._initialDate > self._currentDate: | |
136 raise ValidationError('Initial date must not be after current Date') | |
137 if self._version != self._history[-1]._number: | |
138 raise ValidationError('Document version must be the same as the number of the last Revision') | |
139 | |
140 def __str__(self): | |
141 s = "ID: %s" % self._identification | |
142 s += " Status: %s" % self._status | |
143 s += " v%s" % '.'.join('%d' % i for i in self._version) | |
144 s += " %d revisions" % len(self._history) | |
145 s += " Initial release: %s" % self._initialDate.isoformat() | |
146 return s | |
147 | |
148 | |
149 class CVRFRevision(object): | |
150 def __init__(self, number, date, description): | |
151 self._number = number | |
152 self._date = date | |
153 self._description = description | |
154 | |
155 def validate(self): | |
156 if not self._number: | |
157 raise ValidationError('A Revision must have a Number') | |
158 if not self._date: | |
159 raise ValidationError('A Revision must have a Date') | |
160 if not self._description: | |
161 raise ValidationError('A Revision must have a Description') | |
162 | |
163 class CVRFGenerator(object): | |
164 def __init__(self): | |
165 self._engine = None | |
166 self._date = None | |
167 | |
168 def setEngine(self, engine): | |
169 self._engine = engine | |
170 | |
171 def setDate(self, date): | |
172 self._date = date | |
173 | |
174 def validate(self): | |
175 if (not self._engine) and (not self._date): | |
176 raise ValidationError('The Generator must have at least an Engine or a Date') | |
177 | |
178 | |
1
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
179 class CVRFAggregateSeverity(object): |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
180 def __init__(self, severity): |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
181 self._severity = severity |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
182 self._namespace = None |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
183 |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
184 def setNamespace(self, namespace): |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
185 self._namespace = namespace |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
186 |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
187 |
0 | 188 class CVRF(object): |
189 def __init__(self, title, _type): | |
190 self._title = title | |
191 self._type = _type | |
192 self._publisher = None | |
193 self._tracking = None | |
194 self._notes = [] | |
195 self._distribution = None | |
1
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
196 self._aggregateseverity = None |
0 | 197 self._references = [] |
198 self._acknowledgments = [] | |
199 self._producttree = None | |
200 self._vulnerabilities = [] | |
201 | |
202 def setPublisher(self, publisher): | |
203 self._publisher = publisher | |
204 | |
205 def setTracking(self, tracking): | |
206 self._tracking = tracking | |
207 | |
208 def addNote(self, note): | |
209 self._notes.append(note) | |
210 | |
211 def setDistribution(self, distribution): | |
212 self._distribution = distribution | |
213 | |
1
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
214 def setAggregateSeverity(self, aggregateseverity): |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
215 self._aggregateseverity = aggregateseverity |
d47e1164740f
Add support for AggregateSeverity
Benoît Allard <benoit.allard@greenbone.net>
parents:
0
diff
changeset
|
216 |
0 | 217 def addReference(self, ref): |
218 self._references.append(ref) | |
219 | |
220 def addAcknowledgment(self, ack): | |
221 self._acknowledgments.append(ack) | |
222 | |
223 def createProductTree(self): | |
224 """ only done if the element is there """ | |
225 self._producttree = CVRFProductTree() | |
226 return self._producttree | |
227 | |
228 def addVulnerability(self, vuln): | |
229 self._vulnerabilities.append(vuln) | |
230 | |
231 def getProductForID(self, productid): | |
232 if self._producttree is None: | |
233 raise ValueError('No ProductTree') | |
234 return self._producttree.getProductForID(productid) | |
235 | |
236 def getGroupForID(self, groupid): | |
237 if self._producttree is None: | |
238 raise ValueError('No ProductTree') | |
239 return self._producttree.getGroupForID(groupid) | |
240 | |
241 def getHighestCVSS(self): | |
242 highestBaseScore = 0 | |
243 highest = None | |
244 for vulnerability in self._vulnerabilities: | |
245 for cvss in vulnerability._cvsss: | |
246 if cvss._basescore <= highestBaseScore: | |
247 continue | |
248 highestBaseScore = cvss._basescore | |
249 highest = cvss | |
250 return highest | |
251 | |
252 def getProductList(self, type_='Fixed'): | |
253 products = set() | |
254 if type_ == 'Fixed': | |
255 # First try through the Remediation | |
256 for vulnerability in self._vulnerabilities: | |
257 for remediation in vulnerability._remediations: | |
258 if remediation._type != 'Vendor Fix': | |
259 continue | |
260 for productid in remediation._productids: | |
261 products.add(productid) | |
262 for groupid in remediation._groupids: | |
263 for productid in self.getGroupForID(groupid)._productids: | |
264 products.add(productid) | |
265 if not products: | |
266 # If nothing there, try through the productstatuses | |
267 for vulnerability in self._vulnerabilities: | |
268 for status in vulnerability._productstatuses: | |
269 if status._type != type_: | |
270 continue | |
271 for productid in status._productids: | |
272 products.add(productid) | |
273 return set(self.getProductForID(p) for p in products) | |
274 | |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
275 def mentionsProductId(self, productid): |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
276 # We first look at the ProductTree |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
277 ptree = self._producttree |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
278 for relation in ptree._relationships: |
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
279 if productid == relation._productreference: |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
280 yield relation |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
281 elif productid == relation._relatestoproductreference: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
282 yield relation |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
283 # Then go through the groups |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
284 for group in ptree._groups: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
285 if productid in group._productids: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
286 yield group |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
287 # Finally, go through all the Vulnerabilities |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
288 for vulnerability in self._vulnerabilities: |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
289 for item in vulnerability.mentionsProdId(productid): |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
290 yield item |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
291 |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
292 def isProductOrphan(self, productid): |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
293 """ Returns if a productid is mentioned nowhere in the document """ |
30
b15022ae484a
Fix isProductOrphan
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
294 for _ in self.mentionsProductId(productid): |
b15022ae484a
Fix isProductOrphan
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
295 return False |
b15022ae484a
Fix isProductOrphan
Benoît Allard <benoit.allard@greenbone.net>
parents:
26
diff
changeset
|
296 return True |
22
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
297 |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
298 def changeProductID(self, old, new): |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
299 for item in self.mentionsProductId(old): |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
300 if isinstance(item, CVRFRelationship): |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
301 if old == item._productreference: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
302 item._productreference = new |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
303 elif old == item._relatestoproductreference: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
304 item._relatestoproductreference = new |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
305 else: |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
306 item._productids.remove(old) |
4004b67216a9
Add tests + method to change a ProductID
Benoît Allard <benoit.allard@greenbone.net>
parents:
19
diff
changeset
|
307 item._productids.append(new) |
17
90852c11fabd
Add methods to extract Product references in a document.
Benoît Allard <benoit.allard@greenbone.net>
parents:
15
diff
changeset
|
308 |
19
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
309 def isGroupOrphan(self, groupid): |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
310 """ Returns if a group can be safely deleted """ |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
311 for vulnerability in self._vulnerabilities: |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
312 if vulnerability.isMentioningGroupId(groupid): |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
313 return False |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
314 return True |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
315 |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
316 def isProductTreeOrphan(self): |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
317 """ Difference with the previous method is that we don;t care about |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
318 inter-producttree references """ |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
319 for vulnerability in self._vulnerabilities: |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
320 for product in self._producttree._products: |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
321 if vulnerability.isMentioningProdId(product._productid): |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
322 return False |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
323 for group in self._producttree._groups: |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
324 if vulnerability.isMentioningGroupId(group._groupid): |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
325 return False |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
326 return True |
4b53e7bcff0d
Add method to check group and producttree references
Benoît Allard <benoit.allard@greenbone.net>
parents:
17
diff
changeset
|
327 |
0 | 328 def getNote(self, ordinal): |
329 for note in self._notes: | |
330 if note._ordinal == ordinal: | |
331 return note | |
332 return None | |
333 | |
6
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
334 def getDocId(self): |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
335 if self._tracking is not None: |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
336 return self._tracking.getId() |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
337 # Make up something ... |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
338 return self._title.lower() |
633ebfcff0d0
Add a method to request a Document ID
Benoît Allard <benoit.allard@greenbone.net>
parents:
1
diff
changeset
|
339 |
0 | 340 def validate(self): |
341 if not self._title: | |
342 raise ValidationError('Document Title cannot be empty') | |
343 if not self._type: | |
344 raise ValidationError('Document Type cannot be empty') | |
345 if self._publisher is None: | |
346 raise ValidationError('Document Publisher needs to be set') | |
347 self._publisher.validate() | |
348 if self._tracking is None: | |
349 raise ValidationError('Document Tracking needs to be set') | |
350 self._tracking.validate() | |
351 ordinals = set() | |
352 for note in self._notes: | |
353 note.validate() | |
354 if note._ordinal in ordinals: | |
355 raise ValidationError('Document Note ordinal %d is issued twice' % note._ordinal) | |
356 ordinals.add(note._ordinal) | |
357 for reference in self._references: | |
358 reference.validate() | |
359 for acknowledgment in self._acknowledgments: | |
360 acknowledgment.validate() | |
361 productids = set() | |
362 groupids = set() | |
363 if self._producttree: | |
364 productids, groupids = self._producttree.validate() | |
365 ordinals = set() | |
366 for vulnerability in self._vulnerabilities: | |
367 vulnerability.validate(productids, groupids) | |
368 if vulnerability._ordinal in ordinals: | |
369 raise ValidationError('Vulnerability ordinal %d is issued twice' % vulnerability._ordinal) | |
370 ordinals.add(vulnerability._ordinal) | |
371 | |
372 def __str__(self): | |
373 s = [ | |
374 'Title: %s' % self._title, | |
375 'Type: %s' % self._type, | |
376 'Publisher: %s' % self._publisher, | |
377 'tracking: %s' % self._tracking, | |
378 '%d Notes: %s' % (len(self._notes), ', '.join( | |
379 str(n) for n in self._notes)) | |
380 ] | |
381 if self._distribution is not None: | |
382 s.append('Distribution: %s' % self._distribution) | |
383 s.extend([ | |
384 '%d Acknowledgments' % len(self._acknowledgments), | |
385 'Products: %s' % self._producttree, | |
386 ]) | |
387 return '\n'.join(s) |