Skip to content

Commit 7a05791

Browse files
authored
Merge pull request #10449 from DefectDojo/release/2.35.4
Release: Merge release into master from: release/2.35.4
2 parents bfa20c9 + a22c7df commit 7a05791

15 files changed

Lines changed: 1157 additions & 56 deletions

File tree

components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "defectdojo",
3-
"version": "2.35.3",
3+
"version": "2.35.4",
44
"license" : "BSD-3-Clause",
55
"private": true,
66
"dependencies": {

dojo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
# Django starts so that shared_task will use this app.
55
from .celery import app as celery_app # noqa: F401
66

7-
__version__ = '2.35.3'
7+
__version__ = '2.35.4'
88
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
99
__docs__ = 'https://documentation.defectdojo.com'

dojo/api_v2/views.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
ApiTemplateFindingFilter,
6060
ApiTestFilter,
6161
ReportFindingFilter,
62+
ReportFindingFilterWithoutObjectLookups,
6263
)
6364
from dojo.finding.queries import (
6465
get_authorized_findings,
@@ -2866,13 +2867,15 @@ def report_generate(request, obj, options):
28662867
include_finding_images = options.get("include_finding_images", False)
28672868
include_executive_summary = options.get("include_executive_summary", False)
28682869
include_table_of_contents = options.get("include_table_of_contents", False)
2870+
filter_string_matching = get_system_setting("filter_string_matching", False)
2871+
report_finding_filter_class = ReportFindingFilterWithoutObjectLookups if filter_string_matching else ReportFindingFilter
28692872

28702873
if type(obj).__name__ == "Product_Type":
28712874
product_type = obj
28722875

28732876
report_name = "Product Type Report: " + str(product_type)
28742877

2875-
findings = ReportFindingFilter(
2878+
findings = report_finding_filter_class(
28762879
request.GET,
28772880
prod_type=product_type,
28782881
queryset=prefetch_related_findings_for_report(
@@ -2901,7 +2904,7 @@ def report_generate(request, obj, options):
29012904

29022905
report_name = "Product Report: " + str(product)
29032906

2904-
findings = ReportFindingFilter(
2907+
findings = report_finding_filter_class(
29052908
request.GET,
29062909
product=product,
29072910
queryset=prefetch_related_findings_for_report(
@@ -2915,7 +2918,7 @@ def report_generate(request, obj, options):
29152918

29162919
elif type(obj).__name__ == "Engagement":
29172920
engagement = obj
2918-
findings = ReportFindingFilter(
2921+
findings = report_finding_filter_class(
29192922
request.GET,
29202923
engagement=engagement,
29212924
queryset=prefetch_related_findings_for_report(
@@ -2932,7 +2935,7 @@ def report_generate(request, obj, options):
29322935

29332936
elif type(obj).__name__ == "Test":
29342937
test = obj
2935-
findings = ReportFindingFilter(
2938+
findings = report_finding_filter_class(
29362939
request.GET,
29372940
engagement=test.engagement,
29382941
queryset=prefetch_related_findings_for_report(
@@ -2948,15 +2951,15 @@ def report_generate(request, obj, options):
29482951
endpoints = Endpoint.objects.filter(
29492952
host=host, product=endpoint.product
29502953
).distinct()
2951-
findings = ReportFindingFilter(
2954+
findings = report_finding_filter_class(
29522955
request.GET,
29532956
queryset=prefetch_related_findings_for_report(
29542957
Finding.objects.filter(endpoints__in=endpoints)
29552958
),
29562959
)
29572960

29582961
elif type(obj).__name__ == "CastTaggedQuerySet":
2959-
findings = ReportFindingFilter(
2962+
findings = report_finding_filter_class(
29602963
request.GET,
29612964
queryset=prefetch_related_findings_for_report(obj).distinct(),
29622965
)

dojo/filters.py

Lines changed: 184 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,10 @@ class FindingTagStringFilter(FilterSet):
595595
help_text="Search for tags on a Product that are an exact match, and exclude them",
596596
exclude=True)
597597

598+
def delete_tags_from_form(self, tag_list: list):
599+
for tag in tag_list:
600+
self.form.fields.pop(tag, None)
601+
598602
def __init__(self, *args, **kwargs):
599603
super().__init__(*args, **kwargs)
600604

@@ -1716,12 +1720,12 @@ class FindingFilterWithoutObjectLookups(FindingFilterHelper, FindingTagStringFil
17161720
label="Engagement name Contains",
17171721
help_text="Search for Engagement names that contain a given pattern")
17181722
test__name = CharFilter(
1719-
field_name="test__engagement__name",
1723+
field_name="test__name",
17201724
lookup_expr="iexact",
17211725
label="Test Name",
17221726
help_text="Search for Test names that are an exact match")
17231727
test__name_contains = CharFilter(
1724-
field_name="test__engagement__name",
1728+
field_name="test__name",
17251729
lookup_expr="icontains",
17261730
label="Test name Contains",
17271731
help_text="Search for Test names that contain a given pattern")
@@ -2877,42 +2881,31 @@ class Meta:
28772881
exclude = ['product']
28782882

28792883

2880-
class ReportFindingFilter(FindingTagFilter):
2884+
class ReportFindingFilterHelper(FilterSet):
28812885
title = CharFilter(lookup_expr='icontains', label='Name')
28822886
date = DateFromToRangeFilter(field_name='date', label="Date Discovered")
2883-
test__engagement__product = ModelMultipleChoiceFilter(
2884-
queryset=Product.objects.none(), label="Product")
2885-
test__engagement__product__prod_type = ModelMultipleChoiceFilter(
2886-
queryset=Product_Type.objects.none(),
2887-
label="Product Type")
2888-
test__engagement__product__lifecycle = MultipleChoiceFilter(choices=Product.LIFECYCLE_CHOICES, label="Product Lifecycle")
2889-
test__engagement = ModelMultipleChoiceFilter(queryset=Engagement.objects.none(), label="Engagement")
28902887
severity = MultipleChoiceFilter(choices=SEVERITY_CHOICES)
28912888
active = ReportBooleanFilter()
28922889
is_mitigated = ReportBooleanFilter()
28932890
mitigated = DateRangeFilter(label="Mitigated Date")
28942891
verified = ReportBooleanFilter()
28952892
false_p = ReportBooleanFilter(label="False Positive")
2896-
risk_acceptance = ReportRiskAcceptanceFilter(
2897-
label="Risk Accepted")
2898-
# queryset will be restricted in __init__, here we don't have access to the logged in user
2893+
risk_acceptance = ReportRiskAcceptanceFilter(label="Risk Accepted")
28992894
duplicate = ReportBooleanFilter()
2900-
duplicate_finding = ModelChoiceFilter(queryset=Finding.objects.filter(original_finding__isnull=False).distinct())
29012895
out_of_scope = ReportBooleanFilter()
29022896
outside_of_sla = FindingSLAFilter(label="Outside of SLA")
2903-
29042897
file_path = CharFilter(lookup_expr='icontains')
29052898

29062899
class Meta:
29072900
model = Finding
29082901
# exclude sonarqube issue as by default it will show all without checking permissions
29092902
exclude = ['date', 'cwe', 'url', 'description', 'mitigation', 'impact',
2910-
'references', 'sonarqube_issue',
2911-
'thread_id', 'notes',
2903+
'references', 'sonarqube_issue', 'duplicate_finding',
2904+
'thread_id', 'notes', 'inherited_tags', 'endpoints',
29122905
'numerical_severity', 'reporter', 'last_reviewed',
29132906
'jira_creation', 'jira_change', 'files']
29142907

2915-
def __init__(self, *args, **kwargs):
2908+
def manage_kwargs(self, kwargs):
29162909
self.prod_type = None
29172910
self.product = None
29182911
self.engagement = None
@@ -2926,6 +2919,24 @@ def __init__(self, *args, **kwargs):
29262919
if 'test' in kwargs:
29272920
self.test = kwargs.pop('test')
29282921

2922+
@property
2923+
def qs(self):
2924+
parent = super().qs
2925+
return get_authorized_findings(Permissions.Finding_View, parent)
2926+
2927+
2928+
class ReportFindingFilter(ReportFindingFilterHelper, FindingTagFilter):
2929+
test__engagement__product = ModelMultipleChoiceFilter(
2930+
queryset=Product.objects.none(), label="Product")
2931+
test__engagement__product__prod_type = ModelMultipleChoiceFilter(
2932+
queryset=Product_Type.objects.none(),
2933+
label="Product Type")
2934+
test__engagement__product__lifecycle = MultipleChoiceFilter(choices=Product.LIFECYCLE_CHOICES, label="Product Lifecycle")
2935+
test__engagement = ModelMultipleChoiceFilter(queryset=Engagement.objects.none(), label="Engagement")
2936+
duplicate_finding = ModelChoiceFilter(queryset=Finding.objects.filter(original_finding__isnull=False).distinct())
2937+
2938+
def __init__(self, *args, **kwargs):
2939+
self.manage_kwargs(kwargs)
29292940
super().__init__(*args, **kwargs)
29302941

29312942
# duplicate_finding queryset needs to restricted in line with permissions
@@ -2961,10 +2972,161 @@ def __init__(self, *args, **kwargs):
29612972
if 'test__engagement' in self.form.fields:
29622973
self.form.fields['test__engagement'].queryset = get_authorized_engagements(Permissions.Engagement_View)
29632974

2964-
@property
2965-
def qs(self):
2966-
parent = super().qs
2967-
return get_authorized_findings(Permissions.Finding_View, parent)
2975+
2976+
class ReportFindingFilterWithoutObjectLookups(ReportFindingFilterHelper, FindingTagStringFilter):
2977+
test__engagement__product__prod_type = NumberFilter(widget=HiddenInput())
2978+
test__engagement__product = NumberFilter(widget=HiddenInput())
2979+
test__engagement = NumberFilter(widget=HiddenInput())
2980+
test = NumberFilter(widget=HiddenInput())
2981+
endpoint = NumberFilter(widget=HiddenInput())
2982+
reporter = CharFilter(
2983+
field_name="reporter__username",
2984+
lookup_expr="iexact",
2985+
label="Reporter Username",
2986+
help_text="Search for Reporter names that are an exact match")
2987+
reporter_contains = CharFilter(
2988+
field_name="reporter__username",
2989+
lookup_expr="icontains",
2990+
label="Reporter Username Contains",
2991+
help_text="Search for Reporter names that contain a given pattern")
2992+
reviewers = CharFilter(
2993+
field_name="reviewers__username",
2994+
lookup_expr="iexact",
2995+
label="Reviewer Username",
2996+
help_text="Search for Reviewer names that are an exact match")
2997+
reviewers_contains = CharFilter(
2998+
field_name="reviewers__username",
2999+
lookup_expr="icontains",
3000+
label="Reviewer Username Contains",
3001+
help_text="Search for Reviewer usernames that contain a given pattern")
3002+
last_reviewed_by = CharFilter(
3003+
field_name="last_reviewed_by__username",
3004+
lookup_expr="iexact",
3005+
label="Last Reviewed By Username",
3006+
help_text="Search for Last Reviewed By names that are an exact match")
3007+
last_reviewed_by_contains = CharFilter(
3008+
field_name="last_reviewed_by__username",
3009+
lookup_expr="icontains",
3010+
label="Last Reviewed By Username Contains",
3011+
help_text="Search for Last Reviewed By usernames that contain a given pattern")
3012+
review_requested_by = CharFilter(
3013+
field_name="review_requested_by__username",
3014+
lookup_expr="iexact",
3015+
label="Review Requested By Username",
3016+
help_text="Search for Review Requested By names that are an exact match")
3017+
review_requested_by_contains = CharFilter(
3018+
field_name="review_requested_by__username",
3019+
lookup_expr="icontains",
3020+
label="Review Requested By Username Contains",
3021+
help_text="Search for Review Requested By usernames that contain a given pattern")
3022+
mitigated_by = CharFilter(
3023+
field_name="mitigated_by__username",
3024+
lookup_expr="iexact",
3025+
label="Mitigator Username",
3026+
help_text="Search for Mitigator names that are an exact match")
3027+
mitigated_by_contains = CharFilter(
3028+
field_name="mitigated_by__username",
3029+
lookup_expr="icontains",
3030+
label="Mitigator Username Contains",
3031+
help_text="Search for Mitigator usernames that contain a given pattern")
3032+
defect_review_requested_by = CharFilter(
3033+
field_name="defect_review_requested_by__username",
3034+
lookup_expr="iexact",
3035+
label="Requester of Defect Review Username",
3036+
help_text="Search for Requester of Defect Review names that are an exact match")
3037+
defect_review_requested_by_contains = CharFilter(
3038+
field_name="defect_review_requested_by__username",
3039+
lookup_expr="icontains",
3040+
label="Requester of Defect Review Username Contains",
3041+
help_text="Search for Requester of Defect Review usernames that contain a given pattern")
3042+
test__engagement__product__prod_type__name = CharFilter(
3043+
field_name="test__engagement__product__prod_type__name",
3044+
lookup_expr="iexact",
3045+
label="Product Type Name",
3046+
help_text="Search for Product Type names that are an exact match")
3047+
test__engagement__product__prod_type__name_contains = CharFilter(
3048+
field_name="test__engagement__product__prod_type__name",
3049+
lookup_expr="icontains",
3050+
label="Product Type Name Contains",
3051+
help_text="Search for Product Type names that contain a given pattern")
3052+
test__engagement__product__name = CharFilter(
3053+
field_name="test__engagement__product__name",
3054+
lookup_expr="iexact",
3055+
label="Product Name",
3056+
help_text="Search for Product names that are an exact match")
3057+
test__engagement__product__name_contains = CharFilter(
3058+
field_name="test__engagement__product__name",
3059+
lookup_expr="icontains",
3060+
label="Product name Contains",
3061+
help_text="Search for Product names that contain a given pattern")
3062+
test__engagement__name = CharFilter(
3063+
field_name="test__engagement__name",
3064+
lookup_expr="iexact",
3065+
label="Engagement Name",
3066+
help_text="Search for Engagement names that are an exact match")
3067+
test__engagement__name_contains = CharFilter(
3068+
field_name="test__engagement__name",
3069+
lookup_expr="icontains",
3070+
label="Engagement name Contains",
3071+
help_text="Search for Engagement names that contain a given pattern")
3072+
test__name = CharFilter(
3073+
field_name="test__name",
3074+
lookup_expr="iexact",
3075+
label="Test Name",
3076+
help_text="Search for Test names that are an exact match")
3077+
test__name_contains = CharFilter(
3078+
field_name="test__name",
3079+
lookup_expr="icontains",
3080+
label="Test name Contains",
3081+
help_text="Search for Test names that contain a given pattern")
3082+
3083+
def __init__(self, *args, **kwargs):
3084+
self.manage_kwargs(kwargs)
3085+
super().__init__(*args, **kwargs)
3086+
3087+
product_type_refs = [
3088+
"test__engagement__product__prod_type__name",
3089+
"test__engagement__product__prod_type__name_contains",
3090+
]
3091+
product_refs = [
3092+
"test__engagement__product__name",
3093+
"test__engagement__product__name_contains",
3094+
"test__engagement__product__tags",
3095+
"test__engagement__product__tags_contains",
3096+
"not_test__engagement__product__tags",
3097+
"not_test__engagement__product__tags_contains",
3098+
]
3099+
engagement_refs = [
3100+
"test__engagement__name",
3101+
"test__engagement__name_contains",
3102+
"test__engagement__tags",
3103+
"test__engagement__tags_contains",
3104+
"not_test__engagement__tags",
3105+
"not_test__engagement__tags_contains",
3106+
]
3107+
test_refs = [
3108+
"test__name",
3109+
"test__name_contains",
3110+
"test__tags",
3111+
"test__tags_contains",
3112+
"not_test__tags",
3113+
"not_test__tags_contains",
3114+
]
3115+
3116+
if self.test:
3117+
self.delete_tags_from_form(product_type_refs)
3118+
self.delete_tags_from_form(product_refs)
3119+
self.delete_tags_from_form(engagement_refs)
3120+
self.delete_tags_from_form(test_refs)
3121+
elif self.engagement:
3122+
self.delete_tags_from_form(product_type_refs)
3123+
self.delete_tags_from_form(product_refs)
3124+
self.delete_tags_from_form(engagement_refs)
3125+
elif self.product:
3126+
self.delete_tags_from_form(product_type_refs)
3127+
self.delete_tags_from_form(product_refs)
3128+
elif self.prod_type:
3129+
self.delete_tags_from_form(product_type_refs)
29683130

29693131

29703132
class UserFilter(DojoFilter):

dojo/jira_link/views.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,10 @@ def check_for_and_create_comment(parsed_json):
241241
findings = [jissue.finding]
242242
create_notification(event='jira_comment', title=f'JIRA incoming comment - {jissue.finding}', finding=jissue.finding, url=reverse("view_finding", args=(jissue.finding.id,)), icon='check')
243243
elif jissue.finding_group:
244-
findings = [jissue.finding_group.findings.all()]
245-
create_notification(event='jira_comment', title=f'JIRA incoming comment - {jissue.finding}', finding=jissue.finding, url=reverse("view_finding_group", args=(jissue.finding_group.id,)), icon='check')
244+
findings = jissue.finding_group.findings.all()
245+
first_finding_group = findings.first()
246+
if first_finding_group:
247+
create_notification(event='jira_comment', title=f'JIRA incoming comment - {jissue.finding_group}', finding=first_finding_group, url=reverse("view_finding_group", args=(jissue.finding_group.id,)), icon='check')
246248
elif jissue.engagement:
247249
return webhook_responser_handler("debug", "Comment for engagement ignored")
248250
else:

0 commit comments

Comments
 (0)