Skip to content

Commit 39b28fb

Browse files
committed
Fix tests
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent a74589b commit 39b28fb

8 files changed

Lines changed: 547 additions & 151 deletions

File tree

vulnerabilities/migrations/0135_remove_advisoryv2_advisory_latest_by_avid_idx_and_more.py renamed to vulnerabilities/migrations/0135_advisoryv2__all_impacts_unfurled_successfully_and_more.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 5.2.11 on 2026-06-03 08:00
1+
# Generated by Django 5.2.11 on 2026-06-03 12:46
22

33
from django.db import migrations, models
44

@@ -10,9 +10,13 @@ class Migration(migrations.Migration):
1010
]
1111

1212
operations = [
13-
migrations.RemoveIndex(
13+
migrations.AddField(
1414
model_name="advisoryv2",
15-
name="advisory_latest_by_avid_idx",
15+
name="_all_impacts_unfurled_successfully",
16+
field=models.BooleanField(
17+
default=False,
18+
help_text="Indicates whether all impacts for this advisory have been unfurled successfully.",
19+
),
1620
),
1721
migrations.AddIndex(
1822
model_name="advisoryv2",

vulnerabilities/models.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3258,6 +3258,11 @@ class AdvisoryV2(models.Model):
32583258
help_text="Indicates whether all impacts for this advisory have been unfurled.",
32593259
)
32603260

3261+
_all_impacts_unfurled_successfully = models.BooleanField(
3262+
default=False,
3263+
help_text="Indicates whether all impacts for this advisory have been unfurled successfully.",
3264+
)
3265+
32613266
objects = AdvisoryV2QuerySet.as_manager()
32623267

32633268
class Meta:
@@ -3272,9 +3277,7 @@ class Meta:
32723277
models.Index(
32733278
fields=["avid", "-date_collected", "-id"],
32743279
name="advisory_latest_by_avid_idx",
3275-
)
3276-
]
3277-
indexes = [
3280+
),
32783281
models.Index(
32793282
fields=["_all_impacts_unfurled", "id"],
32803283
name="advisory_unfurled_idx",

vulnerabilities/pipelines/v2_improvers/unfurl_version_range.py

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@ class UnfurlVersionRangePipeline(VulnerableCodePipeline):
5151

5252
# Days elapsed before version range is re-unfurled
5353
reunfurl_after_days = 2
54+
impacted_packages = None
5455

5556
@classmethod
5657
def steps(cls):
57-
return (cls.unfurl_version_range, cls.mark_all_impacts_unfurled)
58+
return (
59+
cls.unfurl_version_range,
60+
cls.mark_all_impacts_unfurled_sucessfully,
61+
cls.mark_all_impacts_unfurl_attempted,
62+
)
5863

5964
def unfurl_version_range(self):
6065
processed_impacted_packages_count = 0
@@ -66,6 +71,7 @@ def unfurl_version_range(self):
6671
chunk_size = 500
6772

6873
impacted_packages = impacted_package_qs(cutoff_day=self.reunfurl_after_days)
74+
self.impacted_packages = impacted_packages
6975
impacted_packages_count = impacted_packages.count()
7076
self.log(f"Unfurl affected vers range for {impacted_packages_count:,d} ImpactedPackage.")
7177

@@ -104,32 +110,67 @@ def unfurl_version_range(self):
104110
processed_impacted_packages_count += 1
105111

106112
if len(update_unfurl_date) > update_batch_size:
113+
cur_time = timezone.now()
107114
ImpactedPackage.objects.filter(pk__in=update_unfurl_date).update(
108-
last_range_unfurl_at=timezone.now()
115+
last_range_unfurl_at=cur_time
109116
)
110117
ImpactedPackage.objects.filter(pk__in=update_successful_unfurl_date).update(
111-
last_successful_range_unfurl_at=timezone.now()
118+
last_successful_range_unfurl_at=cur_time
112119
)
113120
update_unfurl_date.clear()
114121
update_successful_unfurl_date.clear()
115122

123+
cur_time = timezone.now()
124+
116125
ImpactedPackage.objects.filter(pk__in=update_unfurl_date).update(
117-
last_range_unfurl_at=timezone.now()
126+
last_range_unfurl_at=cur_time
118127
)
119128
ImpactedPackage.objects.filter(pk__in=update_successful_unfurl_date).update(
120-
last_successful_range_unfurl_at=timezone.now()
129+
last_successful_range_unfurl_at=cur_time
121130
)
122131
self.log(f"Successfully processed {processed_impacted_packages_count:,d} ImpactedPackage.")
123132
self.log(f"{processed_affected_packages_count:,d} new Impact-Package relation created.")
124133

125-
def mark_all_impacts_unfurled(self):
134+
def mark_all_impacts_unfurled_sucessfully(self):
135+
impacted_packages = self.impacted_packages or impacted_package_qs(
136+
cutoff_day=self.reunfurl_after_days
137+
)
126138
while True:
127-
advisories = list(latest_advisories_with_all_impacts_unfurled()[:100])
139+
advisory_ids = list(
140+
latest_advisories_with_all_impacts_unfurled_successfully(
141+
impacted_packages=impacted_packages
142+
)[:100]
143+
)
128144

129-
if not advisories:
145+
if not advisory_ids:
130146
break
131147

132-
complete_advisories_import(AdvisoryV2.objects.filter(id__in=[a.id for a in advisories]))
148+
complete_advisories_import(advisory_ids=advisory_ids, success=True)
149+
150+
def mark_all_impacts_unfurl_attempted(self):
151+
impacted_packages = self.impacted_packages or impacted_package_qs(
152+
cutoff_day=self.reunfurl_after_days
153+
)
154+
advisories_qs = latest_advisories_with_all_impacts_unfurled_attempted(
155+
impacted_packages=impacted_packages
156+
)
157+
158+
batch_size = 100
159+
batch = []
160+
161+
for advisory_id in advisories_qs.iterator(chunk_size=100):
162+
batch.append(advisory_id)
163+
164+
if len(batch) >= batch_size:
165+
complete_advisories_import(
166+
advisory_ids=list(batch),
167+
)
168+
batch.clear()
169+
170+
if batch:
171+
complete_advisories_import(
172+
advisory_ids=list(batch),
173+
)
133174

134175

135176
def get_affected_purls(versions, impact, logger):
@@ -219,15 +260,17 @@ def impacted_package_qs(cutoff_day=2):
219260

220261

221262
@transaction.atomic
222-
def complete_advisories_import(advisories):
223-
224-
advisory_ids = list(advisories.values_list("id", flat=True))
225-
263+
def complete_advisories_import(advisory_ids, success=False):
226264
if not advisory_ids:
227265
return
228266

229267
AdvisoryV2.objects.filter(id__in=advisory_ids).update(_all_impacts_unfurled=True)
230268

269+
if success:
270+
AdvisoryV2.objects.filter(id__in=advisory_ids).update(
271+
_all_impacts_unfurled_successfully=True
272+
)
273+
231274
affecting_package_ids = set(
232275
ImpactedPackageAffecting.objects.filter(
233276
impacted_package__advisory_id__in=advisory_ids
@@ -256,16 +299,42 @@ def complete_advisories_import(advisories):
256299
group_advisory_for_package(package)
257300

258301

259-
def latest_advisories_with_all_impacts_unfurled():
260-
remaining_unfurled_impacts = ImpactedPackage.objects.filter(
302+
def latest_advisories_with_all_impacts_unfurled_successfully(
303+
impacted_packages=None,
304+
):
305+
unsuccessful_impacts = impacted_packages.filter(
306+
advisory_id=OuterRef("pk"),
307+
advisory__is_latest=True,
308+
).filter(Q(last_range_unfurl_at__isnull=True) | Q(last_successful_range_unfurl_at__isnull=True))
309+
310+
return (
311+
AdvisoryV2.objects.filter(
312+
_all_impacts_unfurled_successfully=False,
313+
is_latest=True,
314+
)
315+
.annotate(has_unsuccessful_impacts=Exists(unsuccessful_impacts))
316+
.filter(has_unsuccessful_impacts=False)
317+
.order_by("id")
318+
.values_list("id", flat=True)
319+
)
320+
321+
322+
def latest_advisories_with_all_impacts_unfurled_attempted(
323+
impacted_packages=None,
324+
):
325+
impacts_not_attempted = impacted_packages.filter(
261326
advisory_id=OuterRef("pk"),
262-
last_range_unfurl_at__isnull=True,
263327
advisory__is_latest=True,
328+
last_range_unfurl_at__isnull=True,
264329
)
265330

266331
return (
267-
AdvisoryV2.objects.filter(_all_impacts_unfurled=False, is_latest=True)
268-
.annotate(has_remaining_unfurled=Exists(remaining_unfurled_impacts))
269-
.filter(has_remaining_unfurled=False)
332+
AdvisoryV2.objects.filter(
333+
_all_impacts_unfurled_successfully=False,
334+
is_latest=True,
335+
)
336+
.annotate(has_unattempted_impacts=Exists(impacts_not_attempted))
337+
.filter(has_unattempted_impacts=False)
270338
.order_by("id")
339+
.values_list("id", flat=True)
271340
)

vulnerabilities/pipes/advisory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ def insert_advisory_v2(
371371
advisory_obj.risk_score = round(risk_score, 1) if risk_score is not None else None
372372
if not advisory.affected_packages:
373373
advisory_obj._all_impacts_unfurled = True
374+
advisory_obj._all_impacts_unfurled_successfully = True
374375
advisory_obj.save()
375376

376377
for affected_pkg in advisory.affected_packages:

vulnerabilities/tests/pipelines/exporters/test_federate_vulnerabilities.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,25 @@ def setUp(self):
8383
date_published=datetime.now() - timedelta(days=10),
8484
url="https://example.com/advisory/2",
8585
)
86-
insert_advisory_v2(
86+
a1 = insert_advisory_v2(
8787
advisory=advisory1,
8888
pipeline_id="test_pipeline_v2",
8989
logger=self.logger.write,
9090
datasource_id="test",
9191
)
92-
insert_advisory_v2(
92+
a1._all_impacts_unfurled = True
93+
a1._all_impacts_unfurled_successfully = True
94+
a1.save()
95+
a2 = insert_advisory_v2(
9396
advisory=advisory2,
9497
pipeline_id="test_pipeline_v2",
9598
logger=self.logger.write,
9699
datasource_id="test",
97100
)
101+
a2._all_impacts_unfurled = True
102+
a2._all_impacts_unfurled_successfully = True
103+
a2.save()
104+
98105

99106
@patch(
100107
"vulnerabilities.pipelines.exporters.federate_vulnerabilities.FederatePackageVulnerabilities.clone_federation_repository"

vulnerabilities/tests/pipelines/v2_improvers/test_compute_package_risk_v2.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def test_simple_risk_pipeline():
3636
url="https://test.com",
3737
date_collected=datetime.now(),
3838
is_latest=True,
39+
_all_impacts_unfurled=True
3940
)
4041
adv.save()
4142

0 commit comments

Comments
 (0)