Merge ~lgp171188/launchpad:revert-cve-model-changes into launchpad:master
- Git
- lp:~lgp171188/launchpad
- revert-cve-model-changes
- Merge into master
Proposed by
Guruprasad
Status: | Merged |
---|---|
Approved by: | Guruprasad |
Approved revision: | e2aa76d6d69bde6129a71d5c50e6146304e8dc18 |
Merge reported by: | Otto Co-Pilot |
Merged at revision: | not available |
Proposed branch: | ~lgp171188/launchpad:revert-cve-model-changes |
Merge into: | launchpad:master |
Diff against target: |
374 lines (+8/-256) 4 files modified
lib/lp/bugs/interfaces/cve.py (+1/-38) lib/lp/bugs/model/cve.py (+4/-38) lib/lp/bugs/tests/test_cve.py (+1/-168) lib/lp/testing/factory.py (+2/-12) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guruprasad | Approve | ||
Review via email: mp+416676@code.launchpad.net |
Commit message
Revert "Add new fields and methods to ICve and Cve"
This reverts commit 2d216ac658b2bd0
as the corresponding DB changes haven't been merged to
the master branch yet.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/lib/lp/bugs/interfaces/cve.py b/lib/lp/bugs/interfaces/cve.py | |||
2 | index 3a860da..2ba5a53 100644 | |||
3 | --- a/lib/lp/bugs/interfaces/cve.py | |||
4 | +++ b/lib/lp/bugs/interfaces/cve.py | |||
5 | @@ -30,15 +30,12 @@ from zope.interface import ( | |||
6 | 30 | from zope.schema import ( | 30 | from zope.schema import ( |
7 | 31 | Choice, | 31 | Choice, |
8 | 32 | Datetime, | 32 | Datetime, |
9 | 33 | Dict, | ||
10 | 34 | Int, | 33 | Int, |
11 | 35 | Text, | ||
12 | 36 | TextLine, | 34 | TextLine, |
13 | 37 | ) | 35 | ) |
14 | 38 | 36 | ||
15 | 39 | from lp import _ | 37 | from lp import _ |
16 | 40 | from lp.app.validators.validation import valid_cve_sequence | 38 | from lp.app.validators.validation import valid_cve_sequence |
17 | 41 | from lp.services.fields import PersonChoice | ||
18 | 42 | 39 | ||
19 | 43 | 40 | ||
20 | 44 | class CveStatus(DBEnumeratedType): | 41 | class CveStatus(DBEnumeratedType): |
21 | @@ -124,45 +121,12 @@ class ICve(Interface): | |||
22 | 124 | description=_("A title for the CVE"))) | 121 | description=_("A title for the CVE"))) |
23 | 125 | references = Attribute("The set of CVE References for this CVE.") | 122 | references = Attribute("The set of CVE References for this CVE.") |
24 | 126 | 123 | ||
25 | 127 | date_made_public = exported( | ||
26 | 128 | Datetime(title=_('Date Made Public'), required=False, readonly=True), | ||
27 | 129 | as_of='devel' | ||
28 | 130 | ) | ||
29 | 131 | |||
30 | 132 | discoverer = exported( | ||
31 | 133 | PersonChoice( | ||
32 | 134 | title=_('Discoverer'), | ||
33 | 135 | required=False, | ||
34 | 136 | readonly=True, | ||
35 | 137 | vocabulary='ValidPerson' | ||
36 | 138 | ), | ||
37 | 139 | as_of='devel' | ||
38 | 140 | ) | ||
39 | 141 | |||
40 | 142 | cvss = exported( | ||
41 | 143 | Dict( | ||
42 | 144 | title=_('CVSS'), | ||
43 | 145 | description=_( | ||
44 | 146 | 'The CVSS vector strings from various authorities ' | ||
45 | 147 | 'that publish it.' | ||
46 | 148 | ), | ||
47 | 149 | key_type=Text(title=_('The authority that published the score.')), | ||
48 | 150 | value_type=Text(title=_('The CVSS vector string.')), | ||
49 | 151 | required=False, | ||
50 | 152 | readonly=True, | ||
51 | 153 | ), | ||
52 | 154 | as_of='devel' | ||
53 | 155 | ) | ||
54 | 156 | |||
55 | 157 | def createReference(source, content, url=None): | 124 | def createReference(source, content, url=None): |
56 | 158 | """Create a new CveReference for this CVE.""" | 125 | """Create a new CveReference for this CVE.""" |
57 | 159 | 126 | ||
58 | 160 | def removeReference(ref): | 127 | def removeReference(ref): |
59 | 161 | """Remove a CveReference.""" | 128 | """Remove a CveReference.""" |
60 | 162 | 129 | ||
61 | 163 | def setCVSSVectorForAuthority(authority, vector_string): | ||
62 | 164 | """Set the CVSS vector string from an authority.""" | ||
63 | 165 | |||
64 | 166 | 130 | ||
65 | 167 | @exported_as_webservice_collection(ICve) | 131 | @exported_as_webservice_collection(ICve) |
66 | 168 | class ICveSet(Interface): | 132 | class ICveSet(Interface): |
67 | @@ -176,8 +140,7 @@ class ICveSet(Interface): | |||
68 | 176 | def __iter__(): | 140 | def __iter__(): |
69 | 177 | """Iterate through all the Cve records.""" | 141 | """Iterate through all the Cve records.""" |
70 | 178 | 142 | ||
73 | 179 | def new(sequence, description, cvestate=CveStatus.CANDIDATE, | 143 | def new(sequence, description, cvestate=CveStatus.CANDIDATE): |
72 | 180 | date_made_public=None, discoverer=None, cvss=None): | ||
74 | 181 | """Create a new ICve.""" | 144 | """Create a new ICve.""" |
75 | 182 | 145 | ||
76 | 183 | @collection_default_content() | 146 | @collection_default_content() |
77 | diff --git a/lib/lp/bugs/model/cve.py b/lib/lp/bugs/model/cve.py | |||
78 | index f49ce00..27a40b5 100644 | |||
79 | --- a/lib/lp/bugs/model/cve.py | |||
80 | +++ b/lib/lp/bugs/model/cve.py | |||
81 | @@ -9,12 +9,10 @@ __all__ = [ | |||
82 | 9 | import operator | 9 | import operator |
83 | 10 | 10 | ||
84 | 11 | import pytz | 11 | import pytz |
85 | 12 | from storm.databases.postgres import JSON | ||
86 | 13 | from storm.locals import ( | 12 | from storm.locals import ( |
87 | 14 | DateTime, | 13 | DateTime, |
88 | 15 | Desc, | 14 | Desc, |
89 | 16 | Int, | 15 | Int, |
90 | 17 | Reference, | ||
91 | 18 | ReferenceSet, | 16 | ReferenceSet, |
92 | 19 | Store, | 17 | Store, |
93 | 20 | Unicode, | 18 | Unicode, |
94 | @@ -62,29 +60,11 @@ class Cve(StormBase, BugLinkTargetMixin): | |||
95 | 62 | references = ReferenceSet( | 60 | references = ReferenceSet( |
96 | 63 | id, 'CveReference.cve_id', order_by='CveReference.id') | 61 | id, 'CveReference.cve_id', order_by='CveReference.id') |
97 | 64 | 62 | ||
114 | 65 | date_made_public = DateTime(tzinfo=pytz.UTC, allow_none=True) | 63 | def __init__(self, sequence, status, description): |
99 | 66 | discoverer_id = Int(name='discoverer', allow_none=True) | ||
100 | 67 | discoverer = Reference(discoverer_id, 'Person.id') | ||
101 | 68 | _cvss = JSON(name='cvss', allow_none=True) | ||
102 | 69 | |||
103 | 70 | @property | ||
104 | 71 | def cvss(self): | ||
105 | 72 | return self._cvss or {} | ||
106 | 73 | |||
107 | 74 | @cvss.setter | ||
108 | 75 | def cvss(self, value): | ||
109 | 76 | assert value is None or isinstance(value, dict) | ||
110 | 77 | self._cvss = value | ||
111 | 78 | |||
112 | 79 | def __init__(self, sequence, status, description, | ||
113 | 80 | date_made_public=None, discoverer=None, cvss=None): | ||
115 | 81 | super().__init__() | 64 | super().__init__() |
116 | 82 | self.sequence = sequence | 65 | self.sequence = sequence |
117 | 83 | self.status = status | 66 | self.status = status |
118 | 84 | self.description = description | 67 | self.description = description |
119 | 85 | self.date_made_public = date_made_public | ||
120 | 86 | self.discoverer = discoverer | ||
121 | 87 | self._cvss = cvss | ||
122 | 88 | 68 | ||
123 | 89 | @property | 69 | @property |
124 | 90 | def url(self): | 70 | def url(self): |
125 | @@ -131,12 +111,6 @@ class Cve(StormBase, BugLinkTargetMixin): | |||
126 | 131 | getUtility(IXRefSet).delete( | 111 | getUtility(IXRefSet).delete( |
127 | 132 | {('cve', self.sequence): [('bug', str(bug.id))]}) | 112 | {('cve', self.sequence): [('bug', str(bug.id))]}) |
128 | 133 | 113 | ||
129 | 134 | def setCVSSVectorForAuthority(self, authority, vector_string): | ||
130 | 135 | """See ICveReference.""" | ||
131 | 136 | if self._cvss is None: | ||
132 | 137 | self._cvss = {} | ||
133 | 138 | self._cvss[authority] = vector_string | ||
134 | 139 | |||
135 | 140 | 114 | ||
136 | 141 | @implementer(ICveSet) | 115 | @implementer(ICveSet) |
137 | 142 | class CveSet: | 116 | class CveSet: |
138 | @@ -162,18 +136,10 @@ class CveSet: | |||
139 | 162 | """See ICveSet.""" | 136 | """See ICveSet.""" |
140 | 163 | return iter(IStore(Cve).find(Cve)) | 137 | return iter(IStore(Cve).find(Cve)) |
141 | 164 | 138 | ||
144 | 165 | def new(self, sequence, description, status=CveStatus.CANDIDATE, | 139 | def new(self, sequence, description, status=CveStatus.CANDIDATE): |
143 | 166 | date_made_public=None, discoverer=None, cvss=None): | ||
145 | 167 | """See ICveSet.""" | 140 | """See ICveSet.""" |
155 | 168 | cve = Cve( | 141 | cve = Cve(sequence=sequence, status=status, |
156 | 169 | sequence=sequence, | 142 | description=description) |
148 | 170 | status=status, | ||
149 | 171 | description=description, | ||
150 | 172 | date_made_public=date_made_public, | ||
151 | 173 | discoverer=discoverer, | ||
152 | 174 | cvss=cvss | ||
153 | 175 | ) | ||
154 | 176 | |||
157 | 177 | IStore(Cve).add(cve) | 143 | IStore(Cve).add(cve) |
158 | 178 | return cve | 144 | return cve |
159 | 179 | 145 | ||
160 | diff --git a/lib/lp/bugs/tests/test_cve.py b/lib/lp/bugs/tests/test_cve.py | |||
161 | index 6882b34..90bffc7 100644 | |||
162 | --- a/lib/lp/bugs/tests/test_cve.py | |||
163 | +++ b/lib/lp/bugs/tests/test_cve.py | |||
164 | @@ -3,19 +3,10 @@ | |||
165 | 3 | 3 | ||
166 | 4 | """CVE related tests.""" | 4 | """CVE related tests.""" |
167 | 5 | 5 | ||
168 | 6 | from datetime import datetime | ||
169 | 7 | |||
170 | 8 | import pytz | ||
171 | 9 | from testtools.matchers import MatchesStructure | ||
172 | 10 | from testtools.testcase import ExpectedException | ||
173 | 11 | from zope.component import getUtility | 6 | from zope.component import getUtility |
174 | 12 | from zope.security.proxy import removeSecurityProxy | ||
175 | 13 | 7 | ||
176 | 14 | from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams | 8 | from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams |
181 | 15 | from lp.bugs.interfaces.cve import ( | 9 | from lp.bugs.interfaces.cve import ICveSet |
178 | 16 | CveStatus, | ||
179 | 17 | ICveSet, | ||
180 | 18 | ) | ||
182 | 19 | from lp.testing import ( | 10 | from lp.testing import ( |
183 | 20 | login_person, | 11 | login_person, |
184 | 21 | person_logged_in, | 12 | person_logged_in, |
185 | @@ -142,161 +133,3 @@ class TestBugLinks(TestCaseWithFactory): | |||
186 | 142 | self.assertContentEqual([bug1], cve2.bugs) | 133 | self.assertContentEqual([bug1], cve2.bugs) |
187 | 143 | self.assertContentEqual([cve2], bug1.cves) | 134 | self.assertContentEqual([cve2], bug1.cves) |
188 | 144 | self.assertContentEqual([], bug2.cves) | 135 | self.assertContentEqual([], bug2.cves) |
189 | 145 | |||
190 | 146 | |||
191 | 147 | class TestCve(TestCaseWithFactory): | ||
192 | 148 | """Tests for Cve fields and methods.""" | ||
193 | 149 | |||
194 | 150 | layer = DatabaseFunctionalLayer | ||
195 | 151 | |||
196 | 152 | def test_cveset_new_method_optional_parameters(self): | ||
197 | 153 | cve = getUtility(ICveSet).new( | ||
198 | 154 | sequence='2099-1234', | ||
199 | 155 | description='A critical vulnerability', | ||
200 | 156 | status=CveStatus.CANDIDATE | ||
201 | 157 | ) | ||
202 | 158 | self.assertThat(cve, MatchesStructure.byEquality( | ||
203 | 159 | sequence='2099-1234', | ||
204 | 160 | status=CveStatus.CANDIDATE, | ||
205 | 161 | description='A critical vulnerability', | ||
206 | 162 | date_made_public=None, | ||
207 | 163 | discoverer=None, | ||
208 | 164 | cvss={} | ||
209 | 165 | )) | ||
210 | 166 | |||
211 | 167 | def test_cveset_new_method_parameters(self): | ||
212 | 168 | person = self.factory.makePerson() | ||
213 | 169 | today = datetime.now(tz=pytz.UTC) | ||
214 | 170 | cvss = { | ||
215 | 171 | 'nvd': 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H' | ||
216 | 172 | } | ||
217 | 173 | cve = getUtility(ICveSet).new( | ||
218 | 174 | sequence='2099-1234', | ||
219 | 175 | description='A critical vulnerability', | ||
220 | 176 | status=CveStatus.CANDIDATE, | ||
221 | 177 | date_made_public=today, | ||
222 | 178 | discoverer=person, | ||
223 | 179 | cvss=cvss | ||
224 | 180 | ) | ||
225 | 181 | self.assertThat(cve, MatchesStructure.byEquality( | ||
226 | 182 | sequence='2099-1234', | ||
227 | 183 | status=CveStatus.CANDIDATE, | ||
228 | 184 | description='A critical vulnerability', | ||
229 | 185 | date_made_public=today, | ||
230 | 186 | discoverer=person, | ||
231 | 187 | cvss=cvss | ||
232 | 188 | )) | ||
233 | 189 | |||
234 | 190 | def test_cve_date_made_public_invalid_values(self): | ||
235 | 191 | invalid_values = ['', 'abcd', {'a': 1}, | ||
236 | 192 | [1, 'a', '2', 'b'], '2022-01-01'] | ||
237 | 193 | cve = self.factory.makeCVE( | ||
238 | 194 | sequence='2099-1234', | ||
239 | 195 | description='A critical vulnerability', | ||
240 | 196 | cvestate=CveStatus.CANDIDATE, | ||
241 | 197 | ) | ||
242 | 198 | for invalid_value in invalid_values: | ||
243 | 199 | with ExpectedException(TypeError, 'Expected datetime,.*'): | ||
244 | 200 | removeSecurityProxy(cve).date_made_public = invalid_value | ||
245 | 201 | |||
246 | 202 | def test_cve_discoverer_id_invalid_values(self): | ||
247 | 203 | invalid_values = ['', 'abcd', '2022-01-01', datetime.now()] | ||
248 | 204 | |||
249 | 205 | cve = self.factory.makeCVE( | ||
250 | 206 | sequence='2099-1234', | ||
251 | 207 | description='A critical vulnerability', | ||
252 | 208 | cvestate=CveStatus.CANDIDATE, | ||
253 | 209 | ) | ||
254 | 210 | for invalid_value in invalid_values: | ||
255 | 211 | with ExpectedException(TypeError, 'Expected int,.*'): | ||
256 | 212 | removeSecurityProxy(cve).discoverer_id = invalid_value | ||
257 | 213 | |||
258 | 214 | def test_cve_cvss_invalid_values(self): | ||
259 | 215 | invalid_values = ['', 'abcd', '2022-01-01', datetime.now()] | ||
260 | 216 | cve = self.factory.makeCVE( | ||
261 | 217 | sequence='2099-1234', | ||
262 | 218 | description='A critical vulnerability', | ||
263 | 219 | cvestate=CveStatus.CANDIDATE, | ||
264 | 220 | ) | ||
265 | 221 | for invalid_value in invalid_values: | ||
266 | 222 | with ExpectedException(AssertionError): | ||
267 | 223 | removeSecurityProxy(cve).cvss = invalid_value | ||
268 | 224 | |||
269 | 225 | def test_cvss_value_returned_when_null(self): | ||
270 | 226 | cve = self.factory.makeCVE( | ||
271 | 227 | sequence='2099-1234', | ||
272 | 228 | description='A critical vulnerability', | ||
273 | 229 | cvestate=CveStatus.CANDIDATE, | ||
274 | 230 | ) | ||
275 | 231 | cve = removeSecurityProxy(cve) | ||
276 | 232 | self.assertIsNone(cve._cvss) | ||
277 | 233 | self.assertEqual({}, cve.cvss) | ||
278 | 234 | |||
279 | 235 | def test_setCVSSVectorForAuthority_initially_unset(self): | ||
280 | 236 | cve = self.factory.makeCVE( | ||
281 | 237 | sequence='2099-1234', | ||
282 | 238 | description='A critical vulnerability', | ||
283 | 239 | cvestate=CveStatus.CANDIDATE, | ||
284 | 240 | ) | ||
285 | 241 | unproxied_cve = removeSecurityProxy(cve) | ||
286 | 242 | self.assertIsNone(unproxied_cve._cvss) | ||
287 | 243 | self.assertEqual({}, unproxied_cve.cvss) | ||
288 | 244 | |||
289 | 245 | cve.setCVSSVectorForAuthority( | ||
290 | 246 | authority="nvd", | ||
291 | 247 | vector_string="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" | ||
292 | 248 | ) | ||
293 | 249 | |||
294 | 250 | self.assertEqual( | ||
295 | 251 | {"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, | ||
296 | 252 | unproxied_cve.cvss | ||
297 | 253 | ) | ||
298 | 254 | |||
299 | 255 | def test_setCVSSVectorForAuthority_overwrite_existing_key_value(self): | ||
300 | 256 | cve = self.factory.makeCVE( | ||
301 | 257 | sequence='2099-1234', | ||
302 | 258 | description='A critical vulnerability', | ||
303 | 259 | cvestate=CveStatus.CANDIDATE, | ||
304 | 260 | cvss={"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"} | ||
305 | 261 | ) | ||
306 | 262 | unproxied_cve = removeSecurityProxy(cve) | ||
307 | 263 | self.assertEqual( | ||
308 | 264 | {"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, | ||
309 | 265 | unproxied_cve.cvss | ||
310 | 266 | ) | ||
311 | 267 | |||
312 | 268 | cve.setCVSSVectorForAuthority( | ||
313 | 269 | authority="nvd", | ||
314 | 270 | vector_string="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" | ||
315 | 271 | ) | ||
316 | 272 | |||
317 | 273 | self.assertEqual( | ||
318 | 274 | {"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"}, | ||
319 | 275 | unproxied_cve.cvss | ||
320 | 276 | ) | ||
321 | 277 | |||
322 | 278 | def test_setCVSSVectorForAuthority_add_new_when_initial_value_set(self): | ||
323 | 279 | cve = self.factory.makeCVE( | ||
324 | 280 | sequence='2099-1234', | ||
325 | 281 | description='A critical vulnerability', | ||
326 | 282 | cvestate=CveStatus.CANDIDATE, | ||
327 | 283 | cvss={"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"} | ||
328 | 284 | ) | ||
329 | 285 | unproxied_cve = removeSecurityProxy(cve) | ||
330 | 286 | self.assertEqual( | ||
331 | 287 | {"nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}, | ||
332 | 288 | unproxied_cve.cvss | ||
333 | 289 | ) | ||
334 | 290 | |||
335 | 291 | cve.setCVSSVectorForAuthority( | ||
336 | 292 | authority="nist", | ||
337 | 293 | vector_string="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" | ||
338 | 294 | ) | ||
339 | 295 | |||
340 | 296 | self.assertEqual( | ||
341 | 297 | { | ||
342 | 298 | "nvd": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", | ||
343 | 299 | "nist": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" | ||
344 | 300 | }, | ||
345 | 301 | unproxied_cve.cvss | ||
346 | 302 | ) | ||
347 | diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py | |||
348 | index 9e37780..041cb89 100644 | |||
349 | --- a/lib/lp/testing/factory.py | |||
350 | +++ b/lib/lp/testing/factory.py | |||
351 | @@ -4582,21 +4582,11 @@ class BareLaunchpadObjectFactory(ObjectFactory): | |||
352 | 4582 | return secret, token | 4582 | return secret, token |
353 | 4583 | 4583 | ||
354 | 4584 | def makeCVE(self, sequence, description=None, | 4584 | def makeCVE(self, sequence, description=None, |
358 | 4585 | cvestate=CveStatus.CANDIDATE, | 4585 | cvestate=CveStatus.CANDIDATE): |
356 | 4586 | date_made_public=None, discoverer=None, | ||
357 | 4587 | cvss=None): | ||
359 | 4588 | """Create a new CVE record.""" | 4586 | """Create a new CVE record.""" |
360 | 4589 | if description is None: | 4587 | if description is None: |
361 | 4590 | description = self.getUniqueUnicode() | 4588 | description = self.getUniqueUnicode() |
371 | 4591 | 4589 | return getUtility(ICveSet).new(sequence, description, cvestate) | |
363 | 4592 | return getUtility(ICveSet).new( | ||
364 | 4593 | sequence, | ||
365 | 4594 | description, | ||
366 | 4595 | cvestate, | ||
367 | 4596 | date_made_public, | ||
368 | 4597 | discoverer, | ||
369 | 4598 | cvss | ||
370 | 4599 | ) | ||
372 | 4600 | 4590 | ||
373 | 4601 | def makePublisherConfig(self, distribution=None, root_dir=None, | 4591 | def makePublisherConfig(self, distribution=None, root_dir=None, |
374 | 4602 | base_url=None, copy_base_url=None): | 4592 | base_url=None, copy_base_url=None): |
Self-approving since this is a trivial revert.