Skip to content

Commit 2e18e6f

Browse files
committed
Speed up import process
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 7abc825 commit 2e18e6f

4 files changed

Lines changed: 74 additions & 46 deletions

File tree

vulnerabilities/pipelines/v2_improvers/compute_package_risk.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from vulnerabilities.models import AdvisoryV2
1717
from vulnerabilities.models import PackageV2
1818
from vulnerabilities.pipelines import VulnerableCodePipeline
19+
from vulnerabilities.pipes.risk_score import bulk_update
1920
from vulnerabilities.risk import compute_vulnerability_risk_factors
2021

2122

@@ -178,14 +179,3 @@ def compute_and_store_package_risk_score(self):
178179
)
179180
self.log(f"Successfully added risk score for {updated:,d} package")
180181

181-
182-
def bulk_update(model, items, fields, logger):
183-
item_count = 0
184-
if items:
185-
try:
186-
model.objects.bulk_update(objs=items, fields=fields)
187-
item_count += len(items)
188-
except Exception as e:
189-
logger(f"Error updating {model.__name__}: {e}")
190-
items.clear()
191-
return item_count

vulnerabilities/pipes/advisory.py

Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
from vulnerabilities.models import VulnerabilitySeverity
4949
from vulnerabilities.models import Weakness
5050
from vulnerabilities.pipes.group_advisories import group_advisory_for_package
51-
from vulnerabilities.pipes.risk_score import compute_advisory_risk_score
51+
from vulnerabilities.pipes.risk_score import compute_advisory_risk_score, compute_package_risk_score_bulk
5252
from vulnerabilities.pipes.risk_score import compute_package_risk_score
5353
from vulnerabilities.pipes.univers_utils import get_exact_purls_v2
5454

@@ -300,6 +300,7 @@ def insert_advisory_v2(
300300
):
301301
from vulnerabilities.models import ImpactedPackage
302302
from vulnerabilities.models import PackageV2
303+
from vulnerabilities.utils import TYPES_WITH_MULTIPLE_IMPORTERS
303304
from vulnerabilities.utils import compute_content_id_v2
304305

305306
advisory_obj = None
@@ -398,9 +399,19 @@ def insert_advisory_v2(
398399
purls=package_fixed_purls
399400
)
400401

401-
add_packages_to_advisory(
402-
logger, advisory_obj, impact, affected_packages_v2, fixed_packages_v2
403-
)
402+
if affected_pkg.package.type in TYPES_WITH_MULTIPLE_IMPORTERS:
403+
group_advisories_for_package_with_lock(
404+
advisory_obj, impact, affected_packages_v2, fixed_packages_v2, logger=logger
405+
)
406+
else:
407+
impact.affecting_packages.add(*affected_packages_v2)
408+
impact.fixed_by_packages.add(*fixed_packages_v2)
409+
410+
compute_package_risk_score_bulk(affected_packages_v2)
411+
if affected_packages_v2:
412+
affected_packages_v2[0].calculate_version_rank
413+
elif fixed_packages_v2:
414+
fixed_packages_v2[0].calculate_version_rank
404415

405416
introduced_commit_v2 = get_or_create_advisory_package_commit_patches(
406417
affected_pkg.introduced_by_commit_patches
@@ -414,7 +425,9 @@ def insert_advisory_v2(
414425

415426

416427
@transaction.atomic
417-
def add_packages_to_advisory(logger, advisory_obj, impact, affected_packages_v2, fixed_packages_v2):
428+
def group_advisories_for_package_with_lock(
429+
advisory_obj, impact, affected_packages_v2, fixed_packages_v2, logger=print
430+
):
418431
from vulnerabilities.models import PackageV2
419432

420433
all_packages = sorted(
@@ -453,35 +466,6 @@ def add_packages_to_advisory(logger, advisory_obj, impact, affected_packages_v2,
453466
f"Failed to group advisories for package {pkg.purl}: {e!r} \n {traceback_format_exc()}",
454467
level=logging.ERROR,
455468
)
456-
try:
457-
risk_score = compute_package_risk_score(
458-
pkg, current_advisory_risk_score=advisory_obj.risk_score
459-
)
460-
logger(f"Computed risk score {risk_score} for package {pkg.purl}")
461-
pkg.risk_score = risk_score
462-
pkg.save()
463-
pkg.calculate_version_rank
464-
except Exception as e:
465-
logger(
466-
f"Failed to compute risk score for package {pkg.purl}: {e!r} \n {traceback_format_exc()}",
467-
level=logging.ERROR,
468-
)
469-
470-
for pkg in list(fixed_packages_v2):
471-
logger(f"Grouping advisories for package: {pkg.purl}")
472-
try:
473-
group_advisory_for_package(
474-
pkg,
475-
logger=logger,
476-
current_advisory=advisory_obj,
477-
current_advisory_relation="fixing",
478-
)
479-
except Exception as e:
480-
logger(
481-
f"Failed to group advisories for package {pkg.purl}: {e!r} \n {traceback_format_exc()}",
482-
level=logging.ERROR,
483-
)
484-
pkg.calculate_version_rank
485469

486470

487471
@transaction.atomic

vulnerabilities/pipes/risk_score.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.db.models import Max
1414

1515
from vulnerabilities.models import AdvisoryV2
16+
from vulnerabilities.models import PackageV2
1617

1718

1819
def quantize_1(value):
@@ -40,6 +41,47 @@ def compute_package_risk_score(package, current_advisory_risk_score=None):
4041
return round(float(max_risk), 1)
4142

4243

44+
def compute_package_risk_score_bulk(packages):
45+
"""Calculate the risk score for a single PackageV2 object."""
46+
purls = packages.values_list("package_url", flat=True)
47+
advisories = AdvisoryV2.objects.latest_affecting_advisories_for_purls(purls).only(
48+
"id", "risk_score"
49+
)
50+
qs = (
51+
PackageV2.objects.filter(
52+
id__in=packages.values_list("id", flat=True),
53+
affected_in_impacts__advisory__risk_score__isnull=False,
54+
affected_in_impacts__advisory__in=advisories,
55+
)
56+
.distinct()
57+
.annotate(computed_risk=Max("affected_in_impacts__advisory__risk_score"))
58+
.only("id")
59+
)
60+
61+
batch = []
62+
batch_size = 5000
63+
updated = 0
64+
65+
for pkg in qs.iterator(chunk_size=batch_size):
66+
pkg.risk_score = round(float(pkg.computed_risk), 1)
67+
batch.append(pkg)
68+
69+
if len(batch) >= batch_size:
70+
updated += bulk_update(
71+
model=PackageV2,
72+
items=batch,
73+
fields=["risk_score"],
74+
)
75+
batch.clear()
76+
77+
updated += bulk_update(
78+
model=PackageV2,
79+
items=batch,
80+
fields=["risk_score"],
81+
)
82+
83+
84+
4385
def compute_advisory_risk_score(advisory):
4486
"""
4587
Calculate the risk score for a single AdvisoryV2 object.
@@ -77,3 +119,16 @@ def compute_advisory_risk_score(advisory):
77119
risk_score = None
78120

79121
return quantize_1(weighted_severity), quantize_1(exploitability), quantize_1(risk_score)
122+
123+
124+
def bulk_update(model, items, fields, logger=None):
125+
item_count = 0
126+
if items:
127+
try:
128+
model.objects.bulk_update(objs=items, fields=fields)
129+
item_count += len(items)
130+
except Exception as e:
131+
if logger:
132+
logger(f"Error updating {model.__name__}: {e}")
133+
items.clear()
134+
return item_count

vulnerabilities/views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ def get_context_data(self, **kwargs):
326326
return context
327327

328328
is_grouped = models.AdvisorySet.objects.filter(package=package).exists()
329-
print(f"Is package {package.purl} grouped? {is_grouped}")
330329

331330
if is_grouped:
332331
context["grouped"] = True

0 commit comments

Comments
 (0)