15
15
16
16
from django .core .exceptions import ValidationError
17
17
from django .db import transaction
18
+ from django .db .models .query import QuerySet
18
19
19
20
from vulnerabilities .importer import AdvisoryData
20
21
from vulnerabilities .importer import Importer
@@ -96,25 +97,37 @@ def process_advisories(
96
97
Insert advisories into the database
97
98
Return the number of inserted advisories.
98
99
"""
100
+ from vulnerabilities .pipes .advisory import get_or_create_aliases
101
+ from vulnerabilities .utils import compute_content_id
102
+
99
103
count = 0
100
104
advisories = []
101
105
for data in advisory_datas :
106
+ content_id = compute_content_id (advisory_data = data )
107
+ advisory = {
108
+ "summary" : data .summary ,
109
+ "affected_packages" : [pkg .to_dict () for pkg in data .affected_packages ],
110
+ "references" : [ref .to_dict () for ref in data .references ],
111
+ "date_published" : data .date_published ,
112
+ "weaknesses" : data .weaknesses ,
113
+ "created_by" : importer_name ,
114
+ "date_collected" : datetime .datetime .now (tz = datetime .timezone .utc ),
115
+ }
102
116
try :
117
+ aliases = get_or_create_aliases (aliases = data .aliases )
103
118
obj , created = Advisory .objects .get_or_create (
104
- aliases = data .aliases ,
105
- summary = data .summary ,
106
- affected_packages = [pkg .to_dict () for pkg in data .affected_packages ],
107
- references = [ref .to_dict () for ref in data .references ],
108
- date_published = data .date_published ,
109
- weaknesses = data .weaknesses ,
110
- defaults = {
111
- "created_by" : importer_name ,
112
- "date_collected" : datetime .datetime .now (tz = datetime .timezone .utc ),
113
- },
119
+ unique_content_id = content_id ,
114
120
url = data .url ,
121
+ defaults = advisory ,
115
122
)
123
+ obj .aliases .add (* aliases )
116
124
if not obj .date_imported :
117
125
advisories .append (obj )
126
+ except Advisory .MultipleObjectsReturned :
127
+ logger .error (
128
+ f"Multiple Advisories returned: unique_content_id: { content_id } , url: { data .url } , advisory: { advisory !r} "
129
+ )
130
+ raise
118
131
except Exception as e :
119
132
logger .error (
120
133
f"Error while processing { data !r} with aliases { data .aliases !r} : { e !r} \n { traceback_format_exc ()} "
@@ -148,6 +161,8 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
148
161
erroneous. Also, the atomic transaction for every advisory and its
149
162
inferences makes sure that date_imported of advisory is consistent.
150
163
"""
164
+ from vulnerabilities .pipes .advisory import get_or_create_aliases
165
+
151
166
inferences_processed_count = 0
152
167
153
168
if not inferences :
@@ -157,9 +172,10 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
157
172
logger .info (f"Improving advisory id: { advisory .id } " )
158
173
159
174
for inference in inferences :
175
+ aliases = get_or_create_aliases (inference .aliases )
160
176
vulnerability = get_or_create_vulnerability_and_aliases (
161
177
vulnerability_id = inference .vulnerability_id ,
162
- aliases = inference . aliases ,
178
+ aliases = aliases ,
163
179
summary = inference .summary ,
164
180
advisory = advisory ,
165
181
)
@@ -265,14 +281,13 @@ def create_valid_vulnerability_reference(url, reference_id=None):
265
281
266
282
267
283
def get_or_create_vulnerability_and_aliases (
268
- aliases : List [ str ] , vulnerability_id = None , summary = None , advisory = None
284
+ aliases : QuerySet , vulnerability_id = None , summary = None , advisory = None
269
285
):
270
286
"""
271
287
Get or create vulnerabilitiy and aliases such that all existing and new
272
288
aliases point to the same vulnerability
273
289
"""
274
- aliases = set (alias .strip () for alias in aliases if alias and alias .strip ())
275
- new_alias_names , existing_vulns = get_vulns_for_aliases_and_get_new_aliases (aliases )
290
+ new_aliases , existing_vulns = get_vulns_for_aliases_and_get_new_aliases (aliases )
276
291
277
292
# All aliases must point to the same vulnerability
278
293
vulnerability = None
@@ -310,11 +325,11 @@ def get_or_create_vulnerability_and_aliases(
310
325
# f"Inconsistent summary for {vulnerability.vulnerability_id}. "
311
326
# f"Existing: {vulnerability.summary!r}, provided: {summary!r}"
312
327
# )
313
- associate_vulnerability_with_aliases (vulnerability = vulnerability , aliases = new_alias_names )
328
+ associate_vulnerability_with_aliases (vulnerability = vulnerability , aliases = new_aliases )
314
329
else :
315
330
try :
316
331
vulnerability = create_vulnerability_and_add_aliases (
317
- aliases = new_alias_names , summary = summary
332
+ aliases = new_aliases , summary = summary
318
333
)
319
334
importer_name = get_importer_name (advisory )
320
335
VulnerabilityChangeLog .log_import (
@@ -324,24 +339,22 @@ def get_or_create_vulnerability_and_aliases(
324
339
)
325
340
except Exception as e :
326
341
logger .error (
327
- f"Cannot create vulnerability with summary { summary !r} and { new_alias_names !r} { e !r} .\n { traceback_format_exc ()} ."
342
+ f"Cannot create vulnerability with summary { summary !r} and { new_aliases !r} { e !r} .\n { traceback_format_exc ()} ."
328
343
)
329
344
return
330
345
331
346
return vulnerability
332
347
333
348
334
- def get_vulns_for_aliases_and_get_new_aliases (aliases ):
349
+ def get_vulns_for_aliases_and_get_new_aliases (aliases : QuerySet ):
335
350
"""
336
351
Return ``new_aliases`` that are not in the database and
337
352
``existing_vulns`` that point to the given ``aliases``.
338
353
"""
339
- new_aliases = set (aliases )
340
- existing_vulns = set ()
341
- for alias in Alias .objects .filter (alias__in = aliases ):
342
- existing_vulns .add (alias .vulnerability )
343
- new_aliases .remove (alias .alias )
344
- return new_aliases , existing_vulns
354
+ new_aliases = aliases .filter (vulnerability__isnull = True )
355
+ existing_vulns = [alias .vulnerability for alias in aliases .filter (vulnerability__isnull = False )]
356
+
357
+ return new_aliases , list (set (existing_vulns ))
345
358
346
359
347
360
@transaction .atomic
@@ -360,7 +373,5 @@ def create_vulnerability_and_add_aliases(aliases, summary):
360
373
361
374
362
375
def associate_vulnerability_with_aliases (aliases , vulnerability ):
363
- for alias_name in aliases :
364
- alias = Alias (alias = alias_name , vulnerability = vulnerability )
365
- alias .save ()
366
- logger .info (f"New alias for { vulnerability !r} : { alias_name } " )
376
+ aliases .update (vulnerability = vulnerability )
377
+ logger .info (f"New alias for { vulnerability !r} : { aliases } " )
0 commit comments