Skip to content

Commit 67900c9

Browse files
committed
Merge branch 'dev' into locations
2 parents 4156ba1 + f844d2c commit 67900c9

45 files changed

Lines changed: 2174 additions & 754 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docker-compose.override.dev.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ services:
1616
DD_ADMIN_PASSWORD: "${DD_ADMIN_PASSWORD:-admin}"
1717
DD_EMAIL_URL: "smtp://mailhog:1025"
1818
celeryworker:
19+
build:
20+
context: .
21+
dockerfile: Dockerfile.django-${DEFECT_DOJO_OS:-debian}
22+
target: development
1923
entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST:-postgres}:${DD_DATABASE_PORT:-5432}', '-t', '30', '--', '/entrypoint-celery-worker-dev.sh']
2024
volumes:
2125
- '.:/app:z'
@@ -24,12 +28,20 @@ services:
2428
DD_DEBUG: 'True'
2529
DD_EMAIL_URL: "smtp://mailhog:1025"
2630
celerybeat:
31+
build:
32+
context: .
33+
dockerfile: Dockerfile.django-${DEFECT_DOJO_OS:-debian}
34+
target: development
2735
volumes:
2836
- '.:/app:z'
2937
environment:
3038
PYTHONWARNINGS: error # We are strict about Warnings during development
3139
DD_DEBUG: 'True'
3240
initializer:
41+
build:
42+
context: .
43+
dockerfile: Dockerfile.django-${DEFECT_DOJO_OS:-debian}
44+
target: development
3345
volumes:
3446
- '.:/app:z'
3547
environment:

docs/content/en/changelog/changelog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ For Open Source release notes, please see the [Releases page on GitHub](https://
1010

1111
## Jan 2025: v2.54
1212

13+
### Jan 20, 2025: v2.54.2
14+
15+
* **(Pro UI)** corrected a bug where unordered lists would display as ordered lists in editor forms.
16+
* **(Smart Upload)** introduced severity filtering to the Smart Importer to skip findings below a specified severity level. Added detailed logging throughout the findings processing to improve traceability and debugging.
17+
18+
### Jan 12, 2025: v2.54.1
19+
20+
* **(AI Tools)** added Risk Scores to schema for MCP processing.
21+
1322
### Jan 5, 2025: v2.54.0
1423

1524
No significant UX changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: 'Upgrading to DefectDojo Version 2.54.3'
3+
toc_hide: true
4+
weight: -20250602
5+
description: Trivy parser deduplication
6+
---
7+
8+
## Trivy parser deduplication
9+
Deduplication of Trivy misconfiguration findings is improved for newly imported findings, but existing findings may no longer match because they don’t contain the new vulnerability_id or file_path fields.

docs/content/en/open_source/upgrading/2.55.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
title: 'Upgrading to DefectDojo Version 2.55.x'
33
toc_hide: true
44
weight: -20260105
5-
description: No special instructions.
5+
description: Authorization related optimizations
66
---
7-
There are no special instructions for upgrading to 2.55.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.55.0) for the contents of the release.
7+
8+
## Authorization related optimizations
9+
10+
The queries related to authorizations have been optmized. For example retrieving the list of authorized findings for the logged in user.
11+
Some of these are now also cached during that duration of a request. This should have no functional effects and only results in better performance.
12+
13+
Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.55.0) for the contents of the release.

docs/package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
"@docsearch/js": "4.5.3",
2121
"@tabler/icons": "3.36.1",
2222
"@thulite/doks-core": "1.8.3",
23-
"@thulite/images": "3.3.3",
24-
"@thulite/inline-svg": "1.2.1",
23+
"@thulite/images": "3.3.4",
24+
"@thulite/inline-svg": "1.2.2",
2525
"@thulite/seo": "2.4.2",
2626
"thulite": "2.6.4"
2727
},

dojo/auditlog.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,16 @@ def process_model_backfill(
805805
"""
806806
if progress_callback is None:
807807
def progress_callback(msg, style=None):
808-
logger.info(msg)
808+
if style == "ERROR":
809+
logger.error(msg)
810+
elif style == "WARNING":
811+
logger.warning(msg)
812+
elif style == "SUCCESS":
813+
logger.info(msg)
814+
elif style == "DEBUG":
815+
logger.debug(msg)
816+
else:
817+
logger.info(msg)
809818

810819
try:
811820
table_name, event_table_name = get_table_names(model_name)
@@ -821,7 +830,7 @@ def progress_callback(msg, style=None):
821830
progress_callback(
822831
f" Event table {event_table_name} not found. "
823832
f"Is {model_name} tracked by pghistory?",
824-
"ERROR",
833+
"DEBUG",
825834
)
826835
return 0, 0.0
827836

dojo/cred/queries.py

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
from crum import get_current_user
2-
from django.db.models import Exists, OuterRef, Q
2+
from django.db.models import Q, Subquery
33

44
from dojo.authorization.authorization import get_roles_for_permission, user_has_global_permission
55
from dojo.models import Cred_Mapping, Product_Group, Product_Member, Product_Type_Group, Product_Type_Member
6+
from dojo.request_cache import cache_for_request
67

78

8-
def get_authorized_cred_mappings(permission, queryset=None):
9+
# Cached: all parameters are hashable, no dynamic queryset filtering
10+
@cache_for_request
11+
def get_authorized_cred_mappings(permission):
12+
"""Cached - returns all cred mappings the user is authorized to see."""
913
user = get_current_user()
1014

1115
if user is None:
1216
return Cred_Mapping.objects.none()
1317

14-
cred_mappings = Cred_Mapping.objects.all().order_by("id") if queryset is None else queryset
18+
cred_mappings = Cred_Mapping.objects.all().order_by("id")
1519

1620
if user.is_superuser:
1721
return cred_mappings
@@ -20,27 +24,69 @@ def get_authorized_cred_mappings(permission, queryset=None):
2024
return cred_mappings
2125

2226
roles = get_roles_for_permission(permission)
27+
28+
# Get authorized product/product_type IDs via subqueries
2329
authorized_product_type_roles = Product_Type_Member.objects.filter(
24-
product_type=OuterRef("product__prod_type_id"),
25-
user=user,
26-
role__in=roles)
30+
user=user, role__in=roles,
31+
).values("product_type_id")
32+
2733
authorized_product_roles = Product_Member.objects.filter(
28-
product=OuterRef("product_id"),
29-
user=user,
30-
role__in=roles)
34+
user=user, role__in=roles,
35+
).values("product_id")
36+
3137
authorized_product_type_groups = Product_Type_Group.objects.filter(
32-
product_type=OuterRef("product__prod_type_id"),
33-
group__users=user,
34-
role__in=roles)
38+
group__users=user, role__in=roles,
39+
).values("product_type_id")
40+
3541
authorized_product_groups = Product_Group.objects.filter(
36-
product=OuterRef("product_id"),
37-
group__users=user,
38-
role__in=roles)
39-
cred_mappings = cred_mappings.annotate(
40-
product__prod_type__member=Exists(authorized_product_type_roles),
41-
product__member=Exists(authorized_product_roles),
42-
product__prod_type__authorized_group=Exists(authorized_product_type_groups),
43-
product__authorized_group=Exists(authorized_product_groups))
42+
group__users=user, role__in=roles,
43+
).values("product_id")
44+
45+
# Filter using IN with Subquery - no annotations needed
4446
return cred_mappings.filter(
45-
Q(product__prod_type__member=True) | Q(product__member=True)
46-
| Q(product__prod_type__authorized_group=True) | Q(product__authorized_group=True))
47+
Q(product__prod_type_id__in=Subquery(authorized_product_type_roles))
48+
| Q(product_id__in=Subquery(authorized_product_roles))
49+
| Q(product__prod_type_id__in=Subquery(authorized_product_type_groups))
50+
| Q(product_id__in=Subquery(authorized_product_groups)),
51+
)
52+
53+
54+
def get_authorized_cred_mappings_for_queryset(permission, queryset):
55+
"""Filters a provided queryset for authorization. Not cached due to dynamic queryset parameter."""
56+
user = get_current_user()
57+
58+
if user is None:
59+
return Cred_Mapping.objects.none()
60+
61+
if user.is_superuser:
62+
return queryset
63+
64+
if user_has_global_permission(user, permission):
65+
return queryset
66+
67+
roles = get_roles_for_permission(permission)
68+
69+
# Get authorized product/product_type IDs via subqueries
70+
authorized_product_type_roles = Product_Type_Member.objects.filter(
71+
user=user, role__in=roles,
72+
).values("product_type_id")
73+
74+
authorized_product_roles = Product_Member.objects.filter(
75+
user=user, role__in=roles,
76+
).values("product_id")
77+
78+
authorized_product_type_groups = Product_Type_Group.objects.filter(
79+
group__users=user, role__in=roles,
80+
).values("product_type_id")
81+
82+
authorized_product_groups = Product_Group.objects.filter(
83+
group__users=user, role__in=roles,
84+
).values("product_id")
85+
86+
# Filter using IN with Subquery - no annotations needed
87+
return queryset.filter(
88+
Q(product__prod_type_id__in=Subquery(authorized_product_type_roles))
89+
| Q(product_id__in=Subquery(authorized_product_roles))
90+
| Q(product__prod_type_id__in=Subquery(authorized_product_type_groups))
91+
| Q(product_id__in=Subquery(authorized_product_groups)),
92+
)

dojo/cred/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from dojo.authorization.authorization_decorators import user_is_authorized, user_is_configuration_authorized
1010
from dojo.authorization.roles_permissions import Permissions
11-
from dojo.cred.queries import get_authorized_cred_mappings
11+
from dojo.cred.queries import get_authorized_cred_mappings_for_queryset
1212
from dojo.forms import CredMappingForm, CredMappingFormProd, CredUserForm, NoteForm
1313
from dojo.models import Cred_Mapping, Cred_User, Engagement, Finding, Product, Test
1414
from dojo.utils import Product_Tab, add_breadcrumb, dojo_crypto_encrypt, prepare_for_view
@@ -85,7 +85,7 @@ def view_cred_details(request, ttid):
8585
notes = cred.notes.all()
8686
cred_products = Cred_Mapping.objects.select_related("product").filter(
8787
product_id__isnull=False, cred_id=ttid).order_by("product__name")
88-
cred_products = get_authorized_cred_mappings(Permissions.Product_View, cred_products)
88+
cred_products = get_authorized_cred_mappings_for_queryset(Permissions.Product_View, cred_products)
8989

9090
if request.method == "POST":
9191
form = NoteForm(request.POST)

dojo/db_migrations/0250_pghistory_backfill.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def progress_callback(msg, style=None):
4343
logger.warning(msg)
4444
elif style == "SUCCESS":
4545
logger.info(msg)
46+
elif style == "DEBUG":
47+
logger.debug(msg)
4648
else:
4749
logger.info(msg)
4850

0 commit comments

Comments
 (0)