11from datetime import datetime
22import dataclasses
33import logging
4+ from typing import Tuple
5+
6+ from django .db import transaction
7+
8+ from vulnerabilities import models
9+ from vulnerabilities .data_source import PackageURL
10+ from vulnerabilities .data_source import Advisory
411
512logger = logging .getLogger (__name__ )
613
@@ -15,11 +22,111 @@ def __init__(self, improver):
1522 self .improver = improver
1623
1724 def run (self ) -> None :
18- logger .info ("Improving using %s." , self .improver .__module__ )
19- inferences = self .improver .updated_inferences ()
25+ logger .info ("Improving using %s." , self .improver .__name__ )
26+ inferences = self .improver () .updated_inferences ()
2027 process_inferences (inferences )
21- logger .info ("Finished improving using %s." , self .improver .__module__ )
28+ logger .info ("Finished improving using %s." , self .improver .__name__ )
2229
2330
31+ @transaction .atomic
2432def process_inferences (inferences ):
25- ...
33+ bulk_create_vuln_pkg_refs = set ()
34+ for inference in inferences :
35+ advisory = inference .advisory
36+ vuln , vuln_created = _get_or_create_vulnerability (advisory )
37+ for vuln_ref in advisory .references :
38+ ref , _ = models .VulnerabilityReference .objects .get_or_create (
39+ vulnerability = vuln , reference_id = vuln_ref .reference_id , url = vuln_ref .url
40+ )
41+
42+ for score in vuln_ref .severities :
43+ models .VulnerabilitySeverity .objects .update_or_create (
44+ vulnerability = vuln ,
45+ scoring_system = score .system .identifier ,
46+ reference = ref ,
47+ defaults = {"value" : str (score .value )},
48+ )
49+
50+ for aff_pkg in advisory .affected_package_urls :
51+ vulnerable_package , _ = _get_or_create_package (
52+ aff_pkg
53+ )
54+ create_or_update_relation (
55+ relation = models .PackageRelatedVulnerability ,
56+ vulnerability = vuln ,
57+ source = inference .source ,
58+ package = vulnerable_package ,
59+ confidence = inference .confidence )
60+
61+ for fixed_pkg in advisory .fixed_package_urls :
62+ patched_package , _ = _get_or_create_package (
63+ fixed_pkg
64+ )
65+ create_or_update_relation (
66+ relation = models .PackageRelatedVulnerabilityFix ,
67+ vulnerability = vuln ,
68+ source = inference .source ,
69+ package = vulnerable_package ,
70+ confidence = inference .confidence )
71+
72+
73+ models .PackageRelatedVulnerability .objects .bulk_create (
74+ [i .to_model_object () for i in bulk_create_vuln_pkg_refs ]
75+ )
76+
77+
78+ def _get_or_create_vulnerability (
79+ advisory : Advisory ,
80+ ) -> Tuple [models .Vulnerability , bool ]:
81+
82+ vuln , created = models .Vulnerability .objects .get_or_create (
83+ vulnerability_id = advisory .vulnerability_id
84+ ) # nopep8
85+ # Eventually we only want to keep summary from NVD and ignore other descriptions.
86+ if advisory .summary and vuln .summary != advisory .summary :
87+ vuln .summary = advisory .summary
88+ vuln .save ()
89+
90+ return vuln , created
91+
92+
93+ def _get_or_create_package (p : PackageURL ) -> Tuple [models .Package , bool ]:
94+
95+ query_kwargs = {}
96+ for key , val in p .to_dict ().items ():
97+ if not val :
98+ if key == "qualifiers" :
99+ query_kwargs [key ] = {}
100+ else :
101+ query_kwargs [key ] = ""
102+ else :
103+ query_kwargs [key ] = val
104+
105+ return models .Package .objects .get_or_create (** query_kwargs )
106+
107+
108+ def _package_url_to_package (purl : PackageURL ) -> models .Package :
109+ p = models .Package ()
110+ p .set_package_url (purl )
111+ return p
112+
113+ def create_or_update_relation (relation , vulnerability , source , package , confidence ):
114+ try :
115+ entry = relation .objects .get (
116+ vulnerability = vulnerability ,
117+ package = package
118+ )
119+ if confidence > entry .confidence :
120+ entry .source = source
121+ entry .confidence = confidence
122+ entry .save ()
123+ logger .debug ("%s: Confidence improved for %s R %s, new confidence: %d" , relation , package , vulnerability , confidence )
124+
125+ except relation .DoesNotExist :
126+ relation .objects .create (
127+ vulnerability = vulnerability ,
128+ source = source ,
129+ package = package ,
130+ confidence = confidence
131+ )
132+
0 commit comments