2929from typing import List
3030from typing import Set
3131from typing import Tuple
32+ from typing import Optional
3233
3334import packageurl
3435from django .db import DataError
4142
4243logger = logging .getLogger (__name__ )
4344
45+ @dataclasses .dataclass (frozen = True )
46+ class VulnerabilityReference_inserter :
47+ vulnerability : models .Vulnerability
48+ reference_id : Optional [str ] = ''
49+ url : Optional [str ] = ''
50+
51+ def __post_init__ (self ):
52+ if not any ([self .reference_id ,self .url ]) :
53+ raise TypeError ("VulnerabilityReference_inserter expects either reference_id or url" )
54+
55+ @dataclasses .dataclass (frozen = True )
56+ class Vulnerability_Package_inserter :
57+ vulnerability : models .Vulnerability
58+ is_vulnerable : bool
59+ package : models .Package
4460
4561class ImportRunner :
4662 """
@@ -89,23 +105,22 @@ def _process_updated_advisories(data_source: DataSource) -> None:
89105 """
90106 TODO: Break this method into smaller functions
91107 """
108+ bulk_create_vuln_refs = set ()
109+ bulk_create_vuln_pkg_refs = set ()
110+ bulk_update_vuln_pkg_refs = set ()
92111 for batch in data_source .updated_advisories ():
93112 for advisory in batch :
94-
95- bulk_create_vuln_refs = []
96- bulk_update_vuln_pkg_refs = []
97- bulk_create_vuln_pkg_refs = []
98-
99113 vuln , vuln_created = _get_or_create_vulnerability (advisory )
100114
101115 if vuln_created :
102116 # This means vulnerability didn't previously exist in the db, so bulk create
103117 # is used without any hesitation
104118 for id_ in set (advisory .reference_ids ):
105- bulk_create_vuln_refs .append (models .VulnerabilityReference (vulnerability = vuln , reference_id = id_ ))
119+ # bulk_create_vuln_refs.append(models.VulnerabilityReference(vulnerability=vuln, reference_id=id_))
120+ bulk_create_vuln_refs .add (VulnerabilityReference_inserter (vulnerability = vuln , reference_id = id_ ))
106121
107122 for url in set (advisory .reference_urls ):
108- bulk_create_vuln_refs .append ( models . VulnerabilityReference (vulnerability = vuln , url = url ))
123+ bulk_create_vuln_refs .add ( VulnerabilityReference_inserter (vulnerability = vuln , url = url ))
109124
110125 else :
111126 vuln_refs_qs = models .VulnerabilityReference .objects .filter (vulnerability = vuln )
@@ -115,60 +130,58 @@ def _process_updated_advisories(data_source: DataSource) -> None:
115130 vuln_urls = {ref .url for ref in vuln_refs_qs }
116131
117132 for id_ in advisory .reference_ids :
118- if id_ not in vuln_ids :
119- # Delete the item because it will allow the duplicates pass to through if they are not
120- # present in vuln_ids
133+ # Add the item preventing duplicates pass to through.
134+ if id_ not in vuln_ids :
121135 vuln_ids .add (id_ )
122- bulk_create_vuln_refs .append ( models . VulnerabilityReference (vulnerability = vuln , reference_id = id_ ))
136+ bulk_create_vuln_refs .add ( VulnerabilityReference_inserter (vulnerability = vuln , reference_id = id_ ))
123137
124138 for url in advisory .reference_urls :
125- # Delete the item because it will allow the duplicates pass to through if they are not
126- # present in vuln_urls
139+ # Add the item preventing duplicates pass to through.
127140 if url not in vuln_urls :
128141 vuln_urls .add (url )
129- bulk_create_vuln_refs .append (models .VulnerabilityReference (vulnerability = vuln , url = url ))
130-
131- models .VulnerabilityReference .objects .bulk_create (bulk_create_vuln_refs )
142+ bulk_create_vuln_refs .add (VulnerabilityReference_inserter (vulnerability = vuln , url = url ))
143+
132144
133145 for ipurl in advisory .impacted_package_urls :
134146 pkg , pkg_created = _get_or_create_package (ipurl )
135- vuln_pkgs_ref = models . Vulnerability_Package_Relation (package = pkg ,vulnerability = vuln ,is_vulnerable = True )
147+ vuln_pkgs_ref = Vulnerability_Package_inserter (package = pkg ,vulnerability = vuln ,is_vulnerable = True )
136148
137149 if pkg_created or vuln_created :
138- bulk_create_vuln_pkg_refs .append (vuln_pkgs_ref )
150+ bulk_create_vuln_pkg_refs .add (vuln_pkgs_ref )
139151
140152 else :
141153 qs = models .Vulnerability_Package_Relation .objects .filter (package = pkg ,vulnerability = vuln )
142154 if qs :
143155 if not qs [0 ].is_vulnerable :
144156 qs [0 ].is_vulnerable = True
145- bulk_update_vuln_pkg_refs .append (qs [0 ])
157+ bulk_update_vuln_pkg_refs .add (qs [0 ])
146158
147159 else :
148- bulk_create_vuln_pkg_refs .append (vuln_pkgs_ref )
160+ bulk_create_vuln_pkg_refs .add (vuln_pkgs_ref )
149161
150162 for rpurl in advisory .resolved_package_urls :
151163 pkg , pkg_created = _get_or_create_package (rpurl )
152- vuln_pkgs_ref = models . Vulnerability_Package_Relation (package = pkg ,vulnerability = vuln ,is_vulnerable = False )
164+ vuln_pkgs_ref = Vulnerability_Package_inserter (package = pkg ,vulnerability = vuln ,is_vulnerable = True )
153165
154166 if pkg_created or vuln_created :
155167 # For a `Vulnerability_Package_Relation` tp exist it needs both, the package and
156168 # vulnerability to already exist in the db.
157- bulk_create_vuln_pkg_refs .append (vuln_pkgs_ref )
169+ bulk_create_vuln_pkg_refs .add (vuln_pkgs_ref )
158170
159171 else :
160172 qs = models .Vulnerability_Package_Relation .objects .filter (package = pkg ,vulnerability = vuln )
161173 if qs :
162174 if qs [0 ].is_vulnerable :
163175 qs [0 ].is_vulnerable = False
164- bulk_update_vuln_pkg_refs .append (qs [0 ])
176+ bulk_update_vuln_pkg_refs .add (qs [0 ])
165177
166178 else :
167- bulk_create_vuln_pkg_refs .append (vuln_pkgs_ref )
179+ bulk_create_vuln_pkg_refs .add (vuln_pkgs_ref )
180+
181+ models .Vulnerability_Package_Relation .objects .bulk_update (bulk_update_vuln_pkg_refs , ['is_vulnerable' ])
182+ models .Vulnerability_Package_Relation .objects .bulk_create ([models .Vulnerability_Package_Relation (** dataclasses .asdict (i )) for i in bulk_create_vuln_pkg_refs ])
183+ models .VulnerabilityReference .objects .bulk_create ([models .VulnerabilityReference (** dataclasses .asdict (i )) for i in bulk_create_vuln_refs ])
168184
169- models .Vulnerability_Package_Relation .objects .bulk_update (bulk_update_vuln_pkg_refs , ['is_vulnerable' ])
170- models .Vulnerability_Package_Relation .objects .bulk_create (bulk_create_vuln_pkg_refs )
171-
172185def _process_added_advisories (data_source : DataSource ) -> None :
173186 for batch in data_source .added_advisories ():
174187 try :
0 commit comments