Skip to content

Commit

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

Release: Merge back 2.36.6 into dev from: master-into-dev/2.36.6-2.37.0-dev
  • Loading branch information
Maffooch authored Jul 29, 2024
2 parents 4b60cef + 11171d8 commit afa58cf
Show file tree
Hide file tree
Showing 53 changed files with 4,886 additions and 662 deletions.
40 changes: 0 additions & 40 deletions .github/workflows/refresh_helm_lock_file.yaml

This file was deleted.

46 changes: 4 additions & 42 deletions dojo/api_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
from dojo.user.utils import get_configuration_permissions_codenames
from dojo.utils import (
async_delete,
generate_file_response,
get_setting,
get_system_setting,
)
Expand Down Expand Up @@ -646,21 +647,8 @@ def download_file(self, request, file_id, pk=None):
{"error": "File ID not associated with Engagement"},
status=status.HTTP_404_NOT_FOUND,
)
# Get the path of the file in media root
file_path = f"{settings.MEDIA_ROOT}/{file_object.file.url.lstrip(settings.MEDIA_URL)}"
file_handle = open(file_path, "rb")
# send file
response = FileResponse(
file_handle,
content_type=f"{mimetypes.guess_type(file_path)}",
status=status.HTTP_200_OK,
)
response["Content-Length"] = file_object.file.size
response[
"Content-Disposition"
] = f'attachment; filename="{file_object.file.name}"'

return response
return generate_file_response(file_object)


class RiskAcceptanceViewSet(
Expand Down Expand Up @@ -1156,21 +1144,8 @@ def download_file(self, request, file_id, pk=None):
{"error": "File ID not associated with Finding"},
status=status.HTTP_404_NOT_FOUND,
)
# Get the path of the file in media root
file_path = f"{settings.MEDIA_ROOT}/{file_object.file.url.lstrip(settings.MEDIA_URL)}"
file_handle = open(file_path, "rb")
# send file
response = FileResponse(
file_handle,
content_type=f"{mimetypes.guess_type(file_path)}",
status=status.HTTP_200_OK,
)
response["Content-Length"] = file_object.file.size
response[
"Content-Disposition"
] = f'attachment; filename="{file_object.file.name}"'

return response
return generate_file_response(file_object)

@extend_schema(
request=serializers.FindingNoteSerializer,
Expand Down Expand Up @@ -2319,21 +2294,8 @@ def download_file(self, request, file_id, pk=None):
{"error": "File ID not associated with Test"},
status=status.HTTP_404_NOT_FOUND,
)
# Get the path of the file in media root
file_path = f"{settings.MEDIA_ROOT}/{file_object.file.url.lstrip(settings.MEDIA_URL)}"
file_handle = open(file_path, "rb")
# send file
response = FileResponse(
file_handle,
content_type=f"{mimetypes.guess_type(file_path)}",
status=status.HTTP_200_OK,
)
response["Content-Length"] = file_object.file.size
response[
"Content-Disposition"
] = f'attachment; filename="{file_object.file.name}"'

return response
return generate_file_response(file_object)


# Authorization: authenticated, configuration
Expand Down
5 changes: 5 additions & 0 deletions dojo/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,19 @@ def ready(self):
# Load any signals here that will be ready for runtime
# Importing the signals file is good enough if using the reciever decorator
import dojo.announcement.signals # noqa: F401
import dojo.benchmark.signals # noqa: F401
import dojo.cred.signals # noqa: F401
import dojo.endpoint.signals # noqa: F401
import dojo.engagement.signals # noqa: F401
import dojo.finding_group.signals # noqa: F401
import dojo.notes.signals # noqa: F401
import dojo.product.signals # noqa: F401
import dojo.product_type.signals # noqa: F401
import dojo.risk_acceptance.signals # noqa: F401
import dojo.sla_config.helpers # noqa: F401
import dojo.tags_signals # noqa: F401
import dojo.test.signals # noqa: F401
import dojo.tool_product.signals # noqa: F401


def get_model_fields_with_extra(model, extra_fields=()):
Expand Down
14 changes: 14 additions & 0 deletions dojo/benchmark/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import logging

from django.db.models.signals import pre_delete
from django.dispatch import receiver

from dojo.models import Benchmark_Product
from dojo.notes.helper import delete_related_notes

logger = logging.getLogger(__name__)


@receiver(pre_delete, sender=Benchmark_Product)
def benchmark_product_pre_delete(sender, instance, **kwargs):
delete_related_notes(instance)
2 changes: 2 additions & 0 deletions dojo/benchmark/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def add_benchmark(queryset, product):
pass


@user_is_authorized(Product, Permissions.Benchmark_Edit, "pid")
def update_benchmark(request, pid, _type):
if request.method == "POST":
bench_id = request.POST.get("bench_id")
Expand Down Expand Up @@ -90,6 +91,7 @@ def update_benchmark(request, pid, _type):
)


@user_is_authorized(Product, Permissions.Benchmark_Edit, "pid")
def update_benchmark_summary(request, pid, _type, summary):
if request.method == "POST":
field = request.POST.get("field")
Expand Down
1 change: 1 addition & 0 deletions dojo/components/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ def components(request):
"filter": comp_filter,
"result": result,
"component_words": sorted(set(component_words)),
"enable_table_filtering": get_system_setting("enable_ui_table_based_searching"),
},
)
14 changes: 14 additions & 0 deletions dojo/cred/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import logging

from django.db.models.signals import pre_delete
from django.dispatch import receiver

from dojo.models import Cred_User
from dojo.notes.helper import delete_related_notes

logger = logging.getLogger(__name__)


@receiver(pre_delete, sender=Cred_User)
def cred_user_pre_delete(sender, instance, **kwargs):
delete_related_notes(instance)
5 changes: 3 additions & 2 deletions dojo/cred/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def view_cred_details(request, ttid):
"form": form,
"notes": notes,
"cred_products": cred_products,
"person": request.user.username,
})


Expand Down Expand Up @@ -650,7 +651,7 @@ def delete_cred_controller(request, destination_url, id, ttid):
if id:
product = None
if destination_url == "all_cred_product":
product = get_object_or_404(Product, id)
product = get_object_or_404(Product, id=id)
elif destination_url == "view_engagement":
engagement = get_object_or_404(Engagement, id=id)
product = engagement.product
Expand All @@ -669,7 +670,7 @@ def delete_cred_controller(request, destination_url, id, ttid):

@user_is_authorized(Cred_User, Permissions.Credential_Delete, "ttid")
def delete_cred(request, ttid):
return delete_cred_controller(request, "cred", 0, ttid)
return delete_cred_controller(request, "cred", 0, ttid=ttid)


@user_is_authorized(Product, Permissions.Product_Edit, "pid")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-07-23 19:53

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0212_sla_configuration_enforce_critical_and_more'),
]

operations = [
migrations.AddField(
model_name='system_settings',
name='enable_ui_table_based_searching',
field=models.BooleanField(default=True, help_text='With this setting enabled, table headings will contain sort buttons for the current page of data in addition to sorting buttons that consider data from all pages.', verbose_name='Enable UI Table Based Filtering/Sorting'),
),
]
8 changes: 7 additions & 1 deletion dojo/engagement/signals.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from auditlog.models import LogEntry
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import post_delete, post_save, pre_save
from django.db.models.signals import post_delete, post_save, pre_delete, pre_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils.translation import gettext as _

from dojo.models import Engagement
from dojo.notes.helper import delete_related_notes
from dojo.notifications.helper import create_notification


Expand Down Expand Up @@ -55,3 +56,8 @@ def engagement_post_delete(sender, instance, using, origin, **kwargs):
url=reverse("view_product", args=(instance.product.id, )),
recipients=[instance.lead],
icon="exclamation-triangle")


@receiver(pre_delete, sender=Engagement)
def engagement_pre_delete(sender, instance, **kwargs):
delete_related_notes(instance)
15 changes: 10 additions & 5 deletions dojo/engagement/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import csv
import logging
import mimetypes
import operator
import re
from datetime import datetime
Expand Down Expand Up @@ -257,6 +258,7 @@ def engagements_all(request):
"filter_form": filtered.form,
"name_words": sorted(set(name_words)),
"eng_words": sorted(set(eng_words)),
"enable_table_filtering": get_system_setting("enable_ui_table_based_searching"),
})


Expand Down Expand Up @@ -438,6 +440,8 @@ def get_filtered_tests(

def get(self, request, eid, *args, **kwargs):
eng = get_object_or_404(Engagement, id=eid)
# Make sure the user is authorized
user_has_permission_or_403(request.user, eng, Permissions.Engagement_View)
tests = eng.test_set.all().order_by("test_type__name", "-updated")
default_page_num = 10
tests_filter = self.get_filtered_tests(request, tests, eng)
Expand Down Expand Up @@ -505,8 +509,9 @@ def get(self, request, eid, *args, **kwargs):

def post(self, request, eid, *args, **kwargs):
eng = get_object_or_404(Engagement, id=eid)
# Make sure the user is authorized
user_has_permission_or_403(request.user, eng, Permissions.Engagement_View)
tests = eng.test_set.all().order_by("test_type__name", "-updated")

default_page_num = 10

tests_filter = self.get_filtered_tests(request, tests, eng)
Expand Down Expand Up @@ -1430,6 +1435,7 @@ def view_edit_risk_acceptance(request, eid, raid, edit_mode=False):
"request": request,
"add_findings": add_fpage,
"return_url": get_return_url(request),
"enable_table_filtering": get_system_setting("enable_ui_table_based_searching"),
})


Expand Down Expand Up @@ -1474,12 +1480,11 @@ def delete_risk_acceptance(request, eid, raid):

@user_is_authorized(Engagement, Permissions.Engagement_View, "eid")
def download_risk_acceptance(request, eid, raid):
import mimetypes

mimetypes.init()

risk_acceptance = get_object_or_404(Risk_Acceptance, pk=raid)

# Ensure the risk acceptance is under the supplied engagement
if not Engagement.objects.filter(risk_acceptance=risk_acceptance, id=eid).exists():
raise PermissionDenied
response = StreamingHttpResponse(
FileIterWrapper(
open(settings.MEDIA_ROOT + "/" + risk_acceptance.path.name, mode="rb")))
Expand Down
3 changes: 2 additions & 1 deletion dojo/finding/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Vulnerability_Id,
Vulnerability_Id_Template,
)
from dojo.notes.helper import delete_related_notes
from dojo.utils import get_current_user, mass_model_updater, to_str_typed

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -402,8 +403,8 @@ def finding_pre_delete(sender, instance, **kwargs):
logger.debug("finding pre_delete: %d", instance.id)
# this shouldn't be necessary as Django should remove any Many-To-Many entries automatically, might be a bug in Django?
# https://code.djangoproject.com/ticket/154

instance.found_by.clear()
delete_related_notes(instance)


def finding_delete(instance, **kwargs):
Expand Down
4 changes: 3 additions & 1 deletion dojo/finding/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ def get_initial_context(self, request: HttpRequest):
"jira_project": None,
"github_config": None,
"bulk_edit_form": FindingBulkUpdateForm(request.GET),
"enable_table_filtering": get_system_setting("enable_ui_table_based_searching"),
"title_words": get_words_for_field(Finding, "title"),
"component_words": get_words_for_field(Finding, "component_name"),
}
Expand Down Expand Up @@ -742,6 +743,7 @@ def get_initial_context(self, request: HttpRequest, finding: Finding, user: Dojo
"files": finding.files.all(),
"note_type_activation": note_type_activation,
"available_note_types": available_note_types,
"enable_table_filtering": get_system_setting("enable_ui_table_based_searching"),
"product_tab": Product_Tab(
finding.test.engagement.product, title="View Finding", tab="findings",
),
Expand Down Expand Up @@ -1736,7 +1738,7 @@ def request_finding_review(request, fid):
return render(
request,
"dojo/review_finding.html",
{"finding": finding, "product_tab": product_tab, "user": user, "form": form},
{"finding": finding, "product_tab": product_tab, "user": user, "form": form, "enable_table_filtering": get_system_setting("enable_ui_table_based_searching")},
)


Expand Down
13 changes: 5 additions & 8 deletions dojo/importers/base_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,12 @@ def parse_findings(
"""
Determine how to parse the findings based on the presence of the
`get_tests` function on the parser object
This function will vary by importer, so it is marked as
abstract with a prohibitive exception raised if the
method is attempted to to be used by the BaseImporter class
"""
# Attempt any preprocessing before generating findings
if len(self.parsed_findings) == 0 or self.test is None:
scan = self.process_scan_file(scan)
if hasattr(parser, "get_tests"):
self.parsed_findings = self.parse_findings_dynamic_test_type(scan, parser)
else:
self.parsed_findings = self.parse_findings_static_test_type(scan, parser)
return self.parsed_findings
self.check_child_implementation_exception()

def sync_process_findings(
self,
Expand Down
Loading

0 comments on commit afa58cf

Please sign in to comment.