@@ -68,11 +68,14 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
6868 logger .info (f"Improving advisory id: { advisory .id } " )
6969
7070 for inference in inferences :
71- vulnerability = get_or_create_vulnerability_and_aliases (
72- vulnerability_id = inference .vulnerability_id ,
73- alias_names = inference .aliases ,
74- summary = inference .summary ,
75- )
71+ if not inference .aliases :
72+ vulnerability = get_or_create_vulnerability_without_aliases (inference )
73+ else :
74+ vulnerability = get_or_create_vulnerability_and_aliases (
75+ vulnerability_id = inference .vulnerability_id ,
76+ alias_names = inference .aliases ,
77+ summary = inference .summary ,
78+ )
7679
7780 if not vulnerability :
7881 logger .warn (f"Unable to get vulnerability for inference: { inference !r} " )
@@ -218,3 +221,76 @@ def get_or_create_vulnerability_and_aliases(vulnerability_id, alias_names, summa
218221 logger .info (f"New alias for { vulnerability !r} : { alias_name } " )
219222
220223 return vulnerability
224+
225+
226+ def get_or_create_vulnerability_without_aliases (inference ):
227+ """
228+ Get or create vulnerabilitiy without aliases
229+
230+ Try to get vulnerability by matching references,
231+ summary and packages. If no vulnerability is found,
232+ create a new one.
233+ """
234+
235+ refs_are_exact_match = True
236+
237+ vuln_by_refs = {}
238+
239+ for ref in inference .references :
240+ try :
241+ reference = VulnerabilityReference .objects .get (url = ref .url )
242+ vuln_by_refs [ref .url ] = set (reference .vulnerabilities .all ())
243+ except VulnerabilityReference .DoesNotExist :
244+ refs_are_exact_match = False
245+ pass
246+
247+ if refs_are_exact_match :
248+ common_vulns = set .intersection (* vuln_by_refs .values ())
249+
250+ if len (common_vulns ) == 1 :
251+ return common_vulns .pop ()
252+ elif len (common_vulns ) > 1 :
253+ for vuln in common_vulns :
254+ if vuln .summary == inference .summary :
255+ if match_packages (inference , vuln ):
256+ return vuln
257+
258+ vulnerability = Vulnerability (summary = inference .summary )
259+ vulnerability .save ()
260+
261+ return vulnerability
262+
263+
264+ def match_packages (inference , vuln ):
265+ """
266+ Check if the packages in the inference match the packages in the vulnerability
267+ """
268+ for affected_purl in inference .affected_purls :
269+ if not find_package_and_check_related_to_vuln (purl = affected_purl , fix = False , vuln = vuln ):
270+ return False
271+ if inference .fixed_purl and not find_package_and_check_related_to_vuln (
272+ purl = inference .fixed_purl , fix = True , vuln = vuln
273+ ):
274+ return False
275+ return True
276+
277+
278+ def find_package_and_check_related_to_vuln (purl , fix , vuln ):
279+ """
280+ Find package in the database and check if it is associated
281+ with the vulnerability.
282+ If package is not found, return False
283+ If package is found, but not associated with the vulnerability, return False
284+ If package is found and associated with the vulnerability, return True
285+ """
286+ try :
287+ package = Package .objects .get_from_purl (purl = purl )
288+ if not PackageRelatedVulnerability .objects .exists (
289+ vulnerability = vuln ,
290+ package = package ,
291+ fix = fix ,
292+ ):
293+ return False
294+ except Package .DoesNotExist :
295+ return False
296+ return True
0 commit comments