Skip to content

Commit

Permalink
Merge pull request #10450 from DefectDojo/master-into-dev/2.35.4-2.36…
Browse files Browse the repository at this point in the history
….0-dev

Release: Merge back 2.35.4 into dev from: master-into-dev/2.35.4-2.36.0-dev
  • Loading branch information
blakeaowens authored Jun 24, 2024
2 parents 91de2e8 + 5941b63 commit 6c7d35e
Show file tree
Hide file tree
Showing 14 changed files with 1,159 additions and 58 deletions.
15 changes: 9 additions & 6 deletions dojo/api_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
ApiTemplateFindingFilter,
ApiTestFilter,
ReportFindingFilter,
ReportFindingFilterWithoutObjectLookups,
)
from dojo.finding.queries import (
get_authorized_findings,
Expand Down Expand Up @@ -2866,13 +2867,15 @@ def report_generate(request, obj, options):
include_finding_images = options.get("include_finding_images", False)
include_executive_summary = options.get("include_executive_summary", False)
include_table_of_contents = options.get("include_table_of_contents", False)
filter_string_matching = get_system_setting("filter_string_matching", False)
report_finding_filter_class = ReportFindingFilterWithoutObjectLookups if filter_string_matching else ReportFindingFilter

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

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

findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
prod_type=product_type,
queryset=prefetch_related_findings_for_report(
Expand Down Expand Up @@ -2901,7 +2904,7 @@ def report_generate(request, obj, options):

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

findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
product=product,
queryset=prefetch_related_findings_for_report(
Expand All @@ -2915,7 +2918,7 @@ def report_generate(request, obj, options):

elif type(obj).__name__ == "Engagement":
engagement = obj
findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
engagement=engagement,
queryset=prefetch_related_findings_for_report(
Expand All @@ -2932,7 +2935,7 @@ def report_generate(request, obj, options):

elif type(obj).__name__ == "Test":
test = obj
findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
engagement=test.engagement,
queryset=prefetch_related_findings_for_report(
Expand All @@ -2948,15 +2951,15 @@ def report_generate(request, obj, options):
endpoints = Endpoint.objects.filter(
host=host, product=endpoint.product
).distinct()
findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
queryset=prefetch_related_findings_for_report(
Finding.objects.filter(endpoints__in=endpoints)
),
)

elif type(obj).__name__ == "CastTaggedQuerySet":
findings = ReportFindingFilter(
findings = report_finding_filter_class(
request.GET,
queryset=prefetch_related_findings_for_report(obj).distinct(),
)
Expand Down
206 changes: 184 additions & 22 deletions dojo/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,10 @@ class FindingTagStringFilter(FilterSet):
help_text="Search for tags on a Product that are an exact match, and exclude them",
exclude=True)

def delete_tags_from_form(self, tag_list: list):
for tag in tag_list:
self.form.fields.pop(tag, None)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down Expand Up @@ -1716,12 +1720,12 @@ class FindingFilterWithoutObjectLookups(FindingFilterHelper, FindingTagStringFil
label="Engagement name Contains",
help_text="Search for Engagement names that contain a given pattern")
test__name = CharFilter(
field_name="test__engagement__name",
field_name="test__name",
lookup_expr="iexact",
label="Test Name",
help_text="Search for Test names that are an exact match")
test__name_contains = CharFilter(
field_name="test__engagement__name",
field_name="test__name",
lookup_expr="icontains",
label="Test name Contains",
help_text="Search for Test names that contain a given pattern")
Expand Down Expand Up @@ -2877,42 +2881,31 @@ class Meta:
exclude = ['product']


class ReportFindingFilter(FindingTagFilter):
class ReportFindingFilterHelper(FilterSet):
title = CharFilter(lookup_expr='icontains', label='Name')
date = DateFromToRangeFilter(field_name='date', label="Date Discovered")
test__engagement__product = ModelMultipleChoiceFilter(
queryset=Product.objects.none(), label="Product")
test__engagement__product__prod_type = ModelMultipleChoiceFilter(
queryset=Product_Type.objects.none(),
label="Product Type")
test__engagement__product__lifecycle = MultipleChoiceFilter(choices=Product.LIFECYCLE_CHOICES, label="Product Lifecycle")
test__engagement = ModelMultipleChoiceFilter(queryset=Engagement.objects.none(), label="Engagement")
severity = MultipleChoiceFilter(choices=SEVERITY_CHOICES)
active = ReportBooleanFilter()
is_mitigated = ReportBooleanFilter()
mitigated = DateRangeFilter(label="Mitigated Date")
verified = ReportBooleanFilter()
false_p = ReportBooleanFilter(label="False Positive")
risk_acceptance = ReportRiskAcceptanceFilter(
label="Risk Accepted")
# queryset will be restricted in __init__, here we don't have access to the logged in user
risk_acceptance = ReportRiskAcceptanceFilter(label="Risk Accepted")
duplicate = ReportBooleanFilter()
duplicate_finding = ModelChoiceFilter(queryset=Finding.objects.filter(original_finding__isnull=False).distinct())
out_of_scope = ReportBooleanFilter()
outside_of_sla = FindingSLAFilter(label="Outside of SLA")

file_path = CharFilter(lookup_expr='icontains')

class Meta:
model = Finding
# exclude sonarqube issue as by default it will show all without checking permissions
exclude = ['date', 'cwe', 'url', 'description', 'mitigation', 'impact',
'references', 'sonarqube_issue',
'thread_id', 'notes',
'references', 'sonarqube_issue', 'duplicate_finding',
'thread_id', 'notes', 'inherited_tags', 'endpoints',
'numerical_severity', 'reporter', 'last_reviewed',
'jira_creation', 'jira_change', 'files']

def __init__(self, *args, **kwargs):
def manage_kwargs(self, kwargs):
self.prod_type = None
self.product = None
self.engagement = None
Expand All @@ -2926,6 +2919,24 @@ def __init__(self, *args, **kwargs):
if 'test' in kwargs:
self.test = kwargs.pop('test')

@property
def qs(self):
parent = super().qs
return get_authorized_findings(Permissions.Finding_View, parent)


class ReportFindingFilter(ReportFindingFilterHelper, FindingTagFilter):
test__engagement__product = ModelMultipleChoiceFilter(
queryset=Product.objects.none(), label="Product")
test__engagement__product__prod_type = ModelMultipleChoiceFilter(
queryset=Product_Type.objects.none(),
label="Product Type")
test__engagement__product__lifecycle = MultipleChoiceFilter(choices=Product.LIFECYCLE_CHOICES, label="Product Lifecycle")
test__engagement = ModelMultipleChoiceFilter(queryset=Engagement.objects.none(), label="Engagement")
duplicate_finding = ModelChoiceFilter(queryset=Finding.objects.filter(original_finding__isnull=False).distinct())

def __init__(self, *args, **kwargs):
self.manage_kwargs(kwargs)
super().__init__(*args, **kwargs)

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

@property
def qs(self):
parent = super().qs
return get_authorized_findings(Permissions.Finding_View, parent)

class ReportFindingFilterWithoutObjectLookups(ReportFindingFilterHelper, FindingTagStringFilter):
test__engagement__product__prod_type = NumberFilter(widget=HiddenInput())
test__engagement__product = NumberFilter(widget=HiddenInput())
test__engagement = NumberFilter(widget=HiddenInput())
test = NumberFilter(widget=HiddenInput())
endpoint = NumberFilter(widget=HiddenInput())
reporter = CharFilter(
field_name="reporter__username",
lookup_expr="iexact",
label="Reporter Username",
help_text="Search for Reporter names that are an exact match")
reporter_contains = CharFilter(
field_name="reporter__username",
lookup_expr="icontains",
label="Reporter Username Contains",
help_text="Search for Reporter names that contain a given pattern")
reviewers = CharFilter(
field_name="reviewers__username",
lookup_expr="iexact",
label="Reviewer Username",
help_text="Search for Reviewer names that are an exact match")
reviewers_contains = CharFilter(
field_name="reviewers__username",
lookup_expr="icontains",
label="Reviewer Username Contains",
help_text="Search for Reviewer usernames that contain a given pattern")
last_reviewed_by = CharFilter(
field_name="last_reviewed_by__username",
lookup_expr="iexact",
label="Last Reviewed By Username",
help_text="Search for Last Reviewed By names that are an exact match")
last_reviewed_by_contains = CharFilter(
field_name="last_reviewed_by__username",
lookup_expr="icontains",
label="Last Reviewed By Username Contains",
help_text="Search for Last Reviewed By usernames that contain a given pattern")
review_requested_by = CharFilter(
field_name="review_requested_by__username",
lookup_expr="iexact",
label="Review Requested By Username",
help_text="Search for Review Requested By names that are an exact match")
review_requested_by_contains = CharFilter(
field_name="review_requested_by__username",
lookup_expr="icontains",
label="Review Requested By Username Contains",
help_text="Search for Review Requested By usernames that contain a given pattern")
mitigated_by = CharFilter(
field_name="mitigated_by__username",
lookup_expr="iexact",
label="Mitigator Username",
help_text="Search for Mitigator names that are an exact match")
mitigated_by_contains = CharFilter(
field_name="mitigated_by__username",
lookup_expr="icontains",
label="Mitigator Username Contains",
help_text="Search for Mitigator usernames that contain a given pattern")
defect_review_requested_by = CharFilter(
field_name="defect_review_requested_by__username",
lookup_expr="iexact",
label="Requester of Defect Review Username",
help_text="Search for Requester of Defect Review names that are an exact match")
defect_review_requested_by_contains = CharFilter(
field_name="defect_review_requested_by__username",
lookup_expr="icontains",
label="Requester of Defect Review Username Contains",
help_text="Search for Requester of Defect Review usernames that contain a given pattern")
test__engagement__product__prod_type__name = CharFilter(
field_name="test__engagement__product__prod_type__name",
lookup_expr="iexact",
label="Product Type Name",
help_text="Search for Product Type names that are an exact match")
test__engagement__product__prod_type__name_contains = CharFilter(
field_name="test__engagement__product__prod_type__name",
lookup_expr="icontains",
label="Product Type Name Contains",
help_text="Search for Product Type names that contain a given pattern")
test__engagement__product__name = CharFilter(
field_name="test__engagement__product__name",
lookup_expr="iexact",
label="Product Name",
help_text="Search for Product names that are an exact match")
test__engagement__product__name_contains = CharFilter(
field_name="test__engagement__product__name",
lookup_expr="icontains",
label="Product name Contains",
help_text="Search for Product names that contain a given pattern")
test__engagement__name = CharFilter(
field_name="test__engagement__name",
lookup_expr="iexact",
label="Engagement Name",
help_text="Search for Engagement names that are an exact match")
test__engagement__name_contains = CharFilter(
field_name="test__engagement__name",
lookup_expr="icontains",
label="Engagement name Contains",
help_text="Search for Engagement names that contain a given pattern")
test__name = CharFilter(
field_name="test__name",
lookup_expr="iexact",
label="Test Name",
help_text="Search for Test names that are an exact match")
test__name_contains = CharFilter(
field_name="test__name",
lookup_expr="icontains",
label="Test name Contains",
help_text="Search for Test names that contain a given pattern")

def __init__(self, *args, **kwargs):
self.manage_kwargs(kwargs)
super().__init__(*args, **kwargs)

product_type_refs = [
"test__engagement__product__prod_type__name",
"test__engagement__product__prod_type__name_contains",
]
product_refs = [
"test__engagement__product__name",
"test__engagement__product__name_contains",
"test__engagement__product__tags",
"test__engagement__product__tags_contains",
"not_test__engagement__product__tags",
"not_test__engagement__product__tags_contains",
]
engagement_refs = [
"test__engagement__name",
"test__engagement__name_contains",
"test__engagement__tags",
"test__engagement__tags_contains",
"not_test__engagement__tags",
"not_test__engagement__tags_contains",
]
test_refs = [
"test__name",
"test__name_contains",
"test__tags",
"test__tags_contains",
"not_test__tags",
"not_test__tags_contains",
]

if self.test:
self.delete_tags_from_form(product_type_refs)
self.delete_tags_from_form(product_refs)
self.delete_tags_from_form(engagement_refs)
self.delete_tags_from_form(test_refs)
elif self.engagement:
self.delete_tags_from_form(product_type_refs)
self.delete_tags_from_form(product_refs)
self.delete_tags_from_form(engagement_refs)
elif self.product:
self.delete_tags_from_form(product_type_refs)
self.delete_tags_from_form(product_refs)
elif self.prod_type:
self.delete_tags_from_form(product_type_refs)


class UserFilter(DojoFilter):
Expand Down
6 changes: 4 additions & 2 deletions dojo/jira_link/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,10 @@ def check_for_and_create_comment(parsed_json):
findings = [jissue.finding]
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')
elif jissue.finding_group:
findings = [jissue.finding_group.findings.all()]
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')
findings = jissue.finding_group.findings.all()
first_finding_group = findings.first()
if first_finding_group:
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')
elif jissue.engagement:
return webhook_responser_handler("debug", "Comment for engagement ignored")
else:
Expand Down
Loading

0 comments on commit 6c7d35e

Please sign in to comment.