From 4728bd4d95209d0ad154ca428a678c44974b0cca Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 7 Oct 2024 15:40:29 +0000 Subject: [PATCH 01/16] Update versions in application files --- components/package.json | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/package.json b/components/package.json index ca4351fe41e..06cdce1889b 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.39.0", + "version": "2.40.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index b1927a7074a..4f2c96ba0fa 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.39.0" +appVersion: "2.40.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.153 +version: 1.6.154-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 67d87e74fe7a66a5578b4b68e68c9093a05dd30c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 18:09:07 -0500 Subject: [PATCH 02/16] Bump django from 5.0.8 to 5.0.9 (#11023) Bumps [django](https://github.com/django/django) from 5.0.8 to 5.0.9. - [Commits](https://github.com/django/django/compare/5.0.8...5.0.9) --- updated-dependencies: - dependency-name: django dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 79d2844fc8f..524c0c9f09f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,7 +21,7 @@ django-slack==5.19.0 git+https://github.com/DefectDojo/django-tagging@develop#egg=django-tagging django-watson==1.6.3 django-prometheus==2.3.1 -Django==5.0.8 +Django==5.0.9 djangorestframework==3.15.2 html2text==2024.2.26 humanize==4.10.0 From 5985567f7d9fd9b615d2e3fc09fd2a6feb54226c Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:01:48 -0500 Subject: [PATCH 03/16] Downgrade uwsgi to 2.0.26 (#11033) Hot reloading appears to be broken in. 2.0.27. The linked GitHub issue is the same behavior that I am seeing https://github.com/unbit/uwsgi/issues/2681 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 524c0c9f09f..a2ffb14422f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ redis==5.1.0 requests==2.32.3 sqlalchemy==2.0.35 # Required by Celery broker transport urllib3==1.26.18 -uWSGI==2.0.27 +uWSGI==2.0.26 vobject==0.9.8 whitenoise==5.2.0 titlecase==2.4.1 From 316d61acc3db15cd43d4159cb86156fc3a7a8d33 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:02:07 -0500 Subject: [PATCH 04/16] New Jira Form: Make express the default (#11041) * New Jira Form: Make express the default * rename some stuff * ruff * correct tests --- dojo/forms.py | 7 +++++-- dojo/jira_link/urls.py | 3 ++- dojo/jira_link/views.py | 24 +++++++++++----------- dojo/templates/dojo/express_new_jira.html | 16 --------------- dojo/templates/dojo/jira.html | 8 ++++---- dojo/templates/dojo/new_jira.html | 7 +++++-- dojo/templates/dojo/new_jira_advanced.html | 13 ++++++++++++ unittests/test_jira_config_product.py | 2 +- 8 files changed, 42 insertions(+), 38 deletions(-) delete mode 100644 dojo/templates/dojo/express_new_jira.html create mode 100644 dojo/templates/dojo/new_jira_advanced.html diff --git a/dojo/forms.py b/dojo/forms.py index 1dd52671c45..9869af62709 100644 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -2425,7 +2425,7 @@ def clean(self): return self.cleaned_data -class JIRAForm(BaseJiraForm): +class AdvancedJIRAForm(BaseJiraForm): issue_template_dir = forms.ChoiceField(required=False, choices=JIRA_TEMPLATE_CHOICES, help_text="Choose the folder containing the Django templates used to render the JIRA issue description. These are stored in dojo/templates/issue-trackers. Leave empty to use the default jira_full templates.") @@ -2445,8 +2445,11 @@ class Meta: exclude = [""] -class ExpressJIRAForm(BaseJiraForm): +class JIRAForm(BaseJiraForm): issue_key = forms.CharField(required=True, help_text="A valid issue ID is required to gather the necessary information.") + issue_template_dir = forms.ChoiceField(required=False, + choices=JIRA_TEMPLATE_CHOICES, + help_text="Choose the folder containing the Django templates used to render the JIRA issue description. These are stored in dojo/templates/issue-trackers. Leave empty to use the default jira_full templates.") class Meta: model = JIRA_Instance diff --git a/dojo/jira_link/urls.py b/dojo/jira_link/urls.py index 84abc6faef6..97295ddea49 100644 --- a/dojo/jira_link/urls.py +++ b/dojo/jira_link/urls.py @@ -8,7 +8,8 @@ re_path(r"^jira/webhook/(?P[\w-]+)$", views.webhook, name="jira_web_hook_secret"), re_path(r"^jira/webhook/", views.webhook, name="jira_web_hook"), re_path(r"^jira/add", views.NewJiraView.as_view(), name="add_jira"), + re_path(r"^jira/advanced", views.AdvancedJiraView.as_view(), name="add_jira_advanced"), re_path(r"^jira/(?P\d+)/edit$", views.EditJiraView.as_view(), name="edit_jira"), re_path(r"^jira/(?P\d+)/delete$", views.DeleteJiraView.as_view(), name="delete_jira"), re_path(r"^jira$", views.ListJiraView.as_view(), name="jira"), - re_path(r"^jira/express", views.ExpressJiraView.as_view(), name="express_jira")] +] diff --git a/dojo/jira_link/views.py b/dojo/jira_link/views.py index 7ab70a1f5a4..0461f600dee 100644 --- a/dojo/jira_link/views.py +++ b/dojo/jira_link/views.py @@ -22,7 +22,7 @@ from dojo.authorization.authorization import user_has_configuration_permission # Local application/library imports -from dojo.forms import DeleteJIRAInstanceForm, ExpressJIRAForm, JIRAForm +from dojo.forms import AdvancedJIRAForm, DeleteJIRAInstanceForm, JIRAForm from dojo.models import JIRA_Instance, JIRA_Issue, Notes, System_Settings, User from dojo.notifications.helper import create_notification from dojo.utils import add_breadcrumb, add_error_message_to_response, get_setting @@ -285,24 +285,24 @@ def get_custom_field(jira, label): return field -class ExpressJiraView(View): +class NewJiraView(View): def get_template(self): - return "dojo/express_new_jira.html" + return "dojo/new_jira.html" def get_fallback_template(self): - return "dojo/new_jira.html" + return "dojo/new_jira_advanced.html" def get_form_class(self): - return ExpressJIRAForm + return JIRAForm def get_fallback_form_class(self): - return JIRAForm + return AdvancedJIRAForm def get(self, request): if not user_has_configuration_permission(request.user, "dojo.add_jira_instance"): raise PermissionDenied jform = self.get_form_class()() - add_breadcrumb(title="New Jira Configuration (Express)", top_level=False, request=request) + add_breadcrumb(title="New Jira Configuration", top_level=False, request=request) return render(request, self.get_template(), {"jform": jform}) def post(self, request): @@ -391,18 +391,18 @@ def post(self, request): return render(request, self.get_template(), {"jform": jform}) -class NewJiraView(View): +class AdvancedJiraView(View): def get_template(self): - return "dojo/new_jira.html" + return "dojo/new_jira_advanced.html" def get_form_class(self): - return JIRAForm + return AdvancedJIRAForm def get(self, request): if not user_has_configuration_permission(request.user, "dojo.add_jira_instance"): raise PermissionDenied jform = self.get_form_class()() - add_breadcrumb(title="New Jira Configuration", top_level=False, request=request) + add_breadcrumb(title="New Jira Configuration (Advanced)", top_level=False, request=request) return render(request, self.get_template(), {"jform": jform}) def post(self, request): @@ -442,7 +442,7 @@ def get_template(self): return "dojo/edit_jira.html" def get_form_class(self): - return JIRAForm + return AdvancedJIRAForm def get(self, request, jid=None): if not user_has_configuration_permission(request.user, "dojo.change_jira_instance"): diff --git a/dojo/templates/dojo/express_new_jira.html b/dojo/templates/dojo/express_new_jira.html deleted file mode 100644 index 4394c5d6bbc..00000000000 --- a/dojo/templates/dojo/express_new_jira.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html"%} -{% block content %} - {{ block.super }} -

Add a JIRA Configuration Express

-
{% csrf_token %} - {% include "dojo/form_fields.html" with form=jform %} -
-
- -
-

- Finding severity mappings and other options can be edited after express configuration is complete. -
-
-
-{% endblock %} diff --git a/dojo/templates/dojo/jira.html b/dojo/templates/dojo/jira.html index a3208648d64..1068cf7c4ca 100644 --- a/dojo/templates/dojo/jira.html +++ b/dojo/templates/dojo/jira.html @@ -19,13 +19,13 @@

diff --git a/dojo/templates/dojo/new_jira.html b/dojo/templates/dojo/new_jira.html index 232117681cb..6f4cb6e055e 100644 --- a/dojo/templates/dojo/new_jira.html +++ b/dojo/templates/dojo/new_jira.html @@ -6,8 +6,11 @@

Add a JIRA Configuration

{% include "dojo/form_fields.html" with form=jform %}
- + +
+

+ Finding severity mappings and other options can be edited after configuration is complete.
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/dojo/templates/dojo/new_jira_advanced.html b/dojo/templates/dojo/new_jira_advanced.html new file mode 100644 index 00000000000..2af3a37c600 --- /dev/null +++ b/dojo/templates/dojo/new_jira_advanced.html @@ -0,0 +1,13 @@ +{% extends "base.html"%} +{% block content %} + {{ block.super }} +

Add a JIRA Configuration (Advanced)

+
{% csrf_token %} + {% include "dojo/form_fields.html" with form=jform %} +
+
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/unittests/test_jira_config_product.py b/unittests/test_jira_config_product.py index ff72f34993a..7213a2f5f00 100644 --- a/unittests/test_jira_config_product.py +++ b/unittests/test_jira_config_product.py @@ -49,7 +49,7 @@ def setUp(self): @patch("dojo.jira_link.views.jira_helper.get_jira_connection_raw") def add_jira_instance(self, data, jira_mock): - response = self.client.post(reverse("add_jira"), urlencode(data), content_type="application/x-www-form-urlencoded") + response = self.client.post(reverse("add_jira_advanced"), urlencode(data), content_type="application/x-www-form-urlencoded") # check that storing a new config triggers a login call to JIRA call_1 = call(data["url"], data["username"], data["password"]) call_2 = call(data["url"], data["username"], data["password"]) From d56964f4fd1938f194a1673b2c9a9553d00b5540 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:02:20 -0500 Subject: [PATCH 05/16] AWS Security Hub: Accommodate for reports with missing AccountID (#11034) --- dojo/tools/awssecurityhub/parser.py | 2 +- .../awssecurityhub/missing_account_id.json | 112 ++++++++++++++++++ unittests/tools/test_awssecurityhub_parser.py | 6 + 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 unittests/scans/awssecurityhub/missing_account_id.json diff --git a/dojo/tools/awssecurityhub/parser.py b/dojo/tools/awssecurityhub/parser.py index 3d07d2554c7..e59afa23ce3 100644 --- a/dojo/tools/awssecurityhub/parser.py +++ b/dojo/tools/awssecurityhub/parser.py @@ -28,7 +28,7 @@ def get_tests(self, scan_type, scan): aws_acc = [] for finding in findings: prod.append(finding.get("ProductName", "AWS Security Hub Ruleset")) - aws_acc.append(finding.get("AwsAccountId")) + aws_acc.append(finding.get("AwsAccountId", "No Account Found")) report_date = data.get("createdAt") test = ParserTest( name=self.ID, type=self.ID, version="", diff --git a/unittests/scans/awssecurityhub/missing_account_id.json b/unittests/scans/awssecurityhub/missing_account_id.json new file mode 100644 index 00000000000..fe7ddfc2e94 --- /dev/null +++ b/unittests/scans/awssecurityhub/missing_account_id.json @@ -0,0 +1,112 @@ +{ + "findings": [ + { + "EpssScore": "0.00239", + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:inspector2:us-east-1:1234567:finding/12344bc", + "ProductArn": "arn:aws:securityhub:us-east-1::product/aws/inspector", + "ProductName": "Inspector", + "CompanyName": "Amazon", + "Region": "us-east-1", + "GeneratorId": "AWSInspector", + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE" + ], + "FirstObservedAt": "2024-07-30T12:17:32.646Z", + "LastObservedAt": "2024-09-18T05:16:44.106Z", + "CreatedAt": "2024-07-30T12:17:32.646Z", + "UpdatedAt": "2024-09-18T05:16:44.106Z", + "Severity": { + "Label": "MEDIUM", + "Normalized": 50 + }, + "Title": "CVE-2024-123 - fdd", + "Description": "A vulnerability was found in sdd.", + "Remediation": { + "Recommendation": { + "Text": "None Provided" + } + }, + "ProductFields": { + "aws/inspector/FindingStatus": "ACTIVE", + "aws/inspector/inspectorScore": "5.1", + "aws/inspector/resources/1/resourceDetails/awsEc2InstanceDetails/platform": "AMAZON_LINUX_2023", + "aws/inspector/ProductVersion": "1", + "aws/inspector/instanceId": "i-1234xxyy", + "aws/securityhub/FindingId": "arn:aws:inspector2:us-east-1:1234567:finding/addfss", + "aws/securityhub/ProductName": "Inspector", + "aws/securityhub/CompanyName": "Amazon" + }, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": "i-1234xxyy", + "Partition": "aws", + "Region": "us-east-1", + "Tags": { + "Name": "Name:xx-123-yy" + }, + "Details": { + "AwsEc2Instance": { + "Type": "tt", + "ImageId": "ami-1234", + "IpV4Addresses": [ + "0.0.0.0" + ], + "IamInstanceProfileArn": "arn:aws:iam::1234567:instance-profile/something", + "VpcId": "vpc-1234", + "SubnetId": "subnet-xxxxxxx", + "LaunchedAt": "2024-09-18T05:16:44.106Z" + } + } + } + ], + "WorkflowState": "NEW", + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE", + "Vulnerabilities": [ + { + "Id": "CVE-2024-1234", + "VulnerablePackages": [ + { + "Name": "aa", + "Version": "1.2.0", + "Architecture": "X86_64]", + "PackageManager": "OS", + "FixedInVersion": "abc[2.0]" + } + ], + "Cvss": [ + { + "Version": "3.1", + "BaseScore": "7.5", + "BaseVector": "CVSS:9.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N", + "Source": "NVD" + } + ], + "Vendor": { + "Name": "AMAZON_CVE", + "Url": "https://alas.aws.amazon.com/cve/json/v1/CVE-2024-1234.json", + "VendorSeverity": "Medium", + "VendorCreatedAt": "2024-01-16T00:00:00Z", + "VendorUpdatedAt": "2024-09-18T05:16:44.106Z" + }, + "ReferenceUrls": [ + "https://alas.aws.amazon.com" + ], + "FixAvailable": "YES" + } + ], + "FindingProviderFields": { + "Severity": { + "Label": "MEDIUM" + }, + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE" + ] + } + } + ] + } \ No newline at end of file diff --git a/unittests/tools/test_awssecurityhub_parser.py b/unittests/tools/test_awssecurityhub_parser.py index 9d05083eaff..5885852b348 100644 --- a/unittests/tools/test_awssecurityhub_parser.py +++ b/unittests/tools/test_awssecurityhub_parser.py @@ -134,3 +134,9 @@ def test_issue_10956(self): self.assertEqual(1, len(findings)) finding = findings[0] self.assertEqual("0.00239", finding.epss_score) + + def test_missing_account_id(self): + with open(get_unit_tests_path() + sample_path("missing_account_id.json"), encoding="utf-8") as test_file: + parser = AwsSecurityHubParser() + findings = parser.get_findings(test_file, Test()) + self.assertEqual(1, len(findings)) From 51557ec03817a7e90138c1d1e782b57be609c39c Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:02:37 -0500 Subject: [PATCH 06/16] Netsparker: Attempt to accommodate any date string format (#11047) --- dojo/tools/netsparker/parser.py | 23 +- unittests/scans/netsparker/issue_11020.json | 227 ++++++++++++++++++++ unittests/tools/test_netsparker_parser.py | 14 ++ 3 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 unittests/scans/netsparker/issue_11020.json diff --git a/dojo/tools/netsparker/parser.py b/dojo/tools/netsparker/parser.py index 35a08920542..47b81a2a65b 100644 --- a/dojo/tools/netsparker/parser.py +++ b/dojo/tools/netsparker/parser.py @@ -3,6 +3,7 @@ import html2text from cvss import parser as cvss_parser +from dateutil import parser as date_parser from dojo.models import Endpoint, Finding @@ -24,14 +25,20 @@ def get_findings(self, filename, test): except Exception: data = json.loads(tree) dupes = {} - if "UTC" in data["Generated"]: - scan_date = datetime.datetime.strptime( - data["Generated"].split(" ")[0], "%d/%m/%Y", - ).date() - else: - scan_date = datetime.datetime.strptime( - data["Generated"], "%d/%m/%Y %H:%M %p", - ).date() + try: + if "UTC" in data["Generated"]: + scan_date = datetime.datetime.strptime( + data["Generated"].split(" ")[0], "%d/%m/%Y", + ).date() + else: + scan_date = datetime.datetime.strptime( + data["Generated"], "%d/%m/%Y %H:%M %p", + ).date() + except ValueError: + try: + scan_date = date_parser.parse(data["Generated"]) + except date_parser.ParserError: + scan_date = None for item in data["Vulnerabilities"]: title = item["Name"] diff --git a/unittests/scans/netsparker/issue_11020.json b/unittests/scans/netsparker/issue_11020.json new file mode 100644 index 00000000000..1c54c7a995e --- /dev/null +++ b/unittests/scans/netsparker/issue_11020.json @@ -0,0 +1,227 @@ +{ + "Generated": "2024-10-08 02:33 PM", + "Target": { + "Duration": "00:00:38.3663144", + "Initiated": "2024-10-08 12:33 PM", + "ScanId": "93d4edbae56145ef001ab203020d164c", + "Url": "http://php.testsparker.com/auth/login.php" + }, + "Vulnerabilities": [ + { + "Certainty": 90, + "Classification": { + "Iso27001": "A.18.1.3", + "Capec": "170", + "Cvss": null, + "Cvss31": null, + "Cvss40": null, + "Cwe": "205", + "Hipaa": "164.306(a), 164.308(a)", + "Owasp": "A5", + "OwaspProactiveControls": "", + "Pci32": "", + "Wasc": "13", + "Asvs40": "14.3.3", + "Nistsp80053": "AC-22", + "DisaStig": "V-16814", + "OwaspApiTop10": "API7", + "OwaspTopTen2021": "A05", + "OwaspTopTen2023": "API8", + "PciDss40": "" + }, + "Confirmed": false, + "Description": "

Invicti Enterprise identified a version disclosure (PHP) in the target web server's HTTP response.

\n

This information can help an attacker gain a greater understanding of the systems in use and potentially develop further attacks targeted at the specific version of PHP.

", + "ExploitationSkills": "", + "ExternalReferences": "", + "ExtraInformation": [ + { + "Name": "Extracted Version", + "Value": "5.2.6" + } + ], + "FirstSeenDate": "2024-07-23 05:32 PM", + "HttpRequest": { + "Content": "GET /auth/login.php HTTP/1.1\r\nHost: php.testsparker.com\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nCookie: PHPSESSID=e6ab62571859a3d766d49945296f081d\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.140 Safari/537.36\r\n\r\n", + "Method": "GET", + "Parameters": [] + }, + "HttpResponse": { + "Content": "HTTP/1.1 200 OK\r\nServer: Apache/2.2.8 (Win32) PHP/5.2.6\r\nContent-Length: 3058\r\nX-Powered-By: PHP/5.2.6\r\nPragma: no-cache\r\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\r\nKeep-Alive: timeout=5, max=150\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nDate: Tue, 08 Oct 2024 09:37:09 GMT\r\nCache-Control: no-store, must-revalidate, no-cache, post-check=0, pre-check=0\r\n\r\n\n\n\n\n\n\n\nInvicti Test Web Site - PHP\n\n\n
\n \n\t
\n\t\t\n\t
\n\t\n\t
\n\n\t
\n\t\t
\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t\t\t\t\t

Login Area

\n\t\t\t\t\t

\n Enter your credentials (admin / admin123456)\n
\n

\n Username: \n
\n Password:  \n\n\n
\n\t \n
\n \n
\n

\n\n\t\t\t\t
 
\n\t\t\t\t
\n\n\n\t\t\t\t
\n\t\t\t
\n\t\t
 
\n\t\t
\n\t\t\n\t \n\t
\n\t\t\t
    \n\t\t\t\t
  • \n\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\t
    \n\t\t\t\t\t
     
    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Tags

    \n\t\t\t\t\t

    netsparker xss web-application-security false-positive-free automated-exploitation sql-injection local/remote-file-inclusion

    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Inner Pages

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Links

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\n\t\t\t
\n\t\t
\t\t\n\t\t
 
\n\t
\n\t
\n\t
\n\t\n
\nv\n
\n\t\t

Copyright (c) 2010 testsparker.com. All rights reserved. Design by Free CSS Templates.

\n\t
\t\n\n\n", + "Duration": 458.7166, + "StatusCode": 200 + }, + "LookupId": "bfc0a79b-e3dc-45af-0195-b1a1030bc008", + "Impact": "
An attacker might use the disclosed information to harvest specific security vulnerabilities for the version identified.
", + "KnownVulnerabilities": [], + "LastSeenDate": "2024-10-08 12:37 PM", + "Name": "Version Disclosure (PHP)", + "ProofOfConcept": "", + "RemedialActions": "", + "RemedialProcedure": "
Configure your web server to prevent information leakage from the SERVER header of its HTTP response.
", + "RemedyReferences": "", + "Severity": "Low", + "State": "Present, Scanning", + "Type": "PhpVersionDisclosure", + "Url": "http://php.testsparker.com/auth/login.php", + "Tags": [] + }, + { + "Certainty": 90, + "Classification": { + "Iso27001": "A.14.1.2", + "Capec": "310", + "Cvss": null, + "Cvss31": null, + "Cvss40": null, + "Cwe": "1035, 937", + "Hipaa": "164.308(a)(1)(i)", + "Owasp": "A9", + "OwaspProactiveControls": "C1", + "Pci32": "6.2", + "Wasc": "", + "Asvs40": "1.14.3", + "Nistsp80053": "CM-6", + "DisaStig": "V-16836", + "OwaspApiTop10": "", + "OwaspTopTen2021": "A06", + "OwaspTopTen2023": "API8", + "PciDss40": "6.3.3" + }, + "Confirmed": false, + "Description": "

Invicti Enterprise identified you are using an out-of-date version of Apache.

", + "ExploitationSkills": "", + "ExternalReferences": "", + "ExtraInformation": [ + { + "Name": "Identified Version", + "Value": "2.2.8" + }, + { + "Name": "Latest Version", + "Value": "2.2.34 (in this branch)" + }, + { + "Name": "Overall Latest Version", + "Value": "2.4.62" + }, + { + "Name": "Branch Status", + "Value": "This branch has stopped receiving updates since 7/11/2017." + }, + { + "Name": "Vulnerability Database", + "Value": "Result is based on 10/01/2024 18:00:00 vulnerability database content." + } + ], + "FirstSeenDate": "2024-07-23 05:32 PM", + "HttpRequest": { + "Content": "GET /auth/login.php HTTP/1.1\r\nHost: php.testsparker.com\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nCookie: PHPSESSID=e6ab62571859a3d766d49945296f081d\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.140 Safari/537.36\r\n\r\n", + "Method": "GET", + "Parameters": [] + }, + "HttpResponse": { + "Content": "HTTP/1.1 200 OK\r\nServer: Apache/2.2.8 (Win32) PHP/5.2.6\r\nContent-Length: 3058\r\nX-Powered-By: PHP/5.2.6\r\nPragma: no-cache\r\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\r\nKeep-Alive: timeout=5, max=150\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nDate: Tue, 08 Oct 2024 09:37:09 GMT\r\nCache-Control: no-store, must-revalidate, no-cache, post-check=0, pre-check=0\r\n\r\n\n\n\n\n\n\n\nInvicti Test Web Site - PHP\n\n\n
\n \n\t
\n\t\t\n\t
\n\t\n\t
\n\n\t
\n\t\t
\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t\t\t\t\t

Login Area

\n\t\t\t\t\t

\n Enter your credentials (admin / admin123456)\n
\n

\n Username: \n
\n Password:  \n\n\n
\n\t \n
\n \n
\n

\n\n\t\t\t\t
 
\n\t\t\t\t
\n\n\n\t\t\t\t
\n\t\t\t
\n\t\t
 
\n\t\t
\n\t\t\n\t \n\t
\n\t\t\t
    \n\t\t\t\t
  • \n\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\t
    \n\t\t\t\t\t
     
    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Tags

    \n\t\t\t\t\t

    netsparker xss web-application-security false-positive-free automated-exploitation sql-injection local/remote-file-inclusion

    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Inner Pages

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Links

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\n\t\t\t
\n\t\t
\t\t\n\t\t
 
\n\t
\n\t
\n\t
\n\t\n
\nv\n
\n\t\t

Copyright (c) 2010 testsparker.com. All rights reserved. Design by Free CSS Templates.

\n\t
\t\n\n\n", + "Duration": 458.7166, + "StatusCode": 200 + }, + "LookupId": "e3f86681-1ae6-49e8-0186-b1a1030bbbb1", + "Impact": "
Since this is an old version of the software, it may be vulnerable to attacks.
", + "KnownVulnerabilities": [ + { + "Severity": "Critical", + "Title": "Apache HTTP Server Out-of-bounds Read Vulnerability" + } + ], + "LastSeenDate": "2024-10-08 12:37 PM", + "Name": "Out-of-date Version (Apache)", + "ProofOfConcept": "", + "RemedialActions": "", + "RemedialProcedure": "
\n

Please upgrade your installation of Apache to the latest stable version.

\n
", + "RemedyReferences": "", + "Severity": "Critical", + "State": "Present, Scanning", + "Type": "ApacheOutOfDate", + "Url": "http://php.testsparker.com/auth/login.php", + "Tags": [] + }, + { + "Certainty": 90, + "Classification": { + "Iso27001": "A.14.1.2", + "Capec": "310", + "Cvss": null, + "Cvss31": null, + "Cvss40": null, + "Cwe": "1035, 937", + "Hipaa": "164.308(a)(1)(i)", + "Owasp": "A9", + "OwaspProactiveControls": "C1", + "Pci32": "6.2", + "Wasc": "", + "Asvs40": "1.14.3", + "Nistsp80053": "CM-6", + "DisaStig": "V-16836", + "OwaspApiTop10": "", + "OwaspTopTen2021": "A06", + "OwaspTopTen2023": "API8", + "PciDss40": "6.3.3" + }, + "Confirmed": false, + "Description": "

Invicti Enterprise identified you are using an out-of-date version of PHP.

", + "ExploitationSkills": "", + "ExternalReferences": "", + "ExtraInformation": [ + { + "Name": "Identified Version", + "Value": "5.2.6" + }, + { + "Name": "Latest Version", + "Value": "5.2.17 (in this branch)" + }, + { + "Name": "Overall Latest Version", + "Value": "8.3.12" + }, + { + "Name": "Branch Status", + "Value": "This branch has stopped receiving updates since 1/6/2011." + }, + { + "Name": "Vulnerability Database", + "Value": "Result is based on 10/01/2024 18:00:00 vulnerability database content." + } + ], + "FirstSeenDate": "2024-07-23 05:32 PM", + "HttpRequest": { + "Content": "GET /auth/login.php HTTP/1.1\r\nHost: php.testsparker.com\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nCache-Control: no-cache\r\nCookie: PHPSESSID=e6ab62571859a3d766d49945296f081d\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.140 Safari/537.36\r\n\r\n", + "Method": "GET", + "Parameters": [] + }, + "HttpResponse": { + "Content": "HTTP/1.1 200 OK\r\nServer: Apache/2.2.8 (Win32) PHP/5.2.6\r\nContent-Length: 3058\r\nX-Powered-By: PHP/5.2.6\r\nPragma: no-cache\r\nExpires: Thu, 19 Nov 1981 08:52:00 GMT\r\nKeep-Alive: timeout=5, max=150\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nDate: Tue, 08 Oct 2024 09:37:09 GMT\r\nCache-Control: no-store, must-revalidate, no-cache, post-check=0, pre-check=0\r\n\r\n\n\n\n\n\n\n\nInvicti Test Web Site - PHP\n\n\n
\n \n\t
\n\t\t\n\t
\n\t\n\t
\n\n\t
\n\t\t
\n\t
\n\t
\n\t\t
\n\t\t\t
\n\t\t\t\t\t\t\t\t

Login Area

\n\t\t\t\t\t

\n Enter your credentials (admin / admin123456)\n
\n

\n Username: \n
\n Password:  \n\n\n
\n\t \n
\n \n
\n

\n\n\t\t\t\t
 
\n\t\t\t\t
\n\n\n\t\t\t\t
\n\t\t\t
\n\t\t
 
\n\t\t
\n\t\t\n\t \n\t
\n\t\t\t
    \n\t\t\t\t
  • \n\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\t
    \n\t\t\t\t\t
     
    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Tags

    \n\t\t\t\t\t

    netsparker xss web-application-security false-positive-free automated-exploitation sql-injection local/remote-file-inclusion

    \n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Inner Pages

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\t\t\t\t\t

    Links

    \n\t\t\t\t\t\n\t\t\t\t
  • \n\t\t\t\t
  • \n\n\t\t\t
\n\t\t
\t\t\n\t\t
 
\n\t
\n\t
\n\t
\n\t\n
\nv\n
\n\t\t

Copyright (c) 2010 testsparker.com. All rights reserved. Design by Free CSS Templates.

\n\t
\t\n\n\n", + "Duration": 458.7166, + "StatusCode": 200 + }, + "LookupId": "c609abb8-f7c6-4646-0190-b1a1030bbeb1", + "Impact": "
Since this is an old version of the software, it may be vulnerable to attacks.
", + "KnownVulnerabilities": [ + { + "Severity": "Critical", + "Title": "PHP Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') Vulnerability" + } + ], + "LastSeenDate": "2024-10-08 12:37 PM", + "Name": "Out-of-date Version (PHP)", + "ProofOfConcept": "", + "RemedialActions": "", + "RemedialProcedure": "
Please upgrade your installation of PHP to the latest stable version.
", + "RemedyReferences": "", + "Severity": "Critical", + "State": "Present, Scanning", + "Type": "PhpOutOfDate", + "Url": "http://php.testsparker.com/auth/login.php", + "Tags": [] + } + ] +} \ No newline at end of file diff --git a/unittests/tools/test_netsparker_parser.py b/unittests/tools/test_netsparker_parser.py index 55e396205ab..8537686b97b 100644 --- a/unittests/tools/test_netsparker_parser.py +++ b/unittests/tools/test_netsparker_parser.py @@ -96,3 +96,17 @@ def test_parse_file_issue_10311(self): self.assertEqual("High", finding.severity) self.assertEqual(614, finding.cwe) self.assertEqual("03/02/2019", finding.date.strftime("%d/%m/%Y")) + + def test_parse_file_issue_11020(self): + with open("unittests/scans/netsparker/issue_11020.json", encoding="utf-8") as testfile: + parser = NetsparkerParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(3, len(findings)) + for finding in findings: + for endpoint in finding.unsaved_endpoints: + endpoint.clean() + with self.subTest(i=0): + finding = findings[0] + self.assertEqual("Low", finding.severity) + self.assertEqual(205, finding.cwe) + self.assertEqual("08/10/2024", finding.date.strftime("%d/%m/%Y")) From 58aa6baf961571e5e5d44670a0da1114cdbbc16c Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:03:33 -0500 Subject: [PATCH 07/16] Jira: Add toggle to disable an existing project (#11046) * Jira: Add toggle to disable an existing project * Add help text * Add filter for API * Add new form element to tests * update fixtures * Update dojo/jira_link/helper.py Co-authored-by: Charles Neill <1749665+cneill@users.noreply.github.com> --------- Co-authored-by: Charles Neill <1749665+cneill@users.noreply.github.com> --- dojo/api_v2/views.py | 1 + .../0217_jira_project_enabled.py | 18 ++++++++ dojo/fixtures/defect_dojo_sample_data.json | 3 ++ dojo/forms.py | 5 ++- dojo/jira_link/helper.py | 44 +++++++++++++++---- dojo/models.py | 10 ++++- unittests/dojo_test_case.py | 5 +++ unittests/test_jira_config_engagement.py | 6 +++ unittests/test_jira_config_engagement_epic.py | 1 + 9 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 dojo/db_migrations/0217_jira_project_enabled.py diff --git a/dojo/api_v2/views.py b/dojo/api_v2/views.py index 09e7cb734b5..52978f3b241 100644 --- a/dojo/api_v2/views.py +++ b/dojo/api_v2/views.py @@ -1517,6 +1517,7 @@ class JiraProjectViewSet( "jira_instance", "product", "engagement", + "enabled", "component", "project_key", "push_all_issues", diff --git a/dojo/db_migrations/0217_jira_project_enabled.py b/dojo/db_migrations/0217_jira_project_enabled.py new file mode 100644 index 00000000000..6bde35303ba --- /dev/null +++ b/dojo/db_migrations/0217_jira_project_enabled.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.8 on 2024-10-10 17:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dojo', '0216_alter_jira_project_push_all_issues'), + ] + + operations = [ + migrations.AddField( + model_name='jira_project', + name='enabled', + field=models.BooleanField(blank=True, default=True, help_text='When disabled, Findings will no longer be pushed to Jira, even if they have already been pushed previously.', verbose_name='Enable Connection With Jira Project'), + ), + ] diff --git a/dojo/fixtures/defect_dojo_sample_data.json b/dojo/fixtures/defect_dojo_sample_data.json index d9a51e13e2a..2d0ece6cb16 100644 --- a/dojo/fixtures/defect_dojo_sample_data.json +++ b/dojo/fixtures/defect_dojo_sample_data.json @@ -35210,6 +35210,7 @@ "engagement": null, "component": "", "push_all_issues": false, + "enabled": true, "enable_engagement_epic_mapping": true, "push_notes": false, "product_jira_sla_notification": false, @@ -35227,6 +35228,7 @@ "engagement": null, "component": "", "push_all_issues": true, + "enabled": true, "enable_engagement_epic_mapping": true, "push_notes": true, "product_jira_sla_notification": false, @@ -35244,6 +35246,7 @@ "engagement": null, "component": "", "push_all_issues": false, + "enabled": true, "enable_engagement_epic_mapping": false, "push_notes": false, "product_jira_sla_notification": false, diff --git a/dojo/forms.py b/dojo/forms.py index 9869af62709..6fe83668d1b 100644 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -2859,7 +2859,7 @@ class JIRAProjectForm(forms.ModelForm): class Meta: model = JIRA_Project exclude = ["product", "engagement"] - fields = ["inherit_from_product", "jira_instance", "project_key", "issue_template_dir", "epic_issue_type_name", "component", "custom_fields", "jira_labels", "default_assignee", "add_vulnerability_id_to_jira_label", "push_all_issues", "enable_engagement_epic_mapping", "push_notes", "product_jira_sla_notification", "risk_acceptance_expiration_notification"] + fields = ["inherit_from_product", "jira_instance", "project_key", "issue_template_dir", "epic_issue_type_name", "component", "custom_fields", "jira_labels", "default_assignee", "enabled", "add_vulnerability_id_to_jira_label", "push_all_issues", "enable_engagement_epic_mapping", "push_notes", "product_jira_sla_notification", "risk_acceptance_expiration_notification"] def __init__(self, *args, **kwargs): from dojo.jira_link import helper as jira_helper @@ -2897,6 +2897,7 @@ def __init__(self, *args, **kwargs): self.fields["custom_fields"].disabled = False self.fields["default_assignee"].disabled = False self.fields["jira_labels"].disabled = False + self.fields["enabled"].disabled = False self.fields["add_vulnerability_id_to_jira_label"].disabled = False self.fields["push_all_issues"].disabled = False self.fields["enable_engagement_epic_mapping"].disabled = False @@ -2921,6 +2922,7 @@ def __init__(self, *args, **kwargs): self.initial["custom_fields"] = jira_project_product.custom_fields self.initial["default_assignee"] = jira_project_product.default_assignee self.initial["jira_labels"] = jira_project_product.jira_labels + self.initial["enabled"] = jira_project_product.enabled self.initial["add_vulnerability_id_to_jira_label"] = jira_project_product.add_vulnerability_id_to_jira_label self.initial["push_all_issues"] = jira_project_product.push_all_issues self.initial["enable_engagement_epic_mapping"] = jira_project_product.enable_engagement_epic_mapping @@ -2936,6 +2938,7 @@ def __init__(self, *args, **kwargs): self.fields["custom_fields"].disabled = True self.fields["default_assignee"].disabled = True self.fields["jira_labels"].disabled = True + self.fields["enabled"].disabled = True self.fields["add_vulnerability_id_to_jira_label"].disabled = True self.fields["push_all_issues"].disabled = True self.fields["enable_engagement_epic_mapping"].disabled = True diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py index c05f8808260..fb0eab686eb 100644 --- a/dojo/jira_link/helper.py +++ b/dojo/jira_link/helper.py @@ -71,11 +71,12 @@ def is_jira_configured_and_enabled(obj): if not is_jira_enabled(): return False - if get_jira_project(obj) is None: + jira_project = get_jira_project(obj) + if jira_project is None: logger.debug('JIRA project not found for: "%s" not doing anything', obj) return False - return True + return jira_project.enabled def is_push_to_jira(instance, push_to_jira_parameter=None): @@ -88,6 +89,10 @@ def is_push_to_jira(instance, push_to_jira_parameter=None): if push_to_jira_parameter is not None: return push_to_jira_parameter + # Check to see if jira project is disabled to prevent pushing findings + if not jira_project.enabled: + return False + # push_to_jira was not specified, so look at push_all_issues in JIRA_Project return jira_project.push_all_issues @@ -96,8 +101,10 @@ def is_push_all_issues(instance): if not is_jira_configured_and_enabled(instance): return False - jira_project = get_jira_project(instance) - if jira_project: + if jira_project := get_jira_project(instance): + # Check to see if jira project is disabled to prevent pushing findings + if not jira_project.enabled: + return None return jira_project.push_all_issues return None @@ -108,9 +115,13 @@ def is_push_all_issues(instance): # returns True/False, error_message, error_code def can_be_pushed_to_jira(obj, form=None): # logger.debug('can be pushed to JIRA: %s', finding_or_form) - if not get_jira_project(obj): + jira_project = get_jira_project(obj) + if not jira_project: return False, f"{to_str_typed(obj)} cannot be pushed to jira as there is no jira project configuration for this product.", "error_no_jira_project" + if not jira_project.enabled: + return False, f"{to_str_typed(obj)} cannot be pushed to jira as the jira project is not enabled.", "error_no_jira_project" + if not hasattr(obj, "has_jira_issue"): return False, f"{to_str_typed(obj)} cannot be pushed to jira as there is no jira_issue attribute.", "error_no_jira_issue_attribute" @@ -1389,6 +1400,13 @@ def add_comment(obj, note, force_push=False, **kwargs): def add_simple_jira_comment(jira_instance, jira_issue, comment): try: + jira_project = get_jira_project(jira_issue) + + # Check to see if jira project is disabled to prevent pushing findings + if not jira_project.enabled: + log_jira_generic_alert("JIRA Project is disabled", "Push to JIRA for Epic skipped because JIRA Project is disabled") + return False + jira = get_jira_connection(jira_instance) jira.add_comment( @@ -1403,9 +1421,13 @@ def add_simple_jira_comment(jira_instance, jira_issue, comment): def finding_link_jira(request, finding, new_jira_issue_key): logger.debug("linking existing jira issue %s for finding %i", new_jira_issue_key, finding.id) - existing_jira_issue = jira_get_issue(get_jira_project(finding), new_jira_issue_key) - jira_project = get_jira_project(finding) + existing_jira_issue = jira_get_issue(jira_project, new_jira_issue_key) + + # Check to see if jira project is disabled to prevent pushing findings + if not jira_project.enabled: + add_error_message_to_response("Push to JIRA for finding skipped because JIRA Project is disabled") + return False if not existing_jira_issue: raise ValueError("JIRA issue not found or cannot be retrieved: " + new_jira_issue_key) @@ -1433,9 +1455,13 @@ def finding_link_jira(request, finding, new_jira_issue_key): def finding_group_link_jira(request, finding_group, new_jira_issue_key): logger.debug("linking existing jira issue %s for finding group %i", new_jira_issue_key, finding_group.id) - existing_jira_issue = jira_get_issue(get_jira_project(finding_group), new_jira_issue_key) - jira_project = get_jira_project(finding_group) + existing_jira_issue = jira_get_issue(jira_project, new_jira_issue_key) + + # Check to see if jira project is disabled to prevent pushing findings + if not jira_project.enabled: + add_error_message_to_response("Push to JIRA for group skipped because JIRA Project is disabled") + return False if not existing_jira_issue: raise ValueError("JIRA issue not found or cannot be retrieved: " + new_jira_issue_key) diff --git a/dojo/models.py b/dojo/models.py index b34691b7103..a5bbe7c01f2 100644 --- a/dojo/models.py +++ b/dojo/models.py @@ -3919,9 +3919,17 @@ class JIRA_Project(models.Model): push_notes = models.BooleanField(default=False, blank=True) product_jira_sla_notification = models.BooleanField(default=False, blank=True, verbose_name=_("Send SLA notifications as comment?")) risk_acceptance_expiration_notification = models.BooleanField(default=False, blank=True, verbose_name=_("Send Risk Acceptance expiration notifications as comment?")) + enabled = models.BooleanField( + verbose_name=_("Enable Connection With Jira Project"), + help_text=_("When disabled, Findings will no longer be pushed to Jira, even if they have already been pushed previously."), + default=True, + blank=True) def __str__(self): - return ("%s: " + self.project_key + "(%s)") % (str(self.id), str(self.jira_instance.url) if self.jira_instance else "None") + value = f"{self.id}: {self.project_key} ({self.jira_instance.url if self.jira_instance else 'None'})" + if not self.enabled: + value += " - Not Connected" + return value def clean(self): if not self.jira_instance: diff --git a/unittests/dojo_test_case.py b/unittests/dojo_test_case.py index f72918cf938..39d65e113bc 100644 --- a/unittests/dojo_test_case.py +++ b/unittests/dojo_test_case.py @@ -173,6 +173,7 @@ def get_new_product_with_jira_project_data(self): "jira-project-form-jira_instance": 2, "jira-project-form-enable_engagement_epic_mapping": "on", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-push_notes": "on", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", @@ -188,6 +189,7 @@ def get_new_product_without_jira_project_data(self): "sla_configuration": 1, # A value is set by default by the model, so we need to add it here as well "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", # 'project_key': 'IFFF', # 'jira_instance': 2, # 'enable_engagement_epic_mapping': 'on', @@ -204,6 +206,7 @@ def get_product_with_jira_project_data(self, product): "jira-project-form-jira_instance": 2, "jira-project-form-enable_engagement_epic_mapping": "on", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-push_notes": "on", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", @@ -220,6 +223,7 @@ def get_product_with_jira_project_data2(self, product): "jira-project-form-jira_instance": 2, "jira-project-form-enable_engagement_epic_mapping": "on", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-push_notes": "on", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", @@ -235,6 +239,7 @@ def get_product_with_empty_jira_project_data(self, product): "sla_configuration": 1, # A value is set by default by the model, so we need to add it here as well "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-custom_fields": "null", # 'project_key': 'IFFF', # 'jira_instance': 2, diff --git a/unittests/test_jira_config_engagement.py b/unittests/test_jira_config_engagement.py index 6db30e089a3..59adb4f319b 100644 --- a/unittests/test_jira_config_engagement.py +++ b/unittests/test_jira_config_engagement.py @@ -30,6 +30,7 @@ def get_new_engagement_with_jira_project_data(self): "jira-project-form-jira_instance": 2, "jira-project-form-project_key": "IUNSEC", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", } @@ -47,6 +48,7 @@ def get_new_engagement_with_jira_project_data_and_epic_mapping(self): "jira-project-form-jira_instance": 2, "jira-project-form-project_key": "IUNSEC", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-enable_engagement_epic_mapping": "on", "jira-epic-form-push_to_jira": "on", @@ -65,6 +67,7 @@ def get_new_engagement_without_jira_project_data(self): "jira-project-form-inherit_from_product": "on", # A value is set by default by the model, so we need to add it here as well "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", # 'project_key': 'IFFF', # 'jira_instance': 2, # 'enable_engagement_epic_mapping': 'on', @@ -85,6 +88,7 @@ def get_engagement_with_jira_project_data(self, engagement): "jira-project-form-jira_instance": 2, "jira-project-form-project_key": "ISEC", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", } @@ -102,6 +106,7 @@ def get_engagement_with_jira_project_data2(self, engagement): "jira-project-form-jira_instance": 2, "jira-project-form-project_key": "ISEC2", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-custom_fields": "null", } @@ -118,6 +123,7 @@ def get_engagement_with_empty_jira_project_data(self, engagement): "jira-project-form-inherit_from_product": "on", # A value is set by default by the model, so we need to add it here as well "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", # 'project_key': 'IFFF', # 'jira_instance': 2, # 'enable_engagement_epic_mapping': 'on', diff --git a/unittests/test_jira_config_engagement_epic.py b/unittests/test_jira_config_engagement_epic.py index 75c241fab67..7b6b753416e 100644 --- a/unittests/test_jira_config_engagement_epic.py +++ b/unittests/test_jira_config_engagement_epic.py @@ -58,6 +58,7 @@ def get_new_engagement_with_jira_project_data_and_epic_mapping(self): "jira-project-form-jira_instance": 2, "jira-project-form-project_key": "NTEST", "jira-project-form-epic_issue_type_name": "Epic", + "jira-project-form-enabled": "True", "jira-project-form-product_jira_sla_notification": "on", "jira-project-form-enable_engagement_epic_mapping": "on", "jira-epic-form-push_to_jira": "on", From f345a4e9907bbd39c863389b9e8564d338202fce Mon Sep 17 00:00:00 2001 From: Harold Blankenship <36673698+hblankenship@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:03:58 -0500 Subject: [PATCH 08/16] Fix for Findings count in Dashboard based on wrong date (#11040) * use correct date for finding last 7 days * actual date_range --- dojo/home/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dojo/home/views.py b/dojo/home/views.py index 2c4d16fadef..3c485eb1e9c 100644 --- a/dojo/home/views.py +++ b/dojo/home/views.py @@ -33,7 +33,7 @@ def dashboard(request: HttpRequest) -> HttpResponse: date_range = [today - timedelta(days=6), today] # 7 days (6 days plus today) finding_count = findings\ - .filter(created__date__range=date_range)\ + .filter(date__range=date_range)\ .count() mitigated_count = findings\ .filter(mitigated__date__range=date_range)\ From b58ff497e329a91909716e59c34ffb14ed8bc0f8 Mon Sep 17 00:00:00 2001 From: Harold Blankenship <36673698+hblankenship@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:04:22 -0500 Subject: [PATCH 09/16] fix for issue 11010 (#11042) --- dojo/templates/dojo/view_test.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dojo/templates/dojo/view_test.html b/dojo/templates/dojo/view_test.html index 55bcb4ff8de..a4e0390b91a 100644 --- a/dojo/templates/dojo/view_test.html +++ b/dojo/templates/dojo/view_test.html @@ -1080,8 +1080,7 @@

{% endif %} {% if finding.test.engagement.product.enable_full_risk_acceptance %}
  • - + {% trans "Add Risk Acceptance..." %}
  • From 409896ceced66ce4edaf6c85cd4d4e6d97c2984d Mon Sep 17 00:00:00 2001 From: Harold Blankenship <36673698+hblankenship@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:05:41 -0500 Subject: [PATCH 10/16] remove mods, add Jannik to Hall of Fame (#11043) --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6cb9098145b..17d7bedfb3e 100644 --- a/README.md +++ b/README.md @@ -132,15 +132,14 @@ Core Moderators can help you with pull requests or feedback on dev ideas: * Cody Maffucci ([@Maffooch](https://github.com/maffooch) | [LinkedIn](https://www.linkedin.com/in/cody-maffucci)) Moderators can help you with pull requests or feedback on dev ideas: -* Damien Carol ([@damiencarol](https://github.com/damiencarol) | [LinkedIn](https://www.linkedin.com/in/damien-carol/)) -* Jannik Jürgens ([@alles-klar](https://github.com/alles-klar)) -* Dubravko Sever ([@dsever](https://github.com/dsever)) * Charles Neill ([@cneill](https://github.com/cneill) | [@ccneill](https://twitter.com/ccneill)) * Jay Paz ([@jjpaz](https://twitter.com/jjpaz)) * Blake Owens ([@blakeaowens](https://github.com/blakeaowens)) ## Hall of Fame - +* Jannik Jürgens ([@alles-klar](https://github.com/alles-klar)) - Jannik was a long time contributor and moderator for + DefectDojo and made significant contributions to many areas of the platform. Jannik was instrumental in pioneering + and optimizing deployment methods. * Valentijn Scholten ([@valentijnscholten](https://github.com/valentijnscholten) | [Sponsor](https://github.com/sponsors/valentijnscholten) | [LinkedIn](https://www.linkedin.com/in/valentijn-scholten/)) - Valentijn served as a core moderator for 3 years. From c494b0b5780293db2aadbabe0dc21841d272fdac Mon Sep 17 00:00:00 2001 From: manuelsommer <47991713+manuel-sommer@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:08:21 +0200 Subject: [PATCH 11/16] :tada: Add USN notices for vulnids (#11002) --- dojo/settings/.settings.dist.py.sha256sum | 2 +- dojo/settings/settings.dist.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dojo/settings/.settings.dist.py.sha256sum b/dojo/settings/.settings.dist.py.sha256sum index 5f387ae715d..c433539b1a6 100644 --- a/dojo/settings/.settings.dist.py.sha256sum +++ b/dojo/settings/.settings.dist.py.sha256sum @@ -1 +1 @@ -7ad5e28c5c96c6a3d40826bf32cea96c131825bd4eca857276b0458e26de36a3 +6cd4cfc4ae1dc8f89a2d28122705df499b12efae6993c60aa205661cffea2220 diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index f60d6d695d6..8594ef4a7a8 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -1733,6 +1733,7 @@ def saml2_attrib_map_format(dict): "RHEA": "https://access.redhat.com/errata/", "FEDORA": "https://bodhi.fedoraproject.org/updates/", "ALSA": "https://osv.dev/vulnerability/", # e.g. https://osv.dev/vulnerability/ALSA-2024:0827 + "USN": "https://ubuntu.com/security/notices/", # e.g. https://ubuntu.com/security/notices/USN-6642-1 } # List of acceptable file types that can be uploaded to a given object via arbitrary file upload FILE_UPLOAD_TYPES = env("DD_FILE_UPLOAD_TYPES") From 728ab1e9c3348d056df180fdbc5da355eb155ea1 Mon Sep 17 00:00:00 2001 From: manuelsommer <47991713+manuel-sommer@users.noreply.github.com> Date: Tue, 15 Oct 2024 17:14:31 +0200 Subject: [PATCH 12/16] add DLA security advisory (#11058) * add DLA security advisory * ruff linter * ruff linter --- dojo/settings/.settings.dist.py.sha256sum | 2 +- dojo/settings/settings.dist.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dojo/settings/.settings.dist.py.sha256sum b/dojo/settings/.settings.dist.py.sha256sum index c433539b1a6..b26b379a22c 100644 --- a/dojo/settings/.settings.dist.py.sha256sum +++ b/dojo/settings/.settings.dist.py.sha256sum @@ -1 +1 @@ -6cd4cfc4ae1dc8f89a2d28122705df499b12efae6993c60aa205661cffea2220 +4d3e91f176b73278750dc2f46d27cd4fe2b47d24682ad06d6267880bbdec599c diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index 8594ef4a7a8..39e033010db 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -1734,6 +1734,7 @@ def saml2_attrib_map_format(dict): "FEDORA": "https://bodhi.fedoraproject.org/updates/", "ALSA": "https://osv.dev/vulnerability/", # e.g. https://osv.dev/vulnerability/ALSA-2024:0827 "USN": "https://ubuntu.com/security/notices/", # e.g. https://ubuntu.com/security/notices/USN-6642-1 + "DLA": "https://security-tracker.debian.org/tracker/", # e.g. https://security-tracker.debian.org/tracker/DLA-3917-1 } # List of acceptable file types that can be uploaded to a given object via arbitrary file upload FILE_UPLOAD_TYPES = env("DD_FILE_UPLOAD_TYPES") From 985299d2187829e47b5b9405c860dffc47332cf8 Mon Sep 17 00:00:00 2001 From: Harold Blankenship <36673698+hblankenship@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:16:57 -0500 Subject: [PATCH 13/16] Update support text and buttons (#11051) * update text and icon for Get Support * Change Pro options and Meet the Creators button * re-add text I forgot I removed * add hyphen * Update dojo/templates/dojo/support.html --------- Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> --- dojo/templates/base.html | 4 +-- dojo/templates/dojo/support.html | 62 +++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/dojo/templates/base.html b/dojo/templates/base.html index 9515d68d349..5470baf13bd 100644 --- a/dojo/templates/base.html +++ b/dojo/templates/base.html @@ -589,8 +589,8 @@ {% block support-tab %}
  • {% endblock %} diff --git a/dojo/templates/dojo/support.html b/dojo/templates/dojo/support.html index fd0a49a095b..45066a551f9 100644 --- a/dojo/templates/dojo/support.html +++ b/dojo/templates/dojo/support.html @@ -14,24 +14,68 @@

    Community Support

    What's included:

    Support from the community via OWASP Slack

    -

    Community based discussion

    +

    Community-based discussion

    Join #defectdojo
    -

    Get DefectDojo Pro

    +

    Go Pro!

    What's included:

    -

    Support directly from the creators

    -

    Additional features

    -

    Response time SLA

    -

    Bug fixes

    -

    Feature enhancements

    -

    Best practice advice

    +

    New UI + + +

    +

    Connectors + + +

    +

    Insights + + +

    +

    Data Enrichment + + +

    +

    Universal Importer + + +

    +

    Async Functions + + +

    +

    Support directly from the DefectDojo Team

    +

    Assistance with best practice and implementation

    - Meet The Creators + Go Pro Now
    From ac1048e5d9e33990993b05fef46908519530866c Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:17:11 -0500 Subject: [PATCH 14/16] Parser Tests: add tag to differentiate (#11017) --- unittests/test_parsers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unittests/test_parsers.py b/unittests/test_parsers.py index 63edff395c6..9e2ac077f14 100644 --- a/unittests/test_parsers.py +++ b/unittests/test_parsers.py @@ -1,11 +1,14 @@ import os from pathlib import Path +from django.test import tag as test_tag + from .dojo_test_case import DojoTestCase, get_unit_tests_path basedir = os.path.join(get_unit_tests_path(), "..") +@test_tag("parser-supplement-tests") class TestParsers(DojoTestCase): def test_file_existence(self): for parser_dir in os.scandir(os.path.join(basedir, "dojo", "tools")): From 0962bd6b622e61c7c594c9ff48cfc3a493e9deea Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Tue, 15 Oct 2024 15:29:37 +0000 Subject: [PATCH 15/16] 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 06cdce1889b..019e424ade3 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.40.0-dev", + "version": "2.39.1", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 6bc97e6bbb2..fde5a6c98f2 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.39.0" +__version__ = "2.39.1" __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 4f2c96ba0fa..bd105fc95fd 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.40.0-dev" +appVersion: "2.39.1" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.154-dev +version: 1.6.154 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 309a65f187ea41a1b7ce87de2aa934e39ba27ef0 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Tue, 15 Oct 2024 16:09:23 +0000 Subject: [PATCH 16/16] 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 019e424ade3..06cdce1889b 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.39.1", + "version": "2.40.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index fde5a6c98f2..0dc36e95a1e 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.39.1" +__version__ = "2.40.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 bd105fc95fd..a0cabd6bb3d 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.39.1" +appVersion: "2.40.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.154 +version: 1.6.155-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap