Skip to content

Commit 60b63f8

Browse files
committed
Revert _process_added_advisories, make style changes
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
1 parent 35280ff commit 60b63f8

1 file changed

Lines changed: 60 additions & 51 deletions

File tree

vulnerabilities/import_runner.py

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import dataclasses
2525
import datetime
2626
import logging
27-
from itertools import chain
2827
from typing import Dict
2928
from typing import List
3029
from typing import Set
@@ -49,15 +48,15 @@
4948

5049

5150
@dataclasses.dataclass(frozen=True)
52-
class VulnerabilityReference_inserter:
51+
class VulnerabilityReferenceInserter:
5352
vulnerability: models.Vulnerability
5453
reference_id: Optional[str] = ''
5554
url: Optional[str] = ''
5655

5756
def __post_init__(self):
5857
if not any([self.reference_id, self.url]):
5958
raise TypeError(
60-
"VulnerabilityReference_inserter expects either reference_id or url")
59+
"VulnerabilityReferenceInserter expects either reference_id or url")
6160

6261
def to_model_object(self):
6362
return models.VulnerabilityReference(**dataclasses.asdict(self))
@@ -69,7 +68,7 @@ def to_model_object(self):
6968

7069

7170
@dataclasses.dataclass(frozen=True)
72-
class PackageRelatedVulnerability_inserter:
71+
class PackageRelatedVulnerabilityInserter:
7372
vulnerability: models.Vulnerability
7473
is_vulnerable: bool
7574
package: models.Package
@@ -125,14 +124,10 @@ def run(self, cutoff_date: datetime.datetime = None) -> None:
125124

126125

127126
def _process_updated_advisories(data_source: DataSource) -> None:
128-
"""
129-
TODO: Break this method into smaller functions
130-
"""
131127
bulk_create_vuln_refs = set()
132128
bulk_create_vuln_pkg_refs = set()
133129
for batch in data_source.updated_advisories():
134130
for advisory in batch:
135-
136131
vuln, vuln_created, references = _create_vulnerability_and_references(
137132
advisory)
138133
bulk_create_vuln_refs.update(references)
@@ -142,6 +137,11 @@ def _process_updated_advisories(data_source: DataSource) -> None:
142137
vuln, vuln_created, advisory.resolved_package_urls, is_vulnerable=False)
143138
bulk_create_vuln_pkg_refs.update(inew_refs.union(rnew_refs))
144139

140+
# FIXME: _create_pkg_vuln_refs handles conflicts between the data we encounter via
141+
# updated_advisories() and the data which already exists in the DB. It is not designed
142+
# to handle the conflicting data present within the entries of updated_advisories() itself.
143+
# This can be done by filtering bulk_create_vuln_pkg_refs for pairs (vulnerability, package)
144+
# occurring more than once. Also update the constraints in the models after this is fixed.
145145
models.VulnerabilityReference.objects.bulk_create(
146146
[i.to_model_object() for i in bulk_create_vuln_refs])
147147
models.PackageRelatedVulnerability.objects.bulk_create(
@@ -170,63 +170,68 @@ def _create_vulnerability_and_references(advisory: Advisory):
170170
vuln_references = set()
171171

172172
if vuln_created:
173-
# This means vulnerability didn't previously exist in the db, so bulk create
174-
# is used without any hesitation
175-
for id_ in set(advisory.reference_ids):
176-
vuln_references.add(VulnerabilityReference_inserter(
177-
vulnerability=vuln, reference_id=id_))
173+
# This means vulnerability didn't previously exist in the DB, so add
174+
# the references to bulk create queue without any hesitation
175+
for id_ in advisory.reference_ids:
176+
vuln_references.add(VulnerabilityReferenceInserter(vulnerability=vuln, reference_id=id_)) # nopep8
178177

179-
for url in set(advisory.reference_urls):
180-
vuln_references.add(VulnerabilityReference_inserter(
181-
vulnerability=vuln, url=url))
178+
for url in advisory.reference_urls:
179+
vuln_references.add(VulnerabilityReferenceInserter(vulnerability=vuln, url=url))
182180

183181
else:
184-
vuln_refs_qs = models.VulnerabilityReference.objects.filter(
185-
vulnerability=vuln)
182+
vuln_refs_qs = models.VulnerabilityReference.objects.filter(vulnerability=vuln)
186183
vuln_ids = {ref.reference_id for ref in vuln_refs_qs}
187184
vuln_urls = {ref.url for ref in vuln_refs_qs}
188185

189186
for id_ in advisory.reference_ids:
190187
# Add the item preventing duplicates pass to through.
191188
if id_ not in vuln_ids:
192189
vuln_ids.add(id_)
193-
vuln_references.add(VulnerabilityReference_inserter(
190+
vuln_references.add(VulnerabilityReferenceInserter(
194191
vulnerability=vuln, reference_id=id_))
195192

196193
for url in advisory.reference_urls:
197194
# Add the item preventing duplicates pass to through.
198195
if url not in vuln_urls:
199196
vuln_urls.add(url)
200-
vuln_references.add(VulnerabilityReference_inserter(
197+
vuln_references.add(VulnerabilityReferenceInserter(
201198
vulnerability=vuln, url=url))
202199

203200
return vuln, vuln_created, vuln_references
204201

205202

206203
def _create_pkg_vuln_refs(vuln: models.Vulnerability, vuln_created: bool, purls: Sequence[PackageURL], is_vulnerable: bool): # nopep8
207-
new_refs, updated_refs = set(), set()
204+
new_refs = set()
208205
for purl in purls:
209206
pkg, pkg_created = _get_or_create_package(purl)
210-
vuln_pkg_ref = PackageRelatedVulnerability_inserter(
211-
package=pkg, vulnerability=vuln, is_vulnerable=is_vulnerable)
207+
vuln_pkg_ref = PackageRelatedVulnerabilityInserter(
208+
package=pkg, vulnerability=vuln, is_vulnerable=is_vulnerable)
209+
212210
if pkg_created or vuln_created:
213211
new_refs.add(vuln_pkg_ref)
214212

215213
else:
216-
qs = models.PackageRelatedVulnerability.objects.filter(
214+
existing_pkg_vuln_refs = models.PackageRelatedVulnerability.objects.filter(
217215
package=pkg, vulnerability=vuln)
218-
if not qs:
216+
if not existing_pkg_vuln_refs:
219217
new_refs.add(vuln_pkg_ref)
220218
else:
221219
# Note: PackageRelatedVulnerability has constraints
222220
# unique_together = ('package', 'vulnerability', 'is_vulnerable')
223-
# This fact is used below.
224-
vuln_impact = {i.is_vulnerable for i in qs}
225-
if len(vuln_impact) == 2 or is_vulnerable not in vuln_impact:
226-
conflicts = [i for i in qs]
221+
vuln_impact = {i.is_vulnerable for i in existing_pkg_vuln_refs}
222+
# is_vulnerable is a boolean which indicates the relationship of
223+
# a vulnerability's impact on a package. vuln_impact is a set of
224+
# all such booleans for a pair of (vulnerability, package). In cases
225+
# where vuln_impact == {True, False}, we know that conflicting relationships
226+
# of (vulnerability, package) ALREADY EXIST in the DB.
227+
# The other check `is_vulnerable not in vuln_impact` is used to know whether the
228+
# data we just found is not conflicting with the data already existing in DB.
229+
# In any of the above two cases we move the entries involved in ImportProblem
230+
if vuln_impact == {True, False} or is_vulnerable not in vuln_impact:
231+
conflicts = existing_pkg_vuln_refs[:]
227232
conflicts.append(vuln_pkg_ref.to_model_object())
228233
handle_conflicts(conflicts)
229-
qs.delete()
234+
existing_pkg_vuln_refs.delete()
230235

231236
return new_refs
232237

@@ -278,28 +283,32 @@ def _get_or_create_package(p: PackageURL) -> Tuple[models.Package, bool]:
278283

279284

280285
def _bulk_insert_packages(
281-
impacted: List[PackageURL],
282-
resolved: List[PackageURL]
283-
) -> Tuple[Dict[PackageURL, int], Dict[PackageURL, int]]:
286+
impacted: Set[PackageURL],
287+
resolved: Set[PackageURL]
288+
) -> Tuple[Dict[PackageURL, models.Package], Dict[PackageURL, models.Package]]:
289+
290+
packages = [_package_url_to_package(p) for p in impacted.union(resolved)]
291+
packages = models.Package.objects.bulk_create(packages)
292+
293+
impacted_packages, resolved_packages = {}, {}
284294

285-
impacted_packages = models.Package.objects.bulk_create(
286-
[_package_url_to_package(p) for p in impacted])
287-
resolved_packages = models.Package.objects.bulk_create(
288-
[_package_url_to_package(p) for p in resolved])
295+
for pkg in packages:
296+
# Unfortunately, PackageURLMixin.package_url returns a string, not a PackageURL
297+
purl = PackageURL.from_string(pkg.package_url)
289298

290-
impacted_packages = dict(
291-
zip(impacted, [pkg.id for pkg in impacted_packages]))
292-
resolved_packages = dict(
293-
zip(resolved, [pkg.id for pkg in resolved_packages]))
299+
if purl in impacted:
300+
impacted_packages[purl] = pkg
301+
elif purl in resolved:
302+
resolved_packages[purl] = pkg
294303

295304
return impacted_packages, resolved_packages
296305

297306

298307
def _bulk_insert_impacted_and_resolved_packages(
299308
batch: Set[Advisory],
300309
vulnerabilities: Set[models.Vulnerability],
301-
impacted_packages: Dict[PackageURL, int],
302-
resolved_packages: Dict[PackageURL, int],
310+
impacted_packages: Dict[PackageURL, models.Package],
311+
resolved_packages: Dict[PackageURL, models.Package],
303312
) -> None:
304313

305314
refs: List[models.ImpactedPackage] = []
@@ -313,11 +322,11 @@ def _bulk_insert_impacted_and_resolved_packages(
313322
if not p:
314323
p = _package_url_to_package(impacted_purl)
315324
p.save()
316-
impacted_packages[impacted_purl] = p.id
325+
impacted_packages[impacted_purl] = p
317326

318327
ip = models.PackageRelatedVulnerability(
319328
vulnerability=vuln,
320-
package_id=p,
329+
package=p,
321330
is_vulnerable=True
322331
)
323332
refs.append(ip)
@@ -328,11 +337,11 @@ def _bulk_insert_impacted_and_resolved_packages(
328337
if not p:
329338
p = _package_url_to_package(resolved_purl)
330339
p.save()
331-
resolved_packages[resolved_purl] = p.id
340+
resolved_packages[resolved_purl] = p
332341

333342
ip = models.PackageRelatedVulnerability(
334343
vulnerability=vuln,
335-
package_id=p,
344+
package=p,
336345
is_vulnerable=False
337346
)
338347
refs.append(ip)
@@ -390,12 +399,12 @@ def _advisory_to_vulnerability(
390399
raise RuntimeError(f'No Vulnerability model object found for this Advisory: {advisory.summary}')
391400

392401

393-
def _collect_package_urls(batch: Set[Advisory]) -> Tuple[List[PackageURL], List[PackageURL]]:
394-
impacted, resolved = [], []
402+
def _collect_package_urls(batch: Set[Advisory]) -> Tuple[Set[PackageURL], Set[PackageURL]]:
403+
impacted, resolved = set(), set()
395404

396405
for advisory in batch:
397-
impacted.extend(advisory.impacted_package_urls)
398-
resolved.extend(advisory.resolved_package_urls)
406+
impacted.update(advisory.impacted_package_urls)
407+
resolved.update(advisory.resolved_package_urls)
399408

400409
return impacted, resolved
401410

0 commit comments

Comments
 (0)