Skip to content

Commit 682436d

Browse files
authored
Merge branch 'bugfix' into tests
2 parents ab0d19a + 354e6bd commit 682436d

13 files changed

Lines changed: 315 additions & 87 deletions

File tree

dojo/api_v2/serializers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import dojo.risk_acceptance.helper as ra_helper
2929
from dojo.authorization.authorization import user_has_permission
3030
from dojo.authorization.roles_permissions import Permissions
31+
from dojo.celery_dispatch import dojo_dispatch_task
3132
from dojo.endpoint.utils import endpoint_filter, endpoint_meta_import
3233
from dojo.finding.helper import (
3334
save_endpoints_template,
@@ -116,7 +117,7 @@
116117
Vulnerability_Id,
117118
get_current_date,
118119
)
119-
from dojo.notifications.helper import create_notification
120+
from dojo.notifications.helper import async_create_notification
120121
from dojo.product_announcements import (
121122
LargeScanSizeProductAnnouncement,
122123
ScanTypeProductAnnouncement,
@@ -2086,10 +2087,11 @@ def create(self, validated_data):
20862087
jira_helper.push_to_jira(new_finding)
20872088

20882089
# Create a notification
2089-
create_notification(
2090+
dojo_dispatch_task(
2091+
async_create_notification,
20902092
event="finding_added",
20912093
title=_("Addition of %s") % new_finding.title,
2092-
finding=new_finding,
2094+
finding_id=new_finding.id,
20932095
description=_('Finding "%s" was added by %s') % (new_finding.title, new_finding.reporter),
20942096
url=reverse("view_finding", args=(new_finding.id,)),
20952097
icon="exclamation-triangle",

dojo/engagement/signals.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,30 @@
77
from django.urls import reverse
88
from django.utils.translation import gettext as _
99

10+
from dojo.celery_dispatch import dojo_dispatch_task
1011
from dojo.file_uploads.helper import delete_related_files
1112
from dojo.models import Engagement, Product
1213
from dojo.notes.helper import delete_related_notes
13-
from dojo.notifications.helper import create_notification
14+
from dojo.notifications.helper import async_create_notification, create_notification
1415
from dojo.pghistory_models import DojoEvents
1516

1617

1718
@receiver(post_save, sender=Engagement)
1819
def engagement_post_save(sender, instance, created, **kwargs):
20+
# raw=True is set by loaddata; skip dispatch so fixture loading doesn't require a live broker.
21+
if kwargs.get("raw"):
22+
return
1923
if created:
2024
title = _('Engagement created for "%(product)s": %(name)s') % {"product": instance.product, "name": instance.name}
21-
create_notification(event="engagement_added", title=title, engagement=instance, product=instance.product,
22-
url=reverse("view_engagement", args=(instance.id,)), url_api=reverse("engagement-detail", args=(instance.id,)))
25+
dojo_dispatch_task(
26+
async_create_notification,
27+
event="engagement_added",
28+
title=title,
29+
engagement_id=instance.id,
30+
product_id=instance.product_id,
31+
url=reverse("view_engagement", args=(instance.id,)),
32+
url_api=reverse("engagement-detail", args=(instance.id,)),
33+
)
2334

2435

2536
@receiver(pre_save, sender=Engagement)

dojo/importers/default_importer.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
Test,
1919
Test_Import,
2020
)
21-
from dojo.notifications.helper import create_notification
21+
from dojo.notifications.helper import async_create_notification
2222
from dojo.utils import get_full_url, perform_product_grading
2323
from dojo.validators import clean_tags
2424

@@ -140,12 +140,13 @@ def process_scan(
140140
)
141141
# Send out some notifications to the user
142142
logger.debug("IMPORT_SCAN: Generating notifications")
143-
create_notification(
143+
dojo_dispatch_task(
144+
async_create_notification,
144145
event="test_added",
145146
title=f"Test created for {self.test.engagement.product}: {self.test.engagement.name}: {self.test}",
146-
test=self.test,
147-
engagement=self.test.engagement,
148-
product=self.test.engagement.product,
147+
test_id=self.test.id,
148+
engagement_id=self.test.engagement_id,
149+
product_id=self.test.engagement.product_id,
149150
url=reverse("view_test", args=(self.test.id,)),
150151
url_api=reverse("test-detail", args=(self.test.id,)),
151152
)

dojo/metrics/views.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,10 @@ def _augment_series_with_accepted(series: list[list], ras_qs, *, period: str, tz
916916
)
917917

918918
for row in accepted:
919-
bucket[sev_idx[row["severity"]]] += row["cnt"]
919+
sev = row["severity"]
920+
if sev not in sev_idx:
921+
continue
922+
bucket[sev_idx[sev]] += row["cnt"]
920923

921924
bucket[5] = sum(bucket[1:])
922925

dojo/notifications/helper.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,67 @@ def send_webhooks_notification(event: str, user_id: int | None = None, **kwargs:
911911
get_manager_class_instance()._get_manager_instance("webhooks").send_webhooks_notification(event, user=user, **kwargs)
912912

913913

914+
@app.task
915+
def async_create_notification(
916+
event: str,
917+
engagement_id: int | None = None,
918+
product_id: int | None = None,
919+
product_type_id: int | None = None,
920+
finding_id: int | None = None,
921+
test_id: int | None = None,
922+
**kwargs: dict,
923+
) -> None:
924+
# Re-fetch by id so the recipient-enumeration query and per-user Alert writes
925+
# run in the worker rather than the request thread.
926+
# Fetch most-specific first and derive parent objects from the already-loaded
927+
# select_related chain to avoid redundant queries. For example, fetching a
928+
# Test with select_related("engagement__product") covers all three objects in
929+
# one query, so engagement_id and product_id don't need separate fetches.
930+
fetched_engagement = None
931+
fetched_product = None
932+
933+
if test_id is not None:
934+
test = Test.objects.filter(pk=test_id).select_related("engagement__product").first()
935+
if test is None:
936+
return
937+
kwargs["test"] = test
938+
fetched_engagement = test.engagement
939+
fetched_product = test.engagement.product
940+
941+
if engagement_id is not None:
942+
if fetched_engagement is not None:
943+
kwargs["engagement"] = fetched_engagement
944+
else:
945+
engagement = Engagement.objects.filter(pk=engagement_id).select_related("product").first()
946+
if engagement is None:
947+
return
948+
kwargs["engagement"] = engagement
949+
fetched_product = engagement.product
950+
951+
if product_id is not None:
952+
if fetched_product is not None:
953+
kwargs["product"] = fetched_product
954+
else:
955+
product = Product.objects.filter(pk=product_id).first()
956+
if product is None:
957+
return
958+
kwargs["product"] = product
959+
960+
if product_type_id is not None:
961+
product_type = Product_Type.objects.filter(pk=product_type_id).first()
962+
if product_type is None:
963+
return
964+
kwargs["product_type"] = product_type
965+
966+
if finding_id is not None:
967+
finding = Finding.objects.filter(pk=finding_id).select_related("test__engagement__product").first()
968+
if finding is None:
969+
return
970+
kwargs["finding"] = finding
971+
972+
create_notification(event=event, **kwargs)
973+
974+
914975
@app.task(ignore_result=True)
915976
def webhook_reactivation(endpoint_id: int, **_kwargs: dict) -> None:
916977
get_manager_class_instance()._get_manager_instance("webhooks")._webhook_reactivation(endpoint_id=endpoint_id)

dojo/product/signals.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
from django.urls import reverse
88
from django.utils.translation import gettext as _
99

10+
from dojo.celery_dispatch import dojo_dispatch_task
1011
from dojo.labels import get_labels
1112
from dojo.models import Product
12-
from dojo.notifications.helper import create_notification
13+
from dojo.notifications.helper import async_create_notification, create_notification
1314
from dojo.pghistory_models import DojoEvents
1415
from dojo.utils import get_current_user
1516

@@ -18,13 +19,18 @@
1819

1920
@receiver(post_save, sender=Product)
2021
def product_post_save(sender, instance, created, **kwargs):
22+
# raw=True is set by loaddata; skip dispatch so fixture loading doesn't require a live broker.
23+
if kwargs.get("raw"):
24+
return
2125
if created:
22-
create_notification(event="product_added",
23-
title=instance.name,
24-
product=instance,
25-
url=reverse("view_product", args=(instance.id,)),
26-
url_api=reverse("product-detail", args=(instance.id,)),
27-
)
26+
dojo_dispatch_task(
27+
async_create_notification,
28+
event="product_added",
29+
title=instance.name,
30+
product_id=instance.id,
31+
url=reverse("view_product", args=(instance.id,)),
32+
url_api=reverse("product-detail", args=(instance.id,)),
33+
)
2834

2935

3036
@receiver(post_delete, sender=Product)

dojo/product_type/signals.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,29 @@
88
from django.urls import reverse
99
from django.utils.translation import gettext as _
1010

11+
from dojo.celery_dispatch import dojo_dispatch_task
1112
from dojo.labels import get_labels
1213
from dojo.models import Product_Type
13-
from dojo.notifications.helper import create_notification
14+
from dojo.notifications.helper import async_create_notification, create_notification
1415
from dojo.pghistory_models import DojoEvents
1516

1617
labels = get_labels()
1718

1819

1920
@receiver(post_save, sender=Product_Type)
2021
def product_type_post_save(sender, instance, created, **kwargs):
22+
# raw=True is set by loaddata; skip dispatch so fixture loading doesn't require a live broker.
23+
if kwargs.get("raw"):
24+
return
2125
if created:
22-
create_notification(event="product_type_added",
23-
title=instance.name,
24-
product_type=instance,
25-
url=reverse("view_product_type", args=(instance.id,)),
26-
url_api=reverse("product_type-detail", args=(instance.id,)),
27-
)
26+
dojo_dispatch_task(
27+
async_create_notification,
28+
event="product_type_added",
29+
title=instance.name,
30+
product_type_id=instance.id,
31+
url=reverse("view_product_type", args=(instance.id,)),
32+
url_api=reverse("product_type-detail", args=(instance.id,)),
33+
)
2834

2935

3036
@receiver(post_delete, sender=Product_Type)

dojo/templates/notifications/mail/sla_breach.tpl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
{% if sla_age < 0 %}
1515
{% blocktranslate trimmed %}
1616
This security finding has breached its SLA.
17-
18-
- Day(s) overdue: {{sla}}
17+
<br/>
18+
- Day(s) overdue: {{sla_age}}
1919
{% endblocktranslate %}
2020
{% else %}
2121
{% blocktranslate trimmed %}
2222
A security finding is about to breach its SLA.
23-
24-
- Day(s) remaining: {{sla}}
23+
<br/>
24+
- Day(s) remaining: {{sla_age}}
2525
{% endblocktranslate %}
2626
{% endif %}
2727
</p>

dojo/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,12 +1576,13 @@ def _create_notifications():
15761576
findings_list = []
15771577

15781578
for n in comb_notif_kind:
1579-
title = _notification_title_for_finding(n.finding, kind, n.finding.sla_days_remaining())
1580-
1579+
sla_age = n.finding.sla_days_remaining()
1580+
title = _notification_title_for_finding(n.finding, kind, sla_age)
15811581
create_notification(
15821582
event="sla_breach",
15831583
title=title,
15841584
finding=n.finding,
1585+
sla_age=sla_age,
15851586
url=reverse("view_finding", args=(n.finding.id,)),
15861587
)
15871588

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ whitenoise==5.2.0
4343
titlecase==2.4.1
4444
social-auth-app-django==5.6.0
4545
social-auth-core==4.8.5
46-
gitpython==3.1.46
46+
gitpython==3.1.47
4747
python-gitlab==8.2.0
4848
cpe==1.3.1
4949
packageurl-python==0.17.6

0 commit comments

Comments
 (0)