From 8695edb322e5d6fa5b06392ba35270e9b1aaa21a Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 29 Jul 2024 18:53:00 +0000 Subject: [PATCH 1/7] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 00b56f81882..ab3201e6a41 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.36.6", + "version": "2.37.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index d01a8d9ffc5..707177ee3ee 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa: F401 -__version__ = '2.36.6' +__version__ = '2.37.0-dev' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 61d9e19baa4..a05a5537864 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.36.6" +appVersion: "2.37.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.143 +version: 1.6.144-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 1fb5e9e3d08c5dc065e7bc6649b7e8686c6380e1 Mon Sep 17 00:00:00 2001 From: manuelsommer <47991713+manuel-sommer@users.noreply.github.com> Date: Fri, 2 Aug 2024 00:19:47 +0200 Subject: [PATCH 2/7] :bug: fix Bearer CLI missing Scan Type (#10654) --- dojo/tools/bearer_cli/parser.py | 2 +- unittests/tools/test_bearer_cli_parser.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dojo/tools/bearer_cli/parser.py b/dojo/tools/bearer_cli/parser.py index 0aca0bcbe43..4f91bb8632a 100644 --- a/dojo/tools/bearer_cli/parser.py +++ b/dojo/tools/bearer_cli/parser.py @@ -3,7 +3,7 @@ from dojo.models import Finding -class BearerParser: +class BearerCLIParser: """ Bearer CLI tool is a SAST scanner for multiple languages """ diff --git a/unittests/tools/test_bearer_cli_parser.py b/unittests/tools/test_bearer_cli_parser.py index c3e75819318..d0fcdd26577 100644 --- a/unittests/tools/test_bearer_cli_parser.py +++ b/unittests/tools/test_bearer_cli_parser.py @@ -1,14 +1,14 @@ from django.test import TestCase from dojo.models import Test -from dojo.tools.bearer_cli.parser import BearerParser +from dojo.tools.bearer_cli.parser import BearerCLIParser class TestBearerParser(TestCase): def test_bearer_parser_with_one_vuln_has_one_findings(self): testfile = open("unittests/scans/bearer_cli/bearer_cli_one_vul.json") - parser = BearerParser() + parser = BearerCLIParser() findings = parser.get_findings(testfile, Test()) testfile.close() self.assertEqual(1, len(findings)) @@ -22,7 +22,7 @@ def test_bearer_parser_with_one_vuln_has_one_findings(self): def test_bearer_parser_with_many_vuln_has_many_findings(self): testfile = open("unittests/scans/bearer_cli/bearer_cli_many_vul.json") - parser = BearerParser() + parser = BearerCLIParser() findings = parser.get_findings(testfile, Test()) testfile.close() self.assertEqual(4, len(findings)) From 22937bac300600fd6c79e75142d34695b31f1a69 Mon Sep 17 00:00:00 2001 From: dogboat Date: Thu, 1 Aug 2024 18:20:27 -0400 Subject: [PATCH 3/7] Groups/users labels text (#10663) * groups-users-label-text Update text labels for entries on groups and users view pages * retrigger actions --- dojo/templates/dojo/view_group.html | 16 ++++++++-------- dojo/templates/dojo/view_user.html | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dojo/templates/dojo/view_group.html b/dojo/templates/dojo/view_group.html index afa8b1ccc59..bbb7c1bbc20 100644 --- a/dojo/templates/dojo/view_group.html +++ b/dojo/templates/dojo/view_group.html @@ -3,7 +3,7 @@ {% load authorization_tags %} {% block content %} -

Group {{ group.name }}

+

Group: {{ group.name }}

@@ -43,7 +43,7 @@

Description

-

Members

+

Members of this Group

  @@ -72,7 +72,7 @@

Members

User - Group role + Role in this Group @@ -108,7 +108,7 @@

Members

{% else %}
- No members found. + This Group has no members.
{% endif %}
@@ -116,7 +116,7 @@

Members

-

Product Type Groups

+

Product Types this Group can access

  @@ -182,7 +182,7 @@

Product Type Groups

{% else %}
- No product type groups found. + This Group cannot access any Product Types.
{% endif %}
@@ -190,7 +190,7 @@

Product Type Groups

-

Product Groups

+

Products this Group can access

  @@ -256,7 +256,7 @@

Product Groups

{% else %}
- No product groups found. + This Group cannot access any Products.
{% endif %}
diff --git a/dojo/templates/dojo/view_user.html b/dojo/templates/dojo/view_user.html index ffdd4ac91da..b042ee93095 100644 --- a/dojo/templates/dojo/view_user.html +++ b/dojo/templates/dojo/view_user.html @@ -5,7 +5,7 @@ {% block content %} {{ block.super }} -

{% blocktrans with full_name=user.get_full_name %}User {{ full_name }}{% endblocktrans %}

+

{% blocktrans with full_name=user.get_full_name %}User: {{ full_name }}{% endblocktrans %}

@@ -104,7 +104,7 @@

{% trans "Contact Information" %}

-

{% trans "Product Type Membership" %}

+

{% trans "Product Types this User can access" %}

  @@ -170,14 +170,14 @@

{% trans "Product Type Membership" %}

{% else %}
- {% trans "No product type members found." %} + {% trans "This User is not assigned to any Product Types." %}
{% endif %}
-

{% trans "Product Membership" %}

+

{% trans "Products this User can access" %}

  @@ -243,7 +243,7 @@

{% trans "Product Membership" %}

{% else %}
- {% trans "No product members found." %} + {% trans "This User is not assigned to any Products." %}
{% endif %}
@@ -251,7 +251,7 @@

{% trans "Product Membership" %}

-

{% trans "Group Membership" %}

+

{% trans "Groups this User is a member of" %}

  @@ -280,7 +280,7 @@

{% trans "Group Membership" %}

{% trans "Group" %} - {% trans "Group role" %} + {% trans "Role in this Group" %} @@ -317,7 +317,7 @@

{% trans "Group Membership" %}

{% else %}
- {% trans "No group members found." %} + {% trans "This User is not a member of any Groups." %}
{% endif %}
From a004bea6e77dc461ee580ff17370a11f386e158b Mon Sep 17 00:00:00 2001 From: dogboat Date: Fri, 2 Aug 2024 16:42:22 -0400 Subject: [PATCH 4/7] report-builder-sort-fixes Fix report builder finding and endpoints widgets (#10650) * report-builder-sort-fixes Fix report builder finding and endpoints widgets to properly handle pagination and column sorting/ordering (no longer refreshes page, losing work) * report-builder-sort-fixes consolidate handlers for finding pagination/sort * report-builder-sort-fixes fix bottom pagination on findings/endpoints widgets --- dojo/filters.py | 11 ++++ dojo/reports/views.py | 2 +- dojo/templates/dojo/report_builder.html | 75 +++++++++++++++-------- dojo/templates/dojo/report_endpoints.html | 4 +- dojo/templates/dojo/report_findings.html | 2 +- 5 files changed, 63 insertions(+), 31 deletions(-) diff --git a/dojo/filters.py b/dojo/filters.py index 9d3a94a43d0..2261daff714 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -2896,6 +2896,17 @@ class ReportFindingFilterHelper(FilterSet): outside_of_sla = FindingSLAFilter(label="Outside of SLA") file_path = CharFilter(lookup_expr='icontains') + o = OrderingFilter( + fields=( + ('title', 'title'), + ('date', 'date'), + ('numerical_severity', 'numerical_severity'), + ('epss_score', 'epss_score'), + ('epss_percentile', 'epss_percentile'), + ('test__engagement__product__name', 'test__engagement__product__name'), + ), + ) + class Meta: model = Finding # exclude sonarqube issue as by default it will show all without checking permissions diff --git a/dojo/reports/views.py b/dojo/reports/views.py index 6ef139a2397..672ee0add19 100644 --- a/dojo/reports/views.py +++ b/dojo/reports/views.py @@ -175,7 +175,7 @@ def report_findings(request): title_words = get_words_for_field(Finding, 'title') component_words = get_words_for_field(Finding, 'component_name') - paged_findings = get_page_items(request, findings.qs.distinct().order_by('numerical_severity'), 25) + paged_findings = get_page_items(request, findings.qs.distinct(), 25) return render(request, 'dojo/report_findings.html', diff --git a/dojo/templates/dojo/report_builder.html b/dojo/templates/dojo/report_builder.html index bdaf4768e9f..5efbe164b17 100644 --- a/dojo/templates/dojo/report_builder.html +++ b/dojo/templates/dojo/report_builder.html @@ -272,52 +272,73 @@

Available Widgets

.selectpicker('render'); } - $(document).on('submit', 'form.finding-list', function (event) { - var form = this; - $.get("{% url 'report_findings' %}?" + $(this).serialize()).done(function (data) { + // Retrieves (report) data at the given url and inserts it as HTMl into $targetEl, and configures filters + // on the returned data. + function retrieveReportData(url, $targetEl) { + $.get(url).done(function (data) { filterFieldInit( - $(form).closest('li.finding-list').html(data) + $targetEl.html(data) ); setUpFindingFilters(); }); + } + + // -------- + // Findings + // -------- + // "Apply Filters" + $(document).on('submit', 'form.finding-list', function (event) { + const $form = $(this); event.preventDefault(); + retrieveReportData( + "{% url 'report_findings' %}?" + $form.serialize(), + $form.closest('li.finding-list') + ); }); - $(document).on('click', 'form.finding-list a.clear.centered, div.finding-pagination a', function (event) { - $.get("{% url 'report_findings' %}").done(function (data) { - filterFieldInit( - $('div.in-use-widgets li.finding-list').html(data) - ); - setUpFindingFilters(); - }); + // "Clear filters" + $(document).on('click', 'form.finding-list a.clear.centered', function (event) { + const $a = $(this); + event.preventDefault(); + retrieveReportData("{% url 'report_findings' %}", $a.closest('li.finding-list')); + }); + // Sort/order columns and Pagination + $(document).on('click', 'li.finding-list th a, div.finding-pagination a', function (event) { + const $a = $(this); event.preventDefault(); + retrieveReportData("{% url 'report_findings' %}" + $a.attr('href'), $a.closest('li.finding-list')); }); - $(document).on('submit', 'form.endpoint-list', function (event) { - var form = this; - $.get("{% url 'report_endpoints' %}?" + $(this).serialize()).done(function (data) { - filterFieldInit( - $(form).closest('li.endpoint-list').html(data) - ); - setUpFindingFilters(); - }); + /// -------- + // Endpoints + // --------- + // "Apply filters" + $(document).on('submit', 'form.endpoint-list', function (event) { + const $form = $(this); event.preventDefault(); + retrieveReportData( + "{% url 'report_endpoints' %}?" + $form.serialize(), + $form.closest('li.endpoint-list') + ); }); - $(document).on('click', 'form.endpoint-list a.clear.centered, div.endpoint-pagination a', function (event) { - $.get("{% url 'report_endpoints' %}").done(function (data) { - filterFieldInit( - $('div.in-use-widgets li.endpoint-list').html(data) - ); - setUpFindingFilters(); - }); - + // "Clear filters" + $(document).on('click', 'form.endpoint-list a.clear.centered', function (event) { + const $a = $(this); event.preventDefault(); + retrieveReportData("{% url 'report_endpoints' %}", $a.closest('li.endpoint-list')); }); + // Pagination + $(document).on('click', 'div.endpoint-pagination a', function (event) { + const $a = $(this); + event.preventDefault(); + retrieveReportData("{% url 'report_endpoints' %}" + $a.attr('href'), $a.closest('li.endpoint-list')); + }) + $('[data-toggle="tooltip"]').tooltip() $(document).on('click', '.in-use-widgets .panel-available-widget .panel-heading', function (event) { diff --git a/dojo/templates/dojo/report_endpoints.html b/dojo/templates/dojo/report_endpoints.html index b3c434f2626..07fac4e156e 100644 --- a/dojo/templates/dojo/report_endpoints.html +++ b/dojo/templates/dojo/report_endpoints.html @@ -47,8 +47,8 @@
Filters
-
- {% include "dojo/paging_snippet.html" with page=findings page_size=False %} +
+ {% include "dojo/paging_snippet.html" with page=endpoints page_size=False %}
{% endif %} diff --git a/dojo/templates/dojo/report_findings.html b/dojo/templates/dojo/report_findings.html index 6f1e5c3b7fe..c593e457f89 100644 --- a/dojo/templates/dojo/report_findings.html +++ b/dojo/templates/dojo/report_findings.html @@ -62,7 +62,7 @@
Filters
-
+
{% include "dojo/paging_snippet.html" with page=findings page_size=False %}
From 42dabca8869d396cff4475902f0782b6e09ebf7a Mon Sep 17 00:00:00 2001 From: Charles Neill <1749665+cneill@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:43:27 -0500 Subject: [PATCH 5/7] Adding test to check for invalid parser names (#10656) --- unittests/test_factory.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/unittests/test_factory.py b/unittests/test_factory.py index 0b77643ad8f..e174cc8d39a 100644 --- a/unittests/test_factory.py +++ b/unittests/test_factory.py @@ -1,3 +1,8 @@ +import os +from importlib import import_module +from importlib.util import find_spec +from inspect import isclass + from dojo.models import Test, Test_Type from dojo.tools.factory import get_parser @@ -53,3 +58,23 @@ def test_get_parser_test_active_in_db(self): ) parser = get_parser(scan_type) self.assertIsNotNone(parser) + + def test_parser_name_matches_module(self): + """Test to ensure that parsers' class names match their module names""" + package_dir = "dojo/tools" + module_names = os.listdir(package_dir) + missing_parsers = [] + for module_name in module_names: + if os.path.isdir(os.path.join(package_dir, module_name)): + found = False + if find_spec(f"dojo.tools.{module_name}.parser"): + module = import_module(f"dojo.tools.{module_name}.parser") + for attribute_name in dir(module): + attribute = getattr(module, attribute_name) + if isclass(attribute) and attribute_name.lower() == module_name.replace("_", "") + "parser": + found = True + if not found and module_name != "__pycache__": + missing_parsers.append(module_name) + if len(missing_parsers) > 0: + print(f"Parsers with invalid names: {missing_parsers}") + self.assertEqual(0, len(missing_parsers)) From d443d07d3a16a318e0f5ea7346b737bca88c860a Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:13:00 -0500 Subject: [PATCH 6/7] Correct ruff --- dojo/__init__.py | 6 +++--- dojo/filters.py | 12 ++++++------ unittests/test_factory.py | 6 ++++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dojo/__init__.py b/dojo/__init__.py index 707177ee3ee..a31f5294e23 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa: F401 -__version__ = '2.37.0-dev' -__url__ = 'https://github.com/DefectDojo/django-DefectDojo' -__docs__ = 'https://documentation.defectdojo.com' +__version__ = "2.37.0-dev" +__url__ = "https://github.com/DefectDojo/django-DefectDojo" +__docs__ = "https://documentation.defectdojo.com" diff --git a/dojo/filters.py b/dojo/filters.py index 1355b701477..9916ac31e21 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -2888,12 +2888,12 @@ class ReportFindingFilterHelper(FilterSet): o = OrderingFilter( fields=( - ('title', 'title'), - ('date', 'date'), - ('numerical_severity', 'numerical_severity'), - ('epss_score', 'epss_score'), - ('epss_percentile', 'epss_percentile'), - ('test__engagement__product__name', 'test__engagement__product__name'), + ("title", "title"), + ("date", "date"), + ("numerical_severity", "numerical_severity"), + ("epss_score", "epss_score"), + ("epss_percentile", "epss_percentile"), + ("test__engagement__product__name", "test__engagement__product__name"), ), ) diff --git a/unittests/test_factory.py b/unittests/test_factory.py index e174cc8d39a..7e98de4eb9a 100644 --- a/unittests/test_factory.py +++ b/unittests/test_factory.py @@ -1,3 +1,4 @@ +import logging import os from importlib import import_module from importlib.util import find_spec @@ -5,8 +6,9 @@ from dojo.models import Test, Test_Type from dojo.tools.factory import get_parser +from unittests.dojo_test_case import DojoTestCase, get_unit_tests_path -from .dojo_test_case import DojoTestCase, get_unit_tests_path +logger = logging.getLogger(__name__) class TestFactory(DojoTestCase): @@ -76,5 +78,5 @@ def test_parser_name_matches_module(self): if not found and module_name != "__pycache__": missing_parsers.append(module_name) if len(missing_parsers) > 0: - print(f"Parsers with invalid names: {missing_parsers}") + logger.error(f"Parsers with invalid names: {missing_parsers}") self.assertEqual(0, len(missing_parsers)) From 3fd43db8bca50749adf705c783c3258b65502a40 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:32:51 -0500 Subject: [PATCH 7/7] Update parser module test --- unittests/test_factory.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/unittests/test_factory.py b/unittests/test_factory.py index 7e98de4eb9a..31e793e03e7 100644 --- a/unittests/test_factory.py +++ b/unittests/test_factory.py @@ -66,7 +66,12 @@ def test_parser_name_matches_module(self): package_dir = "dojo/tools" module_names = os.listdir(package_dir) missing_parsers = [] + excluded_parsers = [ + "wizcli_common_parsers", # common class for other wizcli parsers, there is not parsing here + ] for module_name in module_names: + if module_name in excluded_parsers: + continue if os.path.isdir(os.path.join(package_dir, module_name)): found = False if find_spec(f"dojo.tools.{module_name}.parser"):