diff --git a/components/package.json b/components/package.json index cab02bf8dc5..4682a6235fe 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.26.3", + "version": "2.26.4", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/docker-compose.yml b/docker-compose.yml index dc198450e0e..eb4ca1e8eff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: context: ./ dockerfile: "Dockerfile.nginx-${DEFECT_DOJO_OS:-debian}" image: "defectdojo/defectdojo-nginx:${NGINX_VERSION:-latest}" - profiles: + profiles: - mysql-rabbitmq - mysql-redis - postgres-rabbitmq @@ -39,13 +39,13 @@ services: dockerfile: "Dockerfile.django-${DEFECT_DOJO_OS:-debian}" target: django image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" - profiles: + profiles: - mysql-rabbitmq - mysql-redis - postgres-rabbitmq - postgres-redis depends_on: - - ${DD_DOCKERCOMPOSE_DATABASE} + - ${DD_DOCKERCOMPOSE_DATABASE:-postgres} entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST}:${DD_DATABASE_PORT}', '-t', '30', '--', '/entrypoint-uwsgi.sh'] environment: DD_DEBUG: 'False' @@ -62,14 +62,14 @@ services: - "defectdojo_media:${DD_MEDIA_ROOT:-/app/media}" celerybeat: image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" - profiles: + profiles: - mysql-rabbitmq - mysql-redis - postgres-rabbitmq - postgres-redis depends_on: - - ${DD_DOCKERCOMPOSE_DATABASE} - - ${DD_DOCKERCOMPOSE_BROKER} + - ${DD_DOCKERCOMPOSE_DATABASE:-postgres} + - ${DD_DOCKERCOMPOSE_BROKER:-redis} entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST}:${DD_DATABASE_PORT}', '-t', '30', '--', '/entrypoint-celery-beat.sh'] environment: DD_DATABASE_URL: ${DD_DATABASE_URL} @@ -82,14 +82,14 @@ services: target: /app/docker/extra_settings celeryworker: image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" - profiles: + profiles: - mysql-rabbitmq - mysql-redis - postgres-rabbitmq - postgres-redis depends_on: - - ${DD_DOCKERCOMPOSE_DATABASE} - - ${DD_DOCKERCOMPOSE_BROKER} + - ${DD_DOCKERCOMPOSE_DATABASE:-postgres} + - ${DD_DOCKERCOMPOSE_BROKER:-redis} entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST}:${DD_DATABASE_PORT}', '-t', '30', '--', '/entrypoint-celery-worker.sh'] environment: DD_DATABASE_URL: ${DD_DATABASE_URL} @@ -103,13 +103,13 @@ services: - "defectdojo_media:${DD_MEDIA_ROOT:-/app/media}" initializer: image: "defectdojo/defectdojo-django:${DJANGO_VERSION:-latest}" - profiles: + profiles: - mysql-rabbitmq - mysql-redis - postgres-rabbitmq - postgres-redis depends_on: - - ${DD_DOCKERCOMPOSE_DATABASE} + - ${DD_DOCKERCOMPOSE_DATABASE:-postgres} entrypoint: ['/wait-for-it.sh', '${DD_DATABASE_HOST}:${DD_DATABASE_PORT}', '--', '/entrypoint-initializer.sh'] environment: DD_DATABASE_URL: ${DD_DATABASE_URL} @@ -126,7 +126,7 @@ services: target: /app/docker/extra_settings mysql: image: mysql:5.7.43@sha256:2c23f254c6b9444ecda9ba36051a9800e8934a2f5828ecc8730531db8142af83 - profiles: + profiles: - mysql-rabbitmq - mysql-redis environment: @@ -139,7 +139,7 @@ services: - defectdojo_data:/var/lib/mysql postgres: image: postgres:15.4-alpine@sha256:8bc3c893342c766481df5fde58fab6f1a1115b94eb56778126163305243e9709 - profiles: + profiles: - postgres-rabbitmq - postgres-redis environment: @@ -150,14 +150,14 @@ services: - defectdojo_postgres:/var/lib/postgresql/data rabbitmq: image: rabbitmq:3.12.4-alpine@sha256:1db3f856e6628e2ac512a91959437ca5bab5112c856fe730b6b5ff5087e5e3d0 - profiles: + profiles: - mysql-rabbitmq - postgres-rabbitmq volumes: - defectdojo_rabbitmq:/var/lib/rabbitmq redis: image: redis:7.2.0-alpine@sha256:fd5de2340bc46cbc2241975ab027797c350dec6fd86349e3ac384e3a41be6fee - profiles: + profiles: - mysql-redis - postgres-redis volumes: diff --git a/dojo/__init__.py b/dojo/__init__.py index ba68a05c499..0dad01ef5a2 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 -__version__ = '2.26.3' +__version__ = '2.26.4' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/dojo/api_v2/views.py b/dojo/api_v2/views.py index 3104ecf4cc0..8f8024c93de 100644 --- a/dojo/api_v2/views.py +++ b/dojo/api_v2/views.py @@ -767,6 +767,7 @@ class RiskAcceptanceViewSet( mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, + mixins.UpdateModelMixin, viewsets.GenericViewSet, dojo_mixins.DeletePreviewModelMixin, ): diff --git a/dojo/forms.py b/dojo/forms.py index 056edca8c73..e2d31684fca 100755 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -1448,6 +1448,9 @@ def __init__(self, *args, **kwargs): if 'instance' in kwargs: self.endpoint_instance = kwargs.pop('instance') self.product = self.endpoint_instance.product + product_id = self.endpoint_instance.product.pk + findings = Finding.objects.filter(test__engagement__product__id=product_id) + self.fields["findings"].queryset = findings def clean(self): diff --git a/dojo/templates/dojo/product.html b/dojo/templates/dojo/product.html index 8067ea2c7cf..f440037d4ca 100644 --- a/dojo/templates/dojo/product.html +++ b/dojo/templates/dojo/product.html @@ -342,7 +342,16 @@

{ "data": "product" }, { "data": "tags" }, { "data": "criticality" , render: function (data, type, row) { - return type === 'export' ? getDojoExportValueFromTag(data, 'i', 'data-content') : data; + const criticals = { + 'Very High': 5, + 'High': 4, + 'Medium': 3, + 'Low': 2, + 'Very Low': 1, + 'None': 0 + }; + return type === 'sort' ? criticals[getDojoExportValueFromTag(data, 'i', 'data-content')] : + type === 'export' ? getDojoExportValueFromTag(data, 'i', 'data-content') : data; }}, { "data": "metadata", render: function (data, type, row) { return type === 'export' ? getDojoExportValueFromTag(data, 'i', 'data-content') : data; diff --git a/dojo/tools/qualys/csv_parser.py b/dojo/tools/qualys/csv_parser.py index e210c7aea9c..15f84117d22 100644 --- a/dojo/tools/qualys/csv_parser.py +++ b/dojo/tools/qualys/csv_parser.py @@ -3,6 +3,7 @@ import logging import re from datetime import datetime +from dateutil import parser from dojo.models import Endpoint, Finding @@ -114,19 +115,26 @@ def build_findings_from_dict(report_findings: [dict]) -> [Finding]: else: endpoint = Endpoint(host=report_finding["IP"]) + if "CVSS3 Base" in report_finding: + cvssv3 = _extract_cvss_vectors( + report_finding["CVSS3 Base"], report_finding["CVSS3 Temporal"] + ) + elif "CVSS3.1 Base" in report_finding: + cvssv3 = _extract_cvss_vectors( + report_finding["CVSS3.1 Base"], report_finding["CVSS3.1 Temporal"] + ) + finding = Finding( title=f"QID-{report_finding['QID']} | {report_finding['Title']}", mitigation=report_finding["Solution"], description=f"{report_finding['Threat']}\nResult Evidence: \n{report_finding.get('Threat', 'Not available')}", severity=severity_lookup.get(report_finding["Severity"], "Info"), impact=report_finding["Impact"], - date=datetime.strptime( - report_finding["Last Detected"], "%m/%d/%Y %H:%M:%S" - ).date(), - vuln_id_from_tool=report_finding["QID"], - cvssv3=_extract_cvss_vectors( - report_finding["CVSS3 Base"], report_finding["CVSS3 Temporal"] + date=parser.parse( + report_finding["Last Detected"].replace("Z", "") ), + vuln_id_from_tool=report_finding["QID"], + cvssv3=cvssv3 ) cve_data = report_finding.get("CVE ID") diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index fd0f56b53e2..2556daf1587 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.26.3" +appVersion: "2.26.4" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.87 +version: 1.6.88 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index d5ffc901267..69f318ec3a9 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -935,8 +935,33 @@ def __init__(self, *args, **kwargs): self.endpoint_path = 'risk_acceptance' self.viewname = 'risk_acceptance' self.viewset = RiskAcceptanceViewSet + self.payload = { + "id": 1, + "recommendation": "Fix (The risk is eradicated)", + "decision": "Accept (The risk is acknowledged, yet remains)", + "path": "No proof has been supplied", + "name": "string", + "recommendation_details": "string", + "decision_details": "string", + "accepted_by": "string", + "expiration_date": "2023-09-15T17:16:52.989000Z", + "expiration_date_warned": "2023-09-15T17:16:52.989000Z", + "expiration_date_handled": "2023-09-15T17:16:52.989000Z", + "reactivate_expired": True, + "restart_sla_expired": True, + "created": "2020-11-09T23:13:08.520000Z", + "updated": "2023-09-15T17:17:39.462854Z", + "owner": 1, + "accepted_findings": [ + 4 + ], + "notes": [] + } + self.update_fields = {'name': 'newName'} self.test_type = TestType.OBJECT_PERMISSIONS self.permission_check_class = Risk_Acceptance + self.permission_create = Permissions.Risk_Acceptance + self.permission_update = Permissions.Risk_Acceptance self.permission_delete = Permissions.Risk_Acceptance self.deleted_objects = 3 BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs)