diff --git a/.github/workflows/renovate.yaml b/.github/workflows/renovate.yaml index 22cf11cd8df..1673fca3bc6 100644 --- a/.github/workflows/renovate.yaml +++ b/.github/workflows/renovate.yaml @@ -21,4 +21,4 @@ jobs: uses: suzuki-shunsuke/github-action-renovate-config-validator@ca480cb7ec89a9e1cd8c214ad33bda1617184027 # v2.0.0 with: strict: "true" - validator_version: 42.92.5 # renovate: datasource=github-releases depName=renovatebot/renovate + validator_version: 43.2.4 # renovate: datasource=github-releases depName=renovatebot/renovate diff --git a/Dockerfile.django-alpine b/Dockerfile.django-alpine index bf02a563145..4f26ae3c497 100644 --- a/Dockerfile.django-alpine +++ b/Dockerfile.django-alpine @@ -5,7 +5,7 @@ # Dockerfile.nginx to use the caching mechanism of Docker. # Ref: https://devguide.python.org/#branchstatus -FROM python:3.13.11-alpine3.22@sha256:2fd93799bfc6381d078a8f656a5f45d6092e5d11d16f55889b3d5cbfdc64f045 AS base +FROM python:3.13.12-alpine3.22@sha256:41351b07080ccfaa27bf38dde20de79ee6a0ac74a58c00c6d7a7d96ac4e69716 AS base FROM base AS build WORKDIR /app RUN \ diff --git a/Dockerfile.django-debian b/Dockerfile.django-debian index 864005de22d..efbe9b99cf0 100644 --- a/Dockerfile.django-debian +++ b/Dockerfile.django-debian @@ -5,7 +5,7 @@ # Dockerfile.nginx to use the caching mechanism of Docker. # Ref: https://devguide.python.org/#branchstatus -FROM python:3.13.11-slim-trixie@sha256:51e1a0a317fdb6e170dc791bbeae63fac5272c82f43958ef74a34e170c6f8b18 AS base +FROM python:3.13.12-slim-trixie@sha256:3de9a8d7aedbb7984dc18f2dff178a7850f16c1ae7c34ba9d7ecc23d0755e35f AS base FROM base AS build WORKDIR /app RUN \ diff --git a/Dockerfile.integration-tests-debian b/Dockerfile.integration-tests-debian index a5d5eecb805..7f693dcaa83 100644 --- a/Dockerfile.integration-tests-debian +++ b/Dockerfile.integration-tests-debian @@ -3,7 +3,7 @@ FROM openapitools/openapi-generator-cli:v7.19.0@sha256:b9e7ad71a9f9406bd810378a939755fad114747a767e29bbf83ef9364d5f9dc0 AS openapitools # currently only supports x64, no arm yet due to chrome and selenium dependencies -FROM python:3.13.11-slim-trixie@sha256:51e1a0a317fdb6e170dc791bbeae63fac5272c82f43958ef74a34e170c6f8b18 AS build +FROM python:3.13.12-slim-trixie@sha256:3de9a8d7aedbb7984dc18f2dff178a7850f16c1ae7c34ba9d7ecc23d0755e35f AS build WORKDIR /app RUN \ apt-get -y update && \ diff --git a/Dockerfile.nginx-alpine b/Dockerfile.nginx-alpine index 8db761d2b4e..8617c4425d1 100644 --- a/Dockerfile.nginx-alpine +++ b/Dockerfile.nginx-alpine @@ -5,7 +5,7 @@ # Dockerfile.django-alpine to use the caching mechanism of Docker. # Ref: https://devguide.python.org/#branchstatus -FROM python:3.13.11-alpine3.22@sha256:2fd93799bfc6381d078a8f656a5f45d6092e5d11d16f55889b3d5cbfdc64f045 AS base +FROM python:3.13.12-alpine3.22@sha256:41351b07080ccfaa27bf38dde20de79ee6a0ac74a58c00c6d7a7d96ac4e69716 AS base FROM base AS build WORKDIR /app RUN \ diff --git a/components/package.json b/components/package.json index bc3de215a48..eafbd9b86cb 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.55.2", + "version": "2.56.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { @@ -12,7 +12,7 @@ "chosen-bootstrap": "https://github.com/dbtek/chosen-bootstrap", "chosen-js": "^1.8.7", "clipboard": "^2.0.11", - "datatables.net": "^2.3.6", + "datatables.net": "^2.3.7", "datatables.net-buttons-bs": "^3.2.6", "datatables.net-colreorder": "^2.1.2", "drmonty-datatables-plugins": "^1.0.0", diff --git a/components/yarn.lock b/components/yarn.lock index ecfd05a3377..81525788406 100644 --- a/components/yarn.lock +++ b/components/yarn.lock @@ -162,10 +162,10 @@ datatables.net@2.3.2: dependencies: jquery ">=1.7" -datatables.net@^2, datatables.net@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-2.3.6.tgz#a11be57a2b50d7231cae2980a8ff1df3c18b7b17" - integrity sha512-xQ/dCxrjfxM0XY70wSIzakkTZ6ghERwlLmAPyCnu8Sk5cyt9YvOVyOsFNOa/BZ/lM63Q3i2YSSvp/o7GXZGsbg== +datatables.net@^2, datatables.net@^2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-2.3.7.tgz#3cd34f6f5d1f40a46b5a20a4ba32604bdbcd6738" + integrity sha512-AvsjG/Nkp6OxeyBKYZauemuzQCPogE1kOtKwG4sYjvdqGCSLiGaJagQwXv4YxG+ts5vaJr6qKGG9ec3g6vTo3w== dependencies: jquery ">=1.7" diff --git a/docker-compose.yml b/docker-compose.yml index d8a1b14d4a9..923fd12eb06 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -120,7 +120,7 @@ services: source: ./docker/extra_settings target: /app/docker/extra_settings postgres: - image: postgres:18.1-alpine@sha256:4eb15de8e7b692c02427a2df278d18eb89422a534e428efb6d43c968250334d4 + image: postgres:18.1-alpine@sha256:aa6eb304ddb6dd26df23d05db4e5cb05af8951cda3e0dc57731b771e0ef4ab29 environment: POSTGRES_DB: ${DD_DATABASE_NAME:-defectdojo} POSTGRES_USER: ${DD_DATABASE_USER:-defectdojo} @@ -128,7 +128,7 @@ services: volumes: - defectdojo_postgres:/var/lib/postgresql/data valkey: - image: valkey/valkey:7.2.11-alpine@sha256:9e483e0fe4c98b631b166b41d530c7ff1b8009a44f261bff28e9d1e2e27db58d + image: valkey/valkey:7.2.11-alpine@sha256:10328d00120dc14fbc87b2ed61b7677ddbb0d011e705361b4788329a0ec69a93 volumes: # we keep using the redis volume as renaming is not possible and copying data over # would require steps during downtime or complex commands in the intializer diff --git a/docs/content/en/open_source/upgrading/2.56.md b/docs/content/en/open_source/upgrading/2.56.md new file mode 100644 index 00000000000..ebf55dbc894 --- /dev/null +++ b/docs/content/en/open_source/upgrading/2.56.md @@ -0,0 +1,7 @@ +--- +title: 'Upgrading to DefectDojo Version 2.56.x' +toc_hide: true +weight: -20260203 +description: No special instructions. +--- +There are no special instructions for upgrading to 2.56.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.56.0) for the contents of the release. diff --git a/dojo/__init__.py b/dojo/__init__.py index b98285c0f30..700d8de3c7e 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.55.2" +__version__ = "2.56.0-dev" __url__ = "https://github.com/DefectDojo/django-DefectDojo" # noqa: RUF067 __docs__ = "https://documentation.defectdojo.com" # noqa: RUF067 diff --git a/dojo/templates/notifications/mail/product_type_added.tpl b/dojo/templates/notifications/mail/product_type_added.tpl index a229882a346..1f41b3e5a14 100644 --- a/dojo/templates/notifications/mail/product_type_added.tpl +++ b/dojo/templates/notifications/mail/product_type_added.tpl @@ -1,40 +1,57 @@ {% load i18n %} {% load navigation_tags %} {% load display_tags %} +{% url 'view_product_type' product_type.id as product_type_url %} + - - {% autoescape on %} -

- {% trans "Hello" %}, -

-

- {% blocktranslate trimmed prod_url=url|full_url %} - The new product type "{{ title }}" has been added. It can be viewed here: {{ title }} - {% endblocktranslate %} -

-
-
- {% trans "Kind regards" %},
-
- {% if system_settings.team_name %} - {{ system_settings.team_name }} - {% else %} - Defect Dojo - {% endif %} -

-
-
-

- {% url 'notifications' as notification_url %} - {% trans "You can manage your notification settings here" %}: {{ notification_url|full_url }} -

- {% if system_settings.disclaimer_notifications and system_settings.disclaimer_notifications.strip %} -
-
- {% trans "Disclaimer" %}
-

{{ system_settings.disclaimer_notifications }}

-
- {% endif %} - {% endautoescape %} - + + {% autoescape on %} +

+ {% trans "Hello" %}, +

+ +

+ {% blocktranslate trimmed with title=title prod_url=product_type_url|full_url %} + The new product type "{{ title }}" has been added. + It can be viewed here: {{ title }} + {% endblocktranslate %} +

+ +
+
+ + {% trans "Kind regards" %},
+
+ + {% if system_settings.team_name %} + {{ system_settings.team_name }} + {% else %} + Defect Dojo + {% endif %} + +

+
+
+

+ +

+ {% url 'notifications' as notification_url %} + {% trans "You can manage your notification settings here" %}: + {{ notification_url|full_url }} +

+ + {% if system_settings.disclaimer_notifications and system_settings.disclaimer_notifications.strip %} +
+
+ + {% trans "Disclaimer" %} + +
+

+ {{ system_settings.disclaimer_notifications }} +

+
+ {% endif %} + {% endautoescape %} + diff --git a/dojo/tools/qualys/parser.py b/dojo/tools/qualys/parser.py index df9aa6f1ae6..af36c473e48 100644 --- a/dojo/tools/qualys/parser.py +++ b/dojo/tools/qualys/parser.py @@ -353,13 +353,18 @@ def parse_finding(host, tree): if temp.get("CVSS_value") is not None: finding.cvssv3_score = temp.get("CVSS_value") finding.verified = True + endpoint_port = None + if port and str(port).isdigit(): + endpoint_port = int(port) # manage endpoint/location if settings.V3_FEATURE_LOCATIONS: - location = URL(host=issue_row["fqdn"]) if issue_row["fqdn"] else URL(host=issue_row["ip_address"]) + host_val = issue_row["fqdn"] or issue_row["ip_address"] + location = URL(host=host_val, port=endpoint_port) finding.unsaved_locations = [location] else: # TODO: Delete this after the move to Locations - location = Endpoint(host=issue_row["fqdn"]) if issue_row["fqdn"] else Endpoint(host=issue_row["ip_address"]) + host_val = issue_row["fqdn"] or issue_row["ip_address"] + location = Endpoint(host=host_val, port=endpoint_port) finding.unsaved_endpoints = [location] finding.unsaved_vulnerability_ids = temp.get("cve_list", []) ret_rows.append(finding) @@ -369,7 +374,7 @@ def parse_finding(host, tree): def qualys_parser(qualys_xml_file): parser = ElementTree.XMLParser() tree = ElementTree.parse(qualys_xml_file, parser) - host_list = tree.find("HOST_LIST") + host_list = tree.find(".//HOST_LIST") finding_list = [] if host_list is not None: for host in host_list: diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index fe3807b46a0..23bcbb1af8f 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.55.2" +appVersion: "2.56.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.9.12 +version: 1.9.13-dev icon: https://defectdojo.com/hubfs/DefectDojo_favicon.png maintainers: - name: madchap @@ -33,5 +33,5 @@ dependencies: # - kind: security # description: Critical bug annotations: - artifacthub.io/prerelease: "false" - artifacthub.io/changes: "- kind: changed\n description: Bump DefectDojo to 2.55.2\n" + artifacthub.io/prerelease: "true" + artifacthub.io/changes: "" diff --git a/helm/defectdojo/README.md b/helm/defectdojo/README.md index 480b35e158c..a63757f2687 100644 --- a/helm/defectdojo/README.md +++ b/helm/defectdojo/README.md @@ -511,7 +511,7 @@ The HELM schema will be generated for you. # General information about chart values -![Version: 1.9.12](https://img.shields.io/badge/Version-1.9.12-informational?style=flat-square) ![AppVersion: 2.55.2](https://img.shields.io/badge/AppVersion-2.55.2-informational?style=flat-square) +![Version: 1.9.13-dev](https://img.shields.io/badge/Version-1.9.13--dev-informational?style=flat-square) ![AppVersion: 2.56.0-dev](https://img.shields.io/badge/AppVersion-2.56.0--dev-informational?style=flat-square) A Helm chart for Kubernetes to install DefectDojo @@ -767,9 +767,10 @@ A Helm chart for Kubernetes to install DefectDojo | tests.unitTests.resources.requests.cpu | string | `"100m"` | | | tests.unitTests.resources.requests.memory | string | `"128Mi"` | | | trackConfig | string | `"disabled"` | Track configuration (trackConfig): will automatically respin application pods in case of config changes detection can be: 1. disabled (default) 2. enabled, enables tracking configuration changes based on SHA256 | -| valkey | object | `{"auth":{"existingSecret":"defectdojo-valkey-specific","existingSecretPasswordKey":"valkey-password","password":""},"enabled":true,"sentinel":{"enabled":false},"service":{"port":6379},"tls":{"enabled":false}}` | For more advance options check the bitnami chart documentation: https://artifacthub.io/packages/helm/cloudpirates-valkey/valkey | +| valkey | object | `{"auth":{"existingSecret":"defectdojo-valkey-specific","existingSecretPasswordKey":"valkey-password","password":""},"enabled":true,"sentinel":{"enabled":false},"service":{"port":6379},"serviceAccount":{"create":true},"tls":{"enabled":false}}` | For more advance options check the bitnami chart documentation: https://artifacthub.io/packages/helm/cloudpirates-valkey/valkey | | valkey.enabled | bool | `true` | To use an external instance, switch enabled to `false` and set the address in `redisServer` below | | valkey.service | object | `{"port":6379}` | To use a different port for Redis (default: 6379) | +| valkey.serviceAccount.create | bool | `true` | Autocreate dedicated service account (as part of the best practice) | | valkey.tls.enabled | bool | `false` | If TLS is enabled, the Redis broker will use the redis:// and optionally mount the certificates from an existing secret. | | valkeyParams | string | `""` | Parameters attached to the valkey connection string, defaults to "ssl_cert_reqs=optional" if `valkey.tls.enabled` | diff --git a/helm/defectdojo/values.schema.json b/helm/defectdojo/values.schema.json index 1ad08c9f298..54120f850bf 100644 --- a/helm/defectdojo/values.schema.json +++ b/helm/defectdojo/values.schema.json @@ -1500,6 +1500,15 @@ } } }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "description": "Autocreate dedicated service account (as part of the best practice)", + "type": "boolean" + } + } + }, "tls": { "type": "object", "properties": { diff --git a/helm/defectdojo/values.yaml b/helm/defectdojo/values.yaml index d8c6d99576b..792930707e4 100644 --- a/helm/defectdojo/values.yaml +++ b/helm/defectdojo/values.yaml @@ -652,6 +652,9 @@ valkey: # certFilename: tls.crt # certKeyFilename: tls.key # certCAFilename: ca.crt + serviceAccount: + # -- Autocreate dedicated service account (as part of the best practice) + create: true # -- To add extra variables not predefined by helm config it is possible to define in extraConfigs block, e.g. below: # NOTE Do not store any kind of sensitive information inside of it diff --git a/requirements-lint.txt b/requirements-lint.txt index b97a93db478..b7317ed9de5 100644 --- a/requirements-lint.txt +++ b/requirements-lint.txt @@ -1 +1 @@ -ruff==0.14.14 \ No newline at end of file +ruff==0.15.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 52396d021d7..cd830d89307 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,7 +53,7 @@ django-split-settings==1.3.2 # do not upgrade to 2.1.1 - https://github.com/DefectDojo/django-DefectDojo/issues/12918 # use fork with django 5.2 fixes, but based on 2.1.0 git+https://github.com/valentijnscholten/django-tagulous.git@2b514f9140acfce608238d1426d864185b3c60a2#egg=django-tagulous -PyJWT==2.10.1 +PyJWT==2.11.0 cvss==3.6 django-fieldsignals==0.8.0 hyperlink==21.0.0 @@ -69,4 +69,4 @@ fontawesomefree==6.6.0 PyYAML==6.0.3 pyopenssl==25.3.0 parameterized==0.9.0 -setuptools==80.10.2 +setuptools==82.0.0 diff --git a/unittests/scans/qualys/test_qualys.xml b/unittests/scans/qualys/test_qualys.xml new file mode 100644 index 00000000000..93c1a0da710 --- /dev/null +++ b/unittests/scans/qualys/test_qualys.xml @@ -0,0 +1,37 @@ + + + + + + SSL Certificate Expired + 3 + Threat text + Impact text + Solution text + + + + + + + 192.168.1.100 + + + + 80 + 2026-02-08T10:00:00Z + 2026-02-08T10:00:00Z + Confirmed + + + + 443 + 2026-02-08T10:00:00Z + 2026-02-08T10:00:00Z + Confirmed + + + + + + \ No newline at end of file diff --git a/unittests/tools/test_qualys_parser.py b/unittests/tools/test_qualys_parser.py index 060b6b9fcc0..d650eb9bbfd 100644 --- a/unittests/tools/test_qualys_parser.py +++ b/unittests/tools/test_qualys_parser.py @@ -16,6 +16,22 @@ def test_parse_file_with_no_vuln_has_no_findings_first_seen(self): def test_parse_file_with_no_vuln_has_no_findings(self): self.parse_file_with_no_vuln_has_no_findings() + def test_parse_file_with_multiple_ports_for_same_qid(self): + with (get_unit_tests_scans_path("qualys") / "test_qualys.xml").open(encoding="utf-8") as testfile: + parser = QualysParser() + findings = parser.get_findings(testfile, Test()) + + self.assertEqual(len(findings), 2, "Should have 2 findings for different ports") + ports = [self.get_unsaved_locations(f)[0].port for f in findings] + self.assertIn(80, ports) + self.assertIn(443, ports) + + self.assertEqual(findings[0].title, findings[1].title) + self.assertNotEqual( + self.get_unsaved_locations(findings[0])[0].port, + self.get_unsaved_locations(findings[1])[0].port, + ) + def parse_file_with_no_vuln_has_no_findings(self): with ( get_unit_tests_scans_path("qualys") / "empty.xml").open(encoding="utf-8",