From 2af827f9c93d755f9e15805954df3bba59133640 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 3 Jun 2024 20:28:45 +0000 Subject: [PATCH 01/65] Update versions in application files --- components/package.json | 2 +- docs/content/en/getting_started/upgrading/2.36.md | 7 +++++++ dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 docs/content/en/getting_started/upgrading/2.36.md diff --git a/components/package.json b/components/package.json index 3496b28c137..688f4f5d52f 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.35.0", + "version": "2.36.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/docs/content/en/getting_started/upgrading/2.36.md b/docs/content/en/getting_started/upgrading/2.36.md new file mode 100644 index 00000000000..260c86960de --- /dev/null +++ b/docs/content/en/getting_started/upgrading/2.36.md @@ -0,0 +1,7 @@ +--- +title: 'Upgrading to DefectDojo Version 2.36.x' +toc_hide: true +weight: -20240603 +description: No special instructions. +--- +There are no special instructions for upgrading to 2.36.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.36.0) for the contents of the release. diff --git a/dojo/__init__.py b/dojo/__init__.py index 8c662903c28..423f4050e5c 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.35.0' +__version__ = '2.36.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 31b548564ca..435cbde2193 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.35.0" +appVersion: "2.36.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.132 +version: 1.6.133-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 924f36996de7eb0726a3a258195e57c544631b88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:52:24 -0500 Subject: [PATCH 02/65] Bump boto3 from 1.34.117 to 1.34.118 (#10330) Bumps [boto3](https://github.com/boto/boto3) from 1.34.117 to 1.34.118. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.117...1.34.118) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 2f3742de47e..5e760f8a5c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.117 # Required for Celery Broker AWS (SQS) support +boto3==1.34.118 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 4a8146c019cd1441df829d5d0648294924d0dc35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:53:23 -0500 Subject: [PATCH 03/65] Bump uwsgi from 2.0.25.1 to 2.0.26 (#10331) Bumps [uwsgi](https://uwsgi-docs.readthedocs.io/en/latest/) from 2.0.25.1 to 2.0.26. --- updated-dependencies: - dependency-name: uwsgi dependency-type: direct:production update-type: version-update:semver-patch ... 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 5e760f8a5c9..cb37f15ce24 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,7 @@ redis==5.0.4 requests==2.32.3 sqlalchemy==2.0.30 # Required by Celery broker transport urllib3==1.26.18 -uWSGI==2.0.25.1 +uWSGI==2.0.26 vobject==0.9.7 whitenoise==5.2.0 titlecase==2.4.1 From 4ebde663964e0f726787d1f9bca3203c9318a320 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:54:19 -0500 Subject: [PATCH 04/65] Bump drf-spectacular-sidecar from 2024.5.1 to 2024.6.1 (#10329) Bumps [drf-spectacular-sidecar](https://github.com/tfranzel/drf-spectacular-sidecar) from 2024.5.1 to 2024.6.1. - [Commits](https://github.com/tfranzel/drf-spectacular-sidecar/compare/2024.5.1...2024.6.1) --- updated-dependencies: - dependency-name: drf-spectacular-sidecar dependency-type: direct:production update-type: version-update:semver-minor ... 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 cb37f15ce24..27fc3f8f2c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -70,7 +70,7 @@ hyperlink==21.0.0 django-test-migrations==1.3.0 djangosaml2==1.9.3 drf-spectacular==0.27.2 -drf-spectacular-sidecar==2024.5.1 +drf-spectacular-sidecar==2024.6.1 django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 From c61c802d37f2063786ffd10e6c07e33eeae2c615 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 4 Jun 2024 11:54:43 -0500 Subject: [PATCH 05/65] chore(deps): update postgres:16.3-alpine docker digest from 16.3 to 16.3-alpine (docker-compose.yml) (#10327) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 80e2d783f7c..2dddbdb2460 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -137,7 +137,7 @@ services: volumes: - defectdojo_data:/var/lib/mysql postgres: - image: postgres:16.3-alpine@sha256:e89da2c083a5405943408b6807cd1fd25dc9010c1294e30611b841778bedc653 + image: postgres:16.3-alpine@sha256:7b48f843839a3e8b93a750bc5ca8e56b08e9f01466ab7903ff9cd1fc9f0fe259 profiles: - postgres-rabbitmq - postgres-redis From ec49eecced1c35ada45f9979e0d2af4e33d1bf1c Mon Sep 17 00:00:00 2001 From: kiblik Date: Tue, 4 Jun 2024 21:25:06 +0200 Subject: [PATCH 06/65] Use Postgres in rest-framework-tests (#9885) * Use Postgres in rest-framework-tests * Try opposite values --------- Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> --- .github/workflows/rest-framework-tests.yml | 10 +++++----- unittests/test_rest_framework.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rest-framework-tests.yml b/.github/workflows/rest-framework-tests.yml index d50c837efbe..3f1779fe955 100644 --- a/.github/workflows/rest-framework-tests.yml +++ b/.github/workflows/rest-framework-tests.yml @@ -33,19 +33,19 @@ jobs: run: docker/setEnv.sh unit_tests_cicd # phased startup so we can use the exit code from unit test container - - name: Start MySQL - run: docker compose --env-file ./docker/environments/mysql-redis.env up -d mysql + - name: Start Postgres + run: docker compose --env-file ./docker/environments/postgres-redis.env up -d postgres # no celery or initializer needed for unit tests - name: Unit tests - run: docker compose --profile mysql-redis --env-file ./docker/environments/mysql-redis.env up --no-deps --exit-code-from uwsgi uwsgi + run: docker compose --profile postgres-redis --env-file ./docker/environments/postgres-redis.env up --no-deps --exit-code-from uwsgi uwsgi env: DJANGO_VERSION: ${{ matrix.os }} - name: Logs if: failure() - run: docker compose --profile mysql-redis --env-file ./docker/environments/mysql-redis.env logs --tail="2500" uwsgi + run: docker compose --profile postgres-redis --env-file ./docker/environments/postgres-redis.env logs --tail="2500" uwsgi - name: Shutdown if: always() - run: docker compose --profile mysql-redis --env-file ./docker/environments/mysql-redis.env down + run: docker compose --profile postgres-redis --env-file ./docker/environments/postgres-redis.env down diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index 823a10f3b59..32e527b8d97 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -1576,7 +1576,7 @@ def __init__(self, *args, **kwargs): self.permission_create = Permissions.Test_Add self.permission_update = Permissions.Test_Edit self.permission_delete = Permissions.Test_Delete - self.deleted_objects = 18 + self.deleted_objects = 5 BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) @@ -2676,7 +2676,7 @@ def __init__(self, *args, **kwargs): } self.update_fields = {'color': 'blue'} self.test_type = TestType.CONFIGURATION_PERMISSIONS - self.deleted_objects = 2 + self.deleted_objects = 1 BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) From ea8be68b20435c9d4571e9c87c12b9b10588c5fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:37:15 -0500 Subject: [PATCH 07/65] Bump boto3 from 1.34.118 to 1.34.119 (#10342) Bumps [boto3](https://github.com/boto/boto3) from 1.34.118 to 1.34.119. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.118...1.34.119) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 27fc3f8f2c9..c0500ed6ece 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.118 # Required for Celery Broker AWS (SQS) support +boto3==1.34.119 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 83029c6c0361eac97f237c57e960d03016b88446 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:09:58 -0500 Subject: [PATCH 08/65] chore(deps): update dependency ruff from 0.4.7 to v0.4.8 (requirements-lint.txt) (#10344) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements-lint.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-lint.txt b/requirements-lint.txt index 71fa5443a49..5e25262ac38 100644 --- a/requirements-lint.txt +++ b/requirements-lint.txt @@ -1 +1 @@ -ruff==0.4.7 \ No newline at end of file +ruff==0.4.8 \ No newline at end of file From af05ec550755c0706ce7c986e7af8e0e4ee0da26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:10:16 -0500 Subject: [PATCH 09/65] Bump cryptography from 42.0.7 to 42.0.8 (#10341) Bumps [cryptography](https://github.com/pyca/cryptography) from 42.0.7 to 42.0.8. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/42.0.7...42.0.8) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production update-type: version-update:semver-patch ... 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 c0500ed6ece..91f41625482 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ mysqlclient==2.1.1 openpyxl==3.1.3 Pillow==10.3.0 # required by django-imagekit psycopg2-binary==2.9.9 -cryptography==42.0.7 +cryptography==42.0.8 python-dateutil==2.9.0.post0 pytz==2024.1 redis==5.0.4 From bbc79d8b57a7f29028e4267b07e7492da7190da0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:21:21 -0500 Subject: [PATCH 10/65] chore(deps): update postgres:16.3-alpine docker digest from 16.3 to 16.3-alpine (docker-compose.yml) (#10337) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2dddbdb2460..a8fc35c9f42 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -137,7 +137,7 @@ services: volumes: - defectdojo_data:/var/lib/mysql postgres: - image: postgres:16.3-alpine@sha256:7b48f843839a3e8b93a750bc5ca8e56b08e9f01466ab7903ff9cd1fc9f0fe259 + image: postgres:16.3-alpine@sha256:d037653693c4168efbb95cdc1db705d31278a4a8d608d133eca1f07af9793960 profiles: - postgres-rabbitmq - postgres-redis From 54f59b2916eb90453b637eb1ee7c9ced840cf0b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:28:09 -0500 Subject: [PATCH 11/65] Bump redis from 5.0.4 to 5.0.5 (#10350) Bumps [redis](https://github.com/redis/redis-py) from 5.0.4 to 5.0.5. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](https://github.com/redis/redis-py/compare/v5.0.4...v5.0.5) --- updated-dependencies: - dependency-name: redis dependency-type: direct:production update-type: version-update:semver-patch ... 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 91f41625482..92114094d69 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ psycopg2-binary==2.9.9 cryptography==42.0.8 python-dateutil==2.9.0.post0 pytz==2024.1 -redis==5.0.4 +redis==5.0.5 requests==2.32.3 sqlalchemy==2.0.30 # Required by Celery broker transport urllib3==1.26.18 From ec93715819479070f08f2d6046f9089b6c4699a6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:28:49 -0500 Subject: [PATCH 12/65] chore(deps): update helm release rabbitmq from 14.3.3 to ~14.4.0 (helm/defectdojo/chart.yaml) (#10347) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- helm/defectdojo/Chart.lock | 6 +++--- helm/defectdojo/Chart.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index b485770474c..035af5404a8 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -10,9 +10,9 @@ dependencies: version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.3.1 + version: 14.4.0 - name: redis repository: https://charts.bitnami.com/bitnami version: 19.5.0 -digest: sha256:f7d84de0e09aa04522aca1b64fb2a297ad028c507144046f16da47d6750007dd -generated: "2024-05-30T16:46:40.020662037Z" +digest: sha256:a10fdb3b920ee07af57ab5bd51a3644419d75a8092f8192087b6c65d0b94b102 +generated: "2024-06-06T09:34:00.777315379Z" diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 435cbde2193..741bd07a2fa 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -23,7 +23,7 @@ dependencies: alias: postgresqlha condition: postgresqlha.enabled - name: rabbitmq - version: ~14.3.0 + version: ~14.4.0 repository: "https://charts.bitnami.com/bitnami" condition: rabbitmq.enabled - name: redis From 5714e20b619e6fe6f12119430aa36a871d1d573f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:29:28 -0500 Subject: [PATCH 13/65] Bump boto3 from 1.34.119 to 1.34.120 (#10349) Bumps [boto3](https://github.com/boto/boto3) from 1.34.119 to 1.34.120. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.119...1.34.120) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 92114094d69..052b3887c1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.119 # Required for Celery Broker AWS (SQS) support +boto3==1.34.120 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 713b6a98376501489c9ee88ce608db7dbf0d1c9e Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Thu, 6 Jun 2024 21:29:52 +0000 Subject: [PATCH 14/65] 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 f36765a9a80..688f4f5d52f 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.35.1", + "version": "2.36.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 523f51fdd80..423f4050e5c 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.35.1' +__version__ = '2.36.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 8403b51cc38..56203e30611 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.35.1" +appVersion: "2.36.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.133 +version: 1.6.134-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 07c061fcd96474b81a48d2e0b9500b362942ccd8 Mon Sep 17 00:00:00 2001 From: DefectDojo Date: Thu, 6 Jun 2024 21:33:13 +0000 Subject: [PATCH 15/65] Update helm lock file Signed-off-by: DefectDojo --- helm/defectdojo/Chart.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index 035af5404a8..a4d2a57936f 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -4,15 +4,15 @@ dependencies: version: 9.19.1 - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 15.5.1 + version: 15.5.4 - name: postgresql-ha repository: https://charts.bitnami.com/bitnami version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.4.0 + version: 14.4.1 - name: redis repository: https://charts.bitnami.com/bitnami - version: 19.5.0 -digest: sha256:a10fdb3b920ee07af57ab5bd51a3644419d75a8092f8192087b6c65d0b94b102 -generated: "2024-06-06T09:34:00.777315379Z" + version: 19.5.2 +digest: sha256:bbb03050d96cdc317d8088bb62b53a0b892746fd1e5763f7c374da31d3d30895 +generated: "2024-06-06T21:33:03.331847962Z" From a649e76daa074626c54d98f9b2c1c239eb489801 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:07:04 -0500 Subject: [PATCH 16/65] Bump boto3 from 1.34.120 to 1.34.123 (#10380) Bumps [boto3](https://github.com/boto/boto3) from 1.34.120 to 1.34.123. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.120...1.34.123) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 052b3887c1d..17c053c3a26 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.120 # Required for Celery Broker AWS (SQS) support +boto3==1.34.123 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 75b1c675121d32eec377e7bda38133e51c640922 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:56:52 -0500 Subject: [PATCH 17/65] Rest Framework Tests: Isolate tests by request type (#10387) * Rest Framework Tests: Isolate tests by request type * Add explicit ID to be deleted * Typing issue --- unittests/test_rest_framework.py | 581 +++++++++++++++---------------- 1 file changed, 284 insertions(+), 297 deletions(-) diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index 32e527b8d97..ce1ad77da16 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -175,20 +175,6 @@ def wrapper(self, *args, **kwargs): return decorate -# def testIsBroken(method): -# return tag("broken")(method) - - -def check_response_valid(expected_code, response): - def _data_to_str(response): - if hasattr(response, "data"): - return response.data - return None - - assert response.status_code == expected_code, \ - f"Response invalid, returned with code {response.status_code}\nResponse Data:\n{_data_to_str(response)}" - - def format_url(path): return f"{BASE_API_URL}{path}" @@ -367,29 +353,29 @@ def setUp(self): self.url = reverse(self.viewname + '-list') self.schema = open_api3_json_schema + def setUp_not_authorized(self): + testuser = User.objects.get(id=3) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + + def setUp_global_reader(self): + testuser = User.objects.get(id=5) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + + def setUp_global_owner(self): + testuser = User.objects.get(id=6) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + def check_schema(self, schema, obj): schema_checker = SchemaChecker(self.schema["components"]) # print(vars(schema_checker)) schema_checker.check(self.schema, obj) - # def get_valid_object_id(self): - # response = self.client.get(format_url(f"/{self.viewname}/")) - # check_response_valid(status.HTTP_200_OK, response) - # if len(response.data["results"]) == 0: - # return None - - # return response.data["results"][0].get('id', None) - - def get_endpoint_schema(self, path, method): - paths = self.schema["paths"] - methods = paths.get(path, None) - assert methods is not None, f"{path} not found in {list(paths.keys())}" - - endpoint = methods.get(method, None) - assert endpoint is not None, f"Method {method} not found in {list(methods.keys())}" - - return endpoint - def check_schema_response(self, method, status_code, response, detail=False): detail_path = '{id}/' if detail else '' endpoints_schema = self.schema["paths"][format_url(f"/{self.endpoint_path}/{detail_path}")] @@ -397,64 +383,7 @@ def check_schema_response(self, method, status_code, response, detail=False): obj = response.data self.check_schema(schema, obj) - @skipIfNotSubclass(ListModelMixin) - def test_list(self): - # print(open_api3_json_schema) - # validator = ResponseValidator(spec) - - check_for_tags = False - if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): - # create a new instance first to make sure there's at least 1 instance with tags set by payload to trigger tag handling code - logger.debug('creating model with endpoints: %s', self.payload) - response = self.client.post(self.url, self.payload) - self.assertEqual(201, response.status_code, response.content[:1000]) - - # print('response:', response.content[:1000]) - check_for_id = response.data['id'] - # print('id: ', check_for_id) - check_for_tags = self.payload.get('tags', None) - - response = self.client.get(self.url, format='json') - # print('response') - # print(vars(response)) - - # print('response.data') - # print(response.data) - # tags must be present in last entry, the one we created - if check_for_tags: - tags_found = False - for result in response.data['results']: - if result['id'] == check_for_id: - # logger.debug('result.tags: %s', result.get('tags', '')) - self.assertEqual(len(check_for_tags), len(result.get('tags', None))) - for tag in check_for_tags: - # logger.debug('looking for tag %s in tag list %s', tag, result['tags']) - self.assertIn(tag, result['tags']) - tags_found = True - self.assertTrue(tags_found) - - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('get', '200', response) - - @skipIfNotSubclass(CreateModelMixin) - def test_create(self): - length = self.endpoint_model.objects.count() - response = self.client.post(self.url, self.payload) - logger.debug('test_create_response:') - logger.debug(response) - logger.debug(response.data) - self.assertEqual(201, response.status_code, response.content[:1000]) - self.assertEqual(self.endpoint_model.objects.count(), length + 1) - - if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): - self.assertEqual(len(self.payload.get('tags')), len(response.data.get('tags', None))) - for tag in self.payload.get('tags'): - # logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) - self.assertIn(tag, response.data['tags']) - - self.check_schema_response('post', '201', response) - + class RetrieveRequestTest(RESTEndpointTest): @skipIfNotSubclass(RetrieveModelMixin) def test_detail(self): current_objects = self.client.get(self.url, format='json').data @@ -469,80 +398,6 @@ def test_detail(self): self.check_schema_response('get', '200', response, detail=True) - @skipIfNotSubclass(DestroyModelMixin) - def test_delete(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/'.format(current_objects['results'][-1]['id']) - response = self.client.delete(relative_url) - self.assertEqual(204, response.status_code, response.content[:1000]) - - @skipIfNotSubclass(UpdateModelMixin) - def test_update(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) - response = self.client.patch(relative_url, self.update_fields) - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('patch', '200', response, detail=True) - - for key, value in self.update_fields.items(): - # some exception as push_to_jira has been implemented strangely in the update methods in the api - if key not in ['push_to_jira', 'ssh', 'password', 'api_key']: - # Convert data to sets to avoid problems with lists - if isinstance(value, list): - value = set(value) - if isinstance(response.data[key], list): - response_data = set(response.data[key]) - else: - response_data = response.data[key] - self.assertEqual(value, response_data) - - self.assertNotIn('push_to_jira', response.data) - self.assertNotIn('ssh', response.data) - self.assertNotIn('password', response.data) - self.assertNotIn('api_key', response.data) - - if hasattr(self.endpoint_model, 'tags') and self.update_fields and self.update_fields.get('tags', None): - self.assertEqual(len(self.update_fields.get('tags')), len(response.data.get('tags', None))) - for tag in self.update_fields.get('tags'): - logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) - self.assertIn(tag, response.data['tags']) - - response = self.client.put( - relative_url, self.payload) - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('put', '200', response, detail=True) - - @skipIfNotSubclass(DeletePreviewModelMixin) - def test_delete_preview(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/delete_preview/'.format(current_objects['results'][0]['id']) - response = self.client.get(relative_url) - # print('delete_preview response.data') - - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('get', '200', response, detail=True) - - self.assertNotIn('push_to_jira', response.data) - self.assertNotIn('password', response.data) - self.assertNotIn('ssh', response.data) - self.assertNotIn('api_key', response.data) - - self.assertIsInstance(response.data['results'], list) - self.assertGreater(len(response.data['results']), 0, "Length: {}".format(len(response.data['results']))) - - for obj in response.data['results']: - self.assertIsInstance(obj, dict) - self.assertEqual(len(obj), 3) - self.assertIsInstance(obj['model'], str) - if obj['id']: # It needs to be None or int - self.assertIsInstance(obj['id'], int) - self.assertIsInstance(obj['name'], str) - - self.assertEqual(self.deleted_objects, len(response.data['results']), response.content[:1000]) - @skipIfNotSubclass(PrefetchRetrieveMixin) def test_detail_prefetch(self): # print("=======================================================") @@ -571,6 +426,71 @@ def test_detail_prefetch(self): # TODO add schema check + @skipIfNotSubclass(RetrieveModelMixin) + def test_detail_object_not_authorized(self): + if not self.test_type == TestType.OBJECT_PERMISSIONS: + self.skipTest('Authorization is not object based') + + self.setUp_not_authorized() + + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + response = self.client.get(relative_url) + self.assertEqual(404, response.status_code, response.content[:1000]) + + @skipIfNotSubclass(RetrieveModelMixin) + def test_detail_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') + + self.setUp_not_authorized() + + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + response = self.client.get(relative_url) + self.assertEqual(403, response.status_code, response.content[:1000]) + + class ListRequestTest(RESTEndpointTest): + @skipIfNotSubclass(ListModelMixin) + def test_list(self): + # print(open_api3_json_schema) + # validator = ResponseValidator(spec) + + check_for_tags = False + if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): + # create a new instance first to make sure there's at least 1 instance with tags set by payload to trigger tag handling code + logger.debug('creating model with endpoints: %s', self.payload) + response = self.client.post(self.url, self.payload) + self.assertEqual(201, response.status_code, response.content[:1000]) + + # print('response:', response.content[:1000]) + check_for_id = response.data['id'] + # print('id: ', check_for_id) + check_for_tags = self.payload.get('tags', None) + + response = self.client.get(self.url, format='json') + # print('response') + # print(vars(response)) + + # print('response.data') + # print(response.data) + # tags must be present in last entry, the one we created + if check_for_tags: + tags_found = False + for result in response.data['results']: + if result['id'] == check_for_id: + # logger.debug('result.tags: %s', result.get('tags', '')) + self.assertEqual(len(check_for_tags), len(result.get('tags', None))) + for tag in check_for_tags: + # logger.debug('looking for tag %s in tag list %s', tag, result['tags']) + self.assertIn(tag, result['tags']) + tags_found = True + self.assertTrue(tags_found) + + self.assertEqual(200, response.status_code, response.content[:1000]) + + self.check_schema_response('get', '200', response) + @skipIfNotSubclass(PrefetchListMixin) def test_list_prefetch(self): prefetchable_fields = [x[0] for x in _get_prefetchable_fields(self.viewset.serializer_class)] @@ -600,24 +520,6 @@ def test_list_prefetch(self): # TODO add schema check - def setUp_not_authorized(self): - testuser = User.objects.get(id=3) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - - def setUp_global_reader(self): - testuser = User.objects.get(id=5) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - - def setUp_global_owner(self): - testuser = User.objects.get(id=6) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - @skipIfNotSubclass(ListModelMixin) def test_list_object_not_authorized(self): if not self.test_type == TestType.OBJECT_PERMISSIONS: @@ -629,17 +531,34 @@ def test_list_object_not_authorized(self): self.assertFalse(response.data['results']) self.assertEqual(200, response.status_code, response.content[:1000]) - @skipIfNotSubclass(RetrieveModelMixin) - def test_detail_object_not_authorized(self): - if not self.test_type == TestType.OBJECT_PERMISSIONS: - self.skipTest('Authorization is not object based') + @skipIfNotSubclass(ListModelMixin) + def test_list_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') self.setUp_not_authorized() - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' - response = self.client.get(relative_url) - self.assertEqual(404, response.status_code, response.content[:1000]) + response = self.client.get(self.url, format='json') + self.assertEqual(403, response.status_code, response.content[:1000]) + + class CreateRequestTest(RESTEndpointTest): + @skipIfNotSubclass(CreateModelMixin) + def test_create(self): + length = self.endpoint_model.objects.count() + response = self.client.post(self.url, self.payload) + logger.debug('test_create_response:') + logger.debug(response) + logger.debug(response.data) + self.assertEqual(201, response.status_code, response.content[:1000]) + self.assertEqual(self.endpoint_model.objects.count(), length + 1) + + if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): + self.assertEqual(len(self.payload.get('tags')), len(response.data.get('tags', None))) + for tag in self.payload.get('tags'): + # logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) + self.assertIn(tag, response.data['tags']) + + self.check_schema_response('post', '201', response) @skipIfNotSubclass(CreateModelMixin) @patch('dojo.api_v2.permissions.user_has_permission') @@ -655,28 +574,54 @@ def test_create_object_not_authorized(self, mock): ANY, self.permission_create) - @skipIfNotSubclass(DestroyModelMixin) - @patch('dojo.api_v2.permissions.user_has_permission') - def test_delete_object_not_authorized(self, mock): - if not self.test_type == TestType.OBJECT_PERMISSIONS: - self.skipTest('Authorization is not object based') + @skipIfNotSubclass(CreateModelMixin) + def test_create_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') - mock.return_value = False + self.setUp_not_authorized() + response = self.client.post(self.url, self.payload) + self.assertEqual(403, response.status_code, response.content[:1000]) + + class UpdateRequestTest(RESTEndpointTest): + @skipIfNotSubclass(UpdateModelMixin) + def test_update(self): current_objects = self.client.get(self.url, format='json').data relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) - self.client.delete(relative_url) + response = self.client.patch(relative_url, self.update_fields) + self.assertEqual(200, response.status_code, response.content[:1000]) - if self.endpoint_model == Endpoint_Status: - permission_object = Endpoint.objects.get(id=current_objects['results'][0]['endpoint']) - elif self.endpoint_model == JIRA_Issue: - permission_object = Finding.objects.get(id=current_objects['results'][0]['finding']) - else: - permission_object = self.permission_check_class.objects.get(id=current_objects['results'][0]['id']) + self.check_schema_response('patch', '200', response, detail=True) - mock.assert_called_with(User.objects.get(username='admin'), - permission_object, - self.permission_delete) + for key, value in self.update_fields.items(): + # some exception as push_to_jira has been implemented strangely in the update methods in the api + if key not in ['push_to_jira', 'ssh', 'password', 'api_key']: + # Convert data to sets to avoid problems with lists + if isinstance(value, list): + value = set(value) + if isinstance(response.data[key], list): + response_data = set(response.data[key]) + else: + response_data = response.data[key] + self.assertEqual(value, response_data) + + self.assertNotIn('push_to_jira', response.data) + self.assertNotIn('ssh', response.data) + self.assertNotIn('password', response.data) + self.assertNotIn('api_key', response.data) + + if hasattr(self.endpoint_model, 'tags') and self.update_fields and self.update_fields.get('tags', None): + self.assertEqual(len(self.update_fields.get('tags')), len(response.data.get('tags', None))) + for tag in self.update_fields.get('tags'): + logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) + self.assertIn(tag, response.data['tags']) + + response = self.client.put( + relative_url, self.payload) + self.assertEqual(200, response.status_code, response.content[:1000]) + + self.check_schema_response('put', '200', response, detail=True) @skipIfNotSubclass(UpdateModelMixin) @patch('dojo.api_v2.permissions.user_has_permission') @@ -708,70 +653,114 @@ def test_update_object_not_authorized(self, mock): permission_object, self.permission_update) - @skipIfNotSubclass(ListModelMixin) - def test_list_configuration_not_authorized(self): + @skipIfNotSubclass(UpdateModelMixin) + def test_update_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: self.skipTest('Authorization is not configuration based') self.setUp_not_authorized() - response = self.client.get(self.url, format='json') + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + + response = self.client.patch(relative_url, self.update_fields) self.assertEqual(403, response.status_code, response.content[:1000]) - @skipIfNotSubclass(RetrieveModelMixin) - def test_detail_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + response = self.client.put(relative_url, self.payload) + self.assertEqual(403, response.status_code, response.content[:1000]) - self.setUp_not_authorized() + class DeleteRequestTest(RESTEndpointTest): + @skipIfNotSubclass(DestroyModelMixin) + def test_delete(self): + if delete_id := getattr(self, "delete_id", None): + relative_url = f"{self.url}{delete_id}/" + else: + current_objects = self.client.get(self.url, format='json').data + relative_url = f"{self.url}{current_objects['results'][-1]['id']}/" + response = self.client.delete(relative_url) + self.assertEqual(204, response.status_code, response.content[:1000]) + + @skipIfNotSubclass(DeletePreviewModelMixin) + def test_delete_preview(self): + if delete_id := getattr(self, "delete_id", None): + relative_url = f"{self.url}{delete_id}/delete_preview/" + else: + current_objects = self.client.get(self.url, format='json').data + relative_url = f"{self.url}{current_objects['results'][0]['id']}/delete_preview/" - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' response = self.client.get(relative_url) - self.assertEqual(403, response.status_code, response.content[:1000]) + # print('delete_preview response.data') - @skipIfNotSubclass(CreateModelMixin) - def test_create_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + self.assertEqual(200, response.status_code, response.content[:1000]) - self.setUp_not_authorized() + self.check_schema_response('get', '200', response, detail=True) - response = self.client.post(self.url, self.payload) - self.assertEqual(403, response.status_code, response.content[:1000]) + self.assertNotIn('push_to_jira', response.data) + self.assertNotIn('password', response.data) + self.assertNotIn('ssh', response.data) + self.assertNotIn('api_key', response.data) + + self.assertIsInstance(response.data['results'], list) + self.assertGreater(len(response.data['results']), 0, "Length: {}".format(len(response.data['results']))) + + for obj in response.data['results']: + self.assertIsInstance(obj, dict) + self.assertEqual(len(obj), 3) + self.assertIsInstance(obj['model'], str) + if obj['id']: # It needs to be None or int + self.assertIsInstance(obj['id'], int) + self.assertIsInstance(obj['name'], str) + + self.assertEqual(self.deleted_objects, len(response.data['results']), response.content) @skipIfNotSubclass(DestroyModelMixin) - def test_delete_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + @patch('dojo.api_v2.permissions.user_has_permission') + def test_delete_object_not_authorized(self, mock): + if not self.test_type == TestType.OBJECT_PERMISSIONS: + self.skipTest('Authorization is not object based') - self.setUp_not_authorized() + mock.return_value = False - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' - response = self.client.delete(relative_url) - self.assertEqual(403, response.status_code, response.content[:1000]) + current_objects = self.client.get(self.url, format='json').data + relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) + self.client.delete(relative_url) - @skipIfNotSubclass(UpdateModelMixin) - def test_update_configuration_not_authorized(self): + if self.endpoint_model == Endpoint_Status: + permission_object = Endpoint.objects.get(id=current_objects['results'][0]['endpoint']) + elif self.endpoint_model == JIRA_Issue: + permission_object = Finding.objects.get(id=current_objects['results'][0]['finding']) + else: + permission_object = self.permission_check_class.objects.get(id=current_objects['results'][0]['id']) + + mock.assert_called_with(User.objects.get(username='admin'), + permission_object, + self.permission_delete) + + @skipIfNotSubclass(DestroyModelMixin) + def test_delete_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: self.skipTest('Authorization is not configuration based') self.setUp_not_authorized() - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' - - response = self.client.patch(relative_url, self.update_fields) - self.assertEqual(403, response.status_code, response.content[:1000]) - - response = self.client.put(relative_url, self.payload) + if delete_id := getattr(self, "delete_id", None): + relative_url = self.url + f'{delete_id}/' + else: + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + response = self.client.delete(relative_url) self.assertEqual(403, response.status_code, response.content[:1000]) - class MemberEndpointTest(RESTEndpointTest): - def __init__(self, *args, **kwargs): - BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) + class BaseClassTest( + RetrieveRequestTest, + ListRequestTest, + CreateRequestTest, + UpdateRequestTest, + DeleteRequestTest, + ): + pass + class MemberEndpointTest(BaseClassTest): def test_update(self): current_objects = self.client.get(self.url, format='json').data relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) @@ -800,10 +789,7 @@ def test_update_object_not_authorized(self, mock): self.permission_check_class.objects.get(id=current_objects['results'][0]['id']), self.permission_update) - class AuthenticatedViewTest(RESTEndpointTest): - def __init__(self, *args, **kwargs): - BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) - + class AuthenticatedViewTest(BaseClassTest): @skipIfNotSubclass(ListModelMixin) def test_list_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: @@ -827,7 +813,7 @@ def test_detail_configuration_not_authorized(self): self.assertEqual(200, response.status_code, response.content[:1000]) -class AppAnalysisTest(BaseClass.RESTEndpointTest): +class AppAnalysisTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -856,7 +842,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EndpointStatusTest(BaseClass.RESTEndpointTest): +class EndpointStatusTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -947,7 +933,7 @@ def test_update_put_unsuccessful(self): self.assertIn('This endpoint-finding relation already exists', response.content.decode("utf-8")) -class EndpointTest(BaseClass.RESTEndpointTest): +class EndpointTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -974,7 +960,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EngagementTest(BaseClass.RESTEndpointTest): +class EngagementTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1005,7 +991,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class RiskAcceptanceTest(BaseClass.RESTEndpointTest): +class RiskAcceptanceTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1149,7 +1135,7 @@ def test_request_response_get(self): self.assertEqual(200, response.status_code) -class FindingsTest(BaseClass.RESTEndpointTest): +class FindingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1262,7 +1248,7 @@ def test_severity_validation(self): assert result.json()["severity"] == ["Severity must be one of the following: ['Info', 'Low', 'Medium', 'High', 'Critical']"] -class FindingMetadataTest(BaseClass.RESTEndpointTest): +class FindingMetadataTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1324,7 +1310,7 @@ def test_delete(self): assert len(result) == 0, "Metadata not deleted correctly" -class FindingTemplatesTest(BaseClass.RESTEndpointTest): +class FindingTemplatesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1347,7 +1333,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraInstancesTest(BaseClass.RESTEndpointTest): +class JiraInstancesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1377,7 +1363,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraIssuesTest(BaseClass.RESTEndpointTest): +class JiraIssuesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1400,7 +1386,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraProjectTest(BaseClass.RESTEndpointTest): +class JiraProjectTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1427,7 +1413,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class SonarqubeIssueTest(BaseClass.RESTEndpointTest): +class SonarqubeIssueTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1446,7 +1432,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class SonarqubeIssuesTransitionTest(BaseClass.RESTEndpointTest): +class SonarqubeIssuesTransitionTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1465,7 +1451,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class Product_API_Scan_ConfigurationTest(BaseClass.RESTEndpointTest): +class Product_API_Scan_ConfigurationTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1488,7 +1474,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ProductTest(BaseClass.RESTEndpointTest): +class ProductTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1515,7 +1501,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class StubFindingsTest(BaseClass.RESTEndpointTest): +class StubFindingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1546,7 +1532,7 @@ def test_severity_validation(self): assert result.json()["severity"] == ["Severity must be one of the following: ['Info', 'Low', 'Medium', 'High', 'Critical']"] -class TestsTest(BaseClass.RESTEndpointTest): +class TestsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1577,10 +1563,11 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Test_Edit self.permission_delete = Permissions.Test_Delete self.deleted_objects = 5 + self.delete_id = 55 BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolConfigurationsTest(BaseClass.RESTEndpointTest): +class ToolConfigurationsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1606,7 +1593,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolProductSettingsTest(BaseClass.RESTEndpointTest): +class ToolProductSettingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1632,7 +1619,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolTypesTest(BaseClass.RESTEndpointTest): +class ToolTypesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1650,7 +1637,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class NoteTypesTest(BaseClass.RESTEndpointTest): +class NoteTypesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1671,7 +1658,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class NotesTest(BaseClass.RESTEndpointTest): +class NotesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1690,7 +1677,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class UsersTest(BaseClass.RESTEndpointTest): +class UsersTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1735,7 +1722,7 @@ def test_update_user_other_permissions_will_not_leak_and_stay_untouched(self): self.assertEqual(set(user_permissions), set(payload['configuration_permissions'] + [26, 28])) -class UserContactInfoTest(BaseClass.RESTEndpointTest): +class UserContactInfoTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1776,7 +1763,7 @@ def test_user_should_not_have_access_to_product_3_in_detail(self): self.assertEqual(response.status_code, 404) -class ImportScanTest(BaseClass.RESTEndpointTest): +class ImportScanTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2408,7 +2395,7 @@ def test_create_not_authorized_product_name_engagement_name_scan_type_title(self reimporter_mock.assert_not_called() -class ProductTypeTest(BaseClass.RESTEndpointTest): +class ProductTypeTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2449,7 +2436,7 @@ def test_create_authorized_owner(self): self.assertEqual(201, response.status_code, response.content[:1000]) -class DojoGroupsTest(BaseClass.RESTEndpointTest): +class DojoGroupsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2539,7 +2526,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class RolesTest(BaseClass.RESTEndpointTest): +class RolesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2551,7 +2538,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class GlobalRolesTest(BaseClass.RESTEndpointTest): +class GlobalRolesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2589,7 +2576,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Type_Manage_Members self.permission_delete = Permissions.Product_Type_Member_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductMemberTest(BaseClass.MemberEndpointTest): @@ -2612,7 +2599,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Manage_Members self.permission_delete = Permissions.Product_Member_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductTypeGroupTest(BaseClass.MemberEndpointTest): @@ -2635,7 +2622,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Type_Group_Edit self.permission_delete = Permissions.Product_Type_Group_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductGroupTest(BaseClass.MemberEndpointTest): @@ -2658,10 +2645,10 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Group_Edit self.permission_delete = Permissions.Product_Group_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class LanguageTypeTest(BaseClass.RESTEndpointTest): +class LanguageTypeTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2680,7 +2667,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class LanguageTest(BaseClass.RESTEndpointTest): +class LanguageTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2708,7 +2695,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ImportLanguagesTest(BaseClass.RESTEndpointTest): +class ImportLanguagesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2729,7 +2716,7 @@ def __del__(self: object): self.payload['file'].close() def test_create(self): - BaseClass.RESTEndpointTest.test_create(self) + BaseClass.CreateRequestTest.test_create(self) languages = Languages.objects.filter(product=1).order_by('language') @@ -2750,7 +2737,7 @@ def test_create(self): self.assertEqual(languages[1].code, 51056) -class NotificationsTest(BaseClass.RESTEndpointTest): +class NotificationsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2838,7 +2825,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ConfigurationPermissionTest(BaseClass.RESTEndpointTest): +class ConfigurationPermissionTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2850,7 +2837,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class CredentialMappingTest(BaseClass.RESTEndpointTest): +class CredentialMappingTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2873,7 +2860,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class CredentialTest(BaseClass.RESTEndpointTest): +class CredentialTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2895,7 +2882,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class TextQuestionTest(BaseClass.RESTEndpointTest): +class TextQuestionTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2908,7 +2895,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ChoiceQuestionTest(BaseClass.RESTEndpointTest): +class ChoiceQuestionTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2921,7 +2908,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class TextAnswerTest(BaseClass.RESTEndpointTest): +class TextAnswerTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2934,7 +2921,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ChoiceAnswerTest(BaseClass.RESTEndpointTest): +class ChoiceAnswerTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2947,7 +2934,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class GeneralSurveyTest(BaseClass.RESTEndpointTest): +class GeneralSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2960,7 +2947,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EngagementSurveyTest(BaseClass.RESTEndpointTest): +class EngagementSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2973,7 +2960,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class AnsweredSurveyTest(BaseClass.RESTEndpointTest): +class AnsweredSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2986,7 +2973,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class AnnouncementTest(BaseClass.RESTEndpointTest): +class AnnouncementTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): From 94212fb28133c22a973a9460db2989daa4df0c19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 16:26:54 -0500 Subject: [PATCH 18/65] Bump boto3 from 1.34.123 to 1.34.125 (#10398) Bumps [boto3](https://github.com/boto/boto3) from 1.34.123 to 1.34.125. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.123...1.34.125) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 17c053c3a26..c3763ba12ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.123 # Required for Celery Broker AWS (SQS) support +boto3==1.34.125 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 665c6b06ae41cc290bb5f93ec975733b8cb0ddab Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 14 Jun 2024 00:08:09 +0200 Subject: [PATCH 19/65] Upgrade Django to 4.2.13 (#9493) * Upgrade Django to 4.2.10 * Replace MySQL with PostgreSQL (for tests) * RemoteUser tests * Next fixes * Django 4.2.11 * Upgrade to 4.2.13 --- .github/workflows/integration-tests.yml | 10 +-- requirements.txt | 2 +- unittests/test_remote_user.py | 105 ++++++++---------------- unittests/test_user_queries.py | 8 +- 4 files changed, 45 insertions(+), 80 deletions(-) diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 36c951cafec..78b7e373386 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -36,7 +36,7 @@ jobs: "tests/tool_config.py", "openapi-validatator", ] - profile: ["mysql-rabbitmq", "postgres-redis"] + profile: ["postgres-rabbitmq", "postgres-redis"] os: [alpine, debian] fail-fast: false @@ -59,10 +59,10 @@ jobs: - name: Set integration-test mode run: ln -s docker-compose.override.integration_tests.yml docker-compose.override.yml - # phased startup with MySQL and RabbitMQ so we can use the exit code from integrationtest container - - name: Start Dojo MySQL + RabbitMQ - if: matrix.profile == 'mysql-rabbitmq' - run: docker compose --profile ${{ matrix.profile }} --env-file ./docker/environments/${{ matrix.profile }}.env up --no-deps -d mysql nginx celerybeat celeryworker mailhog uwsgi rabbitmq + # phased startup with PostgreSQL and RabbitMQ so we can use the exit code from integrationtest container + - name: Start Dojo PostgreSQL + RabbitMQ + if: matrix.profile == 'postgres-rabbitmq' + run: docker compose --profile ${{ matrix.profile }} --env-file ./docker/environments/${{ matrix.profile }}.env up --no-deps -d postgres nginx celerybeat celeryworker mailhog uwsgi rabbitmq env: DJANGO_VERSION: ${{ matrix.os }} NGINX_VERSION: ${{ matrix.os }} diff --git a/requirements.txt b/requirements.txt index c3763ba12ef..b504fee0ae1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,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==4.1.13 +Django==4.2.13 djangorestframework==3.14.0 html2text==2024.2.26 humanize==4.9.0 diff --git a/unittests/test_remote_user.py b/unittests/test_remote_user.py index c039e006db6..28d9a139bdb 100644 --- a/unittests/test_remote_user.py +++ b/unittests/test_remote_user.py @@ -33,12 +33,9 @@ def test_disabled(self): ) def test_basic(self): resp = self.client1.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - # headers={ - # "Remote-User": self.user.username - # } + headers={ + "Remote-User": self.user.username + } ) self.assertEqual(resp.status_code, 200) @@ -51,18 +48,12 @@ def test_basic(self): ) def test_update_user(self): resp = self.client1.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_FIRSTNAME="new_first", - HTTP_REMOTE_LASTNAME="new_last", - HTTP_REMOTE_EMAIL="new@mail.com", - # headers = { - # "Remote-User": self.user.username, - # "Remote-Firstname": "new_first", - # "Remote-Lastname": "new_last", - # "Remote-Email": "new@mail.com", - # } + headers={ + "Remote-User": self.user.username, + "Remote-Firstname": "new_first", + "Remote-Lastname": "new_last", + "Remote-Email": "new@mail.com", + } ) self.assertEqual(resp.status_code, 200) updated_user = User.objects.get(pk=self.user.pk) @@ -78,14 +69,10 @@ def test_update_user(self): ) def test_update_groups_cleanup(self): resp = self.client1.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_GROUPS=self.group1.name, - # headers = { - # "Remote-User": self.user.username, - # "Remote-Groups": self.group1.name, - # } + headers={ + "Remote-User": self.user.username, + "Remote-Groups": self.group1.name, + } ) self.assertEqual(resp.status_code, 200) dgms = Dojo_Group_Member.objects.filter(user=self.user) @@ -93,14 +80,10 @@ def test_update_groups_cleanup(self): self.assertEqual(dgms.first().group.name, self.group1.name) resp = self.client2.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_GROUPS=self.group2.name, - # headers = { - # "Remote-User": self.user.username, - # "Remote-Groups": self.group2.name, - # } + headers={ + "Remote-User": self.user.username, + "Remote-Groups": self.group2.name, + } ) self.assertEqual(resp.status_code, 200) dgms = Dojo_Group_Member.objects.all().filter(user=self.user) @@ -115,14 +98,10 @@ def test_update_groups_cleanup(self): ) def test_update_multiple_groups_cleanup(self): resp = self.client1.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_GROUPS=f"{self.group1.name},{self.group2.name}", - # headers = { - # "Remote-User": self.user.username, - # "Remote-Groups": f"{self.group1.name},{self.group2.name}", - # } + headers={ + "Remote-User": self.user.username, + "Remote-Groups": f"{self.group1.name},{self.group2.name}", + } ) self.assertEqual(resp.status_code, 200) dgms = Dojo_Group_Member.objects.filter(user=self.user) @@ -136,26 +115,18 @@ def test_update_multiple_groups_cleanup(self): ) def test_update_groups_no_cleanup(self): resp = self.client1.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_GROUPS=self.group1.name, - # headers = { - # "Remote-User": self.user.username, - # "Remote-Groups": self.group1.name, - # } + headers={ + "Remote-User": self.user.username, + "Remote-Groups": self.group1.name, + } ) self.assertEqual(resp.status_code, 200) resp = self.client2.get('/profile', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - HTTP_REMOTE_GROUPS=self.group2.name, - # headers = { - # "Remote-User": self.user.username, - # "Remote-Groups": self.group2.name, - # } + headers={ + "Remote-User": self.user.username, + "Remote-Groups": self.group2.name, + } ) self.assertEqual(resp.status_code, 200) dgms = Dojo_Group_Member.objects.filter(user=self.user) @@ -169,12 +140,9 @@ def test_update_groups_no_cleanup(self): def test_trusted_proxy(self): resp = self.client1.get('/profile', REMOTE_ADDR='192.168.0.42', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - # headers = { - # "Remote-User": self.user.username, - # } + headers={ + "Remote-User": self.user.username, + } ) self.assertEqual(resp.status_code, 200) @@ -187,12 +155,9 @@ def test_untrusted_proxy(self): with self.assertLogs('dojo.remote_user', level='DEBUG') as cm: resp = self.client1.get('/profile', REMOTE_ADDR='192.168.1.42', - # TODO - This can be replaced by following lines in the future - # Using of "headers" is supported since Django 4.2 - HTTP_REMOTE_USER=self.user.username, - # headers = { - # "Remote-User": self.user.username, - # } + headers={ + "Remote-User": self.user.username, + } ) self.assertEqual(resp.status_code, 302) self.assertIn('Requested came from untrusted proxy', cm.output[0]) diff --git a/unittests/test_user_queries.py b/unittests/test_user_queries.py index 3028f04ee84..591ff523073 100644 --- a/unittests/test_user_queries.py +++ b/unittests/test_user_queries.py @@ -59,21 +59,21 @@ def tearDown(self): def test_user_none(self, mock_current_user): mock_current_user.return_value = None - self.assertQuerysetEqual(Dojo_User.objects.none(), get_authorized_users(Permissions.Product_View)) + self.assertQuerySetEqual(Dojo_User.objects.none(), get_authorized_users(Permissions.Product_View)) @patch('dojo.user.queries.get_current_user') def test_user_admin(self, mock_current_user): mock_current_user.return_value = self.admin_user users = Dojo_User.objects.all().order_by('first_name', 'last_name', 'username') - self.assertQuerysetEqual(users, get_authorized_users(Permissions.Product_View)) + self.assertQuerySetEqual(users, get_authorized_users(Permissions.Product_View)) @patch('dojo.user.queries.get_current_user') def test_user_global_permission(self, mock_current_user): mock_current_user.return_value = self.global_permission_user users = Dojo_User.objects.all().order_by('first_name', 'last_name', 'username') - self.assertQuerysetEqual(users, get_authorized_users(Permissions.Product_View)) + self.assertQuerySetEqual(users, get_authorized_users(Permissions.Product_View)) @patch('dojo.user.queries.get_current_user') @patch('dojo.product.queries.get_current_user') @@ -82,4 +82,4 @@ def test_user_regular(self, mock_current_user_1, mock_current_user_2): mock_current_user_2.return_value = self.regular_user users = Dojo_User.objects.exclude(username='invisible_user').order_by('first_name', 'last_name', 'username') - self.assertQuerysetEqual(users, get_authorized_users(Permissions.Product_View)) + self.assertQuerySetEqual(users, get_authorized_users(Permissions.Product_View)) From a4e2409abdb0837e8a30879d5c813af89542da3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:28:06 -0500 Subject: [PATCH 20/65] Bump openpyxl from 3.1.3 to 3.1.4 (#10397) Bumps [openpyxl](https://openpyxl.readthedocs.io) from 3.1.3 to 3.1.4. --- updated-dependencies: - dependency-name: openpyxl dependency-type: direct:production update-type: version-update:semver-patch ... 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 b504fee0ae1..8d8f079dcdb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,7 +33,7 @@ PyGithub==1.58.2 lxml==5.2.2 Markdown==3.6 mysqlclient==2.1.1 -openpyxl==3.1.3 +openpyxl==3.1.4 Pillow==10.3.0 # required by django-imagekit psycopg2-binary==2.9.9 cryptography==42.0.8 From 2e0366ee82aef7c6cfec54cfa45fa051c659947b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:28:25 -0500 Subject: [PATCH 21/65] Update gcr.io/cloudsql-docker/gce-proxy Docker tag from 1.35.3 to v1.35.4 (helm/defectdojo/values.yaml) (#10394) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- helm/defectdojo/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/defectdojo/values.yaml b/helm/defectdojo/values.yaml index 75f3d540012..1faba1520b3 100644 --- a/helm/defectdojo/values.yaml +++ b/helm/defectdojo/values.yaml @@ -457,7 +457,7 @@ cloudsql: image: # set repo and image tag of gce-proxy repository: gcr.io/cloudsql-docker/gce-proxy - tag: 1.35.3 + tag: 1.35.4 pullPolicy: IfNotPresent # set CloudSQL instance: 'project:zone:instancename' instance: "" From 457d1c4ade2c1088e43434c9fcfe077c1a2174b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:51:05 -0500 Subject: [PATCH 22/65] Bump redis from 5.0.5 to 5.0.6 (#10405) Bumps [redis](https://github.com/redis/redis-py) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](https://github.com/redis/redis-py/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: redis dependency-type: direct:production update-type: version-update:semver-patch ... 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 8d8f079dcdb..48ce87d39e7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ psycopg2-binary==2.9.9 cryptography==42.0.8 python-dateutil==2.9.0.post0 pytz==2024.1 -redis==5.0.5 +redis==5.0.6 requests==2.32.3 sqlalchemy==2.0.30 # Required by Celery broker transport urllib3==1.26.18 From b6b21dc6f1d5e6eb4cfe8d994620ebff7e66a71b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:51:15 -0500 Subject: [PATCH 23/65] Bump boto3 from 1.34.125 to 1.34.126 (#10404) Bumps [boto3](https://github.com/boto/boto3) from 1.34.125 to 1.34.126. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.125...1.34.126) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 48ce87d39e7..9f701f6a2fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.125 # Required for Celery Broker AWS (SQS) support +boto3==1.34.126 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From c2ba164198921eaa14e0442eee835f3eef2c70be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:51:28 -0500 Subject: [PATCH 24/65] Bump packageurl-python from 0.15.0 to 0.15.1 (#10403) Bumps [packageurl-python](https://github.com/package-url/packageurl-python) from 0.15.0 to 0.15.1. - [Release notes](https://github.com/package-url/packageurl-python/releases) - [Changelog](https://github.com/package-url/packageurl-python/blob/main/CHANGELOG.rst) - [Commits](https://github.com/package-url/packageurl-python/compare/v0.15.0...v0.15.1) --- updated-dependencies: - dependency-name: packageurl-python dependency-type: direct:production update-type: version-update:semver-patch ... 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 9f701f6a2fc..dddae816752 100644 --- a/requirements.txt +++ b/requirements.txt @@ -54,7 +54,7 @@ gitpython==3.1.43 debugpy==1.8.1 python-gitlab==4.6.0 cpe==1.2.1 -packageurl-python==0.15.0 +packageurl-python==0.15.1 django-crum==0.7.9 JSON-log-formatter==1.0 django-split-settings==1.3.1 From f4c99b9c8da879aa02bf6b17904ae687bc0a3dfe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:37:21 -0500 Subject: [PATCH 25/65] Update dependency ruff from 0.4.8 to v0.4.9 (requirements-lint.txt) (#10406) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements-lint.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-lint.txt b/requirements-lint.txt index 5e25262ac38..583b50b73f4 100644 --- a/requirements-lint.txt +++ b/requirements-lint.txt @@ -1 +1 @@ -ruff==0.4.8 \ No newline at end of file +ruff==0.4.9 \ No newline at end of file From c7fb68441a30dc27449e2105c9c25c5154dcc648 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:04:12 -0500 Subject: [PATCH 26/65] Bump django-filter from 23.5 to 24.2 (#9993) Dependabot couldn't find the original pull request head commit, 092e0a3066d312e74b31567ea9362df2aff960c7. 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 dddae816752..aa90d1a725d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ django_celery_results==2.5.1 django-auditlog==2.3.0 django-dbbackup==4.1.0 django-environ==0.11.2 -django-filter==23.5 +django-filter==24.2 django-imagekit==5.0.0 # This library is very outdated, but is a pillar of DefectDojo # django-multiselectfield==0.1.12 From 3dad729d9c8581af65cce3bea5c5d38009efa920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:10:37 -0500 Subject: [PATCH 27/65] Bump django-debug-toolbar from 4.3.0 to 4.4.2 (#10274) Bumps [django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar) from 4.3.0 to 4.4.2. - [Release notes](https://github.com/jazzband/django-debug-toolbar/releases) - [Changelog](https://github.com/jazzband/django-debug-toolbar/blob/main/docs/changes.rst) - [Commits](https://github.com/jazzband/django-debug-toolbar/compare/4.3...4.4.2) --- updated-dependencies: - dependency-name: django-debug-toolbar dependency-type: direct:production update-type: version-update:semver-minor ... 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 aa90d1a725d..02829e3a37f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -58,7 +58,7 @@ packageurl-python==0.15.1 django-crum==0.7.9 JSON-log-formatter==1.0 django-split-settings==1.3.1 -django-debug-toolbar==4.3.0 +django-debug-toolbar==4.4.2 django-debug-toolbar-request-history==0.1.4 vcrpy==6.0.1 vcrpy-unittest==0.1.7 From 0b1153d27ab1b33446e12d04e972cdd6504b07aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:13:17 -0500 Subject: [PATCH 28/65] Bump django-crispy-forms from 2.0 to 2.2 (#10414) Bumps [django-crispy-forms](https://github.com/django-crispy-forms/django-crispy-forms) from 2.0 to 2.2. - [Release notes](https://github.com/django-crispy-forms/django-crispy-forms/releases) - [Changelog](https://github.com/django-crispy-forms/django-crispy-forms/blob/main/CHANGELOG.md) - [Commits](https://github.com/django-crispy-forms/django-crispy-forms/compare/2.0...2.2) --- updated-dependencies: - dependency-name: django-crispy-forms dependency-type: direct:production update-type: version-update:semver-minor ... 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 02829e3a37f..86929de7dd0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ django-imagekit==5.0.0 # django-multiselectfield==0.1.12 git+https://github.com/DefectDojo/django-multiselectfield@master#egg=django-multiselectfield django-polymorphic==3.1.0 -django-crispy-forms==2.0 +django-crispy-forms==2.2 django_extensions==3.2.3 django-slack==5.19.0 # This library is very outdated and not directly. It is used solely for migration From a2a1f9efbc4b618f0c256c33f5604bf0408d3b16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:48:52 -0500 Subject: [PATCH 29/65] Bump boto3 from 1.34.126 to 1.34.127 (#10415) Bumps [boto3](https://github.com/boto/boto3) from 1.34.126 to 1.34.127. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.126...1.34.127) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 86929de7dd0..95219daa0d6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.126 # Required for Celery Broker AWS (SQS) support +boto3==1.34.127 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 16c8627d39c3d9e8b3d24b254040cdb615d6291c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:50:27 -0500 Subject: [PATCH 30/65] Update docker/build-push-action action from v5 to v6 (.github/workflows/release-x-manual-docker-containers.yml) (#10413) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-docker-images-for-testing.yml | 2 +- .github/workflows/release-x-manual-docker-containers.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docker-images-for-testing.yml b/.github/workflows/build-docker-images-for-testing.yml index 00ffd8aff16..de040266a13 100644 --- a/.github/workflows/build-docker-images-for-testing.yml +++ b/.github/workflows/build-docker-images-for-testing.yml @@ -35,7 +35,7 @@ jobs: - name: Build id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 timeout-minutes: 10 with: context: . diff --git a/.github/workflows/release-x-manual-docker-containers.yml b/.github/workflows/release-x-manual-docker-containers.yml index 87d23a2a4db..6e167143783 100644 --- a/.github/workflows/release-x-manual-docker-containers.yml +++ b/.github/workflows/release-x-manual-docker-containers.yml @@ -63,7 +63,7 @@ jobs: - name: Build and push images with debian if: ${{ matrix.os == 'debian' }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 env: REPO_ORG: ${{ env.repoorg }} docker-image: ${{ matrix.docker-image }} @@ -77,7 +77,7 @@ jobs: - name: Build and push images with alpine if: ${{ matrix.os == 'alpine' }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 env: REPO_ORG: ${{ env.repoorg }} docker-image: ${{ matrix.docker-image }} From b48b2967572595538d012bb785f02e10e5e4049b Mon Sep 17 00:00:00 2001 From: DefectDojo Date: Mon, 17 Jun 2024 17:26:54 +0000 Subject: [PATCH 31/65] Update helm lock file Signed-off-by: DefectDojo --- helm/defectdojo/Chart.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index b485770474c..83b888f255e 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -4,15 +4,15 @@ dependencies: version: 9.19.1 - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 15.5.1 + version: 15.5.6 - name: postgresql-ha repository: https://charts.bitnami.com/bitnami version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.3.1 + version: 14.3.3 - name: redis repository: https://charts.bitnami.com/bitnami - version: 19.5.0 -digest: sha256:f7d84de0e09aa04522aca1b64fb2a297ad028c507144046f16da47d6750007dd -generated: "2024-05-30T16:46:40.020662037Z" + version: 19.5.4 +digest: sha256:4885a27b46b53bf0b395d92f5a02342e20606e4102c809b051588b4a6ebe29b3 +generated: "2024-06-17T17:26:44.734605574Z" From 017a06becdc2fe146f4630b45b67e55d133679ff Mon Sep 17 00:00:00 2001 From: DefectDojo Date: Mon, 17 Jun 2024 17:37:58 +0000 Subject: [PATCH 32/65] Update helm lock file Signed-off-by: DefectDojo --- helm/defectdojo/Chart.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index 2c0127e864f..28c80976067 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -10,9 +10,9 @@ dependencies: version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.4.1 + version: 14.4.3 - name: redis repository: https://charts.bitnami.com/bitnami - version: 19.5.2 -digest: sha256:bbb03050d96cdc317d8088bb62b53a0b892746fd1e5763f7c374da31d3d30895 -generated: "2024-06-06T21:33:03.331847962Z" + version: 19.5.4 +digest: sha256:dfc4c827cf13859928ebf770e5a384721ea67ecedab22fd7baf0e6ede28c6fd4 +generated: "2024-06-17T17:37:48.301414062Z" From 033fa24faf19de909a95a71c9c58e8eab750761c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:21:39 -0500 Subject: [PATCH 33/65] Bump boto3 from 1.34.127 to 1.34.128 (#10425) Bumps [boto3](https://github.com/boto/boto3) from 1.34.127 to 1.34.128. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.127...1.34.128) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 95219daa0d6..5c6d27c84f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.127 # Required for Celery Broker AWS (SQS) support +boto3==1.34.128 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From e85e211d522c3690a4fd3e526637aa27fe54a242 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:29:00 -0500 Subject: [PATCH 34/65] Bump boto3 from 1.34.128 to 1.34.130 (#10436) Bumps [boto3](https://github.com/boto/boto3) from 1.34.128 to 1.34.130. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.128...1.34.130) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 5c6d27c84f0..6135457e0cc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.128 # Required for Celery Broker AWS (SQS) support +boto3==1.34.130 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 981f345f6a0c49545f18a91931713bcdaacfefca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 09:29:24 -0500 Subject: [PATCH 35/65] Bump sqlalchemy from 2.0.30 to 2.0.31 (#10432) Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.30 to 2.0.31. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) --- updated-dependencies: - dependency-name: sqlalchemy dependency-type: direct:production update-type: version-update:semver-patch ... 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 6135457e0cc..befd7adceb0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,7 @@ python-dateutil==2.9.0.post0 pytz==2024.1 redis==5.0.6 requests==2.32.3 -sqlalchemy==2.0.30 # Required by Celery broker transport +sqlalchemy==2.0.31 # Required by Celery broker transport urllib3==1.26.18 uWSGI==2.0.26 vobject==0.9.7 From 30050914bcde0fac877b2f221b2ed6fe12e1482d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 11:57:40 -0500 Subject: [PATCH 36/65] chore(deps): update postgres:16.3-alpine docker digest from 16.3 to 16.3-alpine (docker-compose.yml) (#10427) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7394a10c702..439e3dad55b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -141,7 +141,7 @@ services: volumes: - defectdojo_data:/var/lib/mysql postgres: - image: postgres:16.3-alpine@sha256:d037653693c4168efbb95cdc1db705d31278a4a8d608d133eca1f07af9793960 + image: postgres:16.3-alpine@sha256:3af2a1dcee958ad1806f9025500ffa7529de998d144bdb26baf878ae9ee44f45 profiles: - postgres-rabbitmq - postgres-redis From 758e0d88821abee6d905de3c99bf5fa521d3a973 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Thu, 20 Jun 2024 21:11:43 +0200 Subject: [PATCH 37/65] Ruff: more safe TRY (#10114) --- ruff.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruff.toml b/ruff.toml index 20593fa2390..ba33cd51f1a 100644 --- a/ruff.toml +++ b/ruff.toml @@ -49,8 +49,10 @@ select = [ "SLOT", "PD", "PGH", + "TRY003", "TRY004", "TRY2", + "TRY302", "FLY", "NPY", "AIR", From efe7b29ed185dee45e7db88dfdb9bf5b138e1d29 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Thu, 20 Jun 2024 21:13:10 +0200 Subject: [PATCH 38/65] Ruff: add T10 (#10087) --- dojo/wsgi.py | 6 +++--- ruff.toml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dojo/wsgi.py b/dojo/wsgi.py index 8f6a14863fe..1f79043d491 100644 --- a/dojo/wsgi.py +++ b/dojo/wsgi.py @@ -40,17 +40,17 @@ def is_debugger_listening(port): if os.environ.get("DD_DEBUG") == "True" and not os.getenv("RUN_MAIN") and is_debugger_listening(debugpy_port) != 0: logger.info(f"DD_DEBUG is set to True, setting remote debugging on port {debugpy_port}") try: - import debugpy + import debugpy # noqa: T100 # Required, otherwise debugpy will try to use the uwsgi binary as the python interpreter - https://github.com/microsoft/debugpy/issues/262 debugpy.configure({ "python": "python", "subProcess": True }) - debugpy.listen(("0.0.0.0", debugpy_port)) + debugpy.listen(("0.0.0.0", debugpy_port)) # noqa: T100 if os.environ.get("DD_DEBUG_WAIT_FOR_CLIENT") == "True": logger.info(f"Waiting for the debugging client to connect on port {debugpy_port}") - debugpy.wait_for_client() + debugpy.wait_for_client() # noqa: T100 print("Debugging client connected, resuming execution") except RuntimeError as e: if str(e) != "Can't listen for client connections: [Errno 98] Address already in use": diff --git a/ruff.toml b/ruff.toml index ba33cd51f1a..f787b3be903 100644 --- a/ruff.toml +++ b/ruff.toml @@ -42,6 +42,7 @@ select = [ "EXE", "TRIO", "C4", + "T10", "DJ003", "DJ012", "DJ013", "EM", "ICN", From 0e53d513495b670a179b29c203b7fa4b41523ac7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:26:07 -0500 Subject: [PATCH 39/65] chore(deps): update dependency ruff from 0.4.9 to v0.4.10 (requirements-lint.txt) (#10438) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- requirements-lint.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-lint.txt b/requirements-lint.txt index 583b50b73f4..e022cdb619e 100644 --- a/requirements-lint.txt +++ b/requirements-lint.txt @@ -1 +1 @@ -ruff==0.4.9 \ No newline at end of file +ruff==0.4.10 \ No newline at end of file From d537ecbf502765a6f922b74f64d34078fb11e136 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:31:17 -0500 Subject: [PATCH 40/65] chore(deps): update postgres:16.3-alpine docker digest from 16.3 to 16.3-alpine (docker-compose.yml) (#10439) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 439e3dad55b..6f5953d3909 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -141,7 +141,7 @@ services: volumes: - defectdojo_data:/var/lib/mysql postgres: - image: postgres:16.3-alpine@sha256:3af2a1dcee958ad1806f9025500ffa7529de998d144bdb26baf878ae9ee44f45 + image: postgres:16.3-alpine@sha256:2463c8fa10dd52951104d1195ed25ea5c25ebcd2c394e5020385f6a15d5ffb30 profiles: - postgres-rabbitmq - postgres-redis From 73fd8d5b661c22cb72d7c63b37c9fb333d753e09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:25:16 -0500 Subject: [PATCH 41/65] Bump boto3 from 1.34.130 to 1.34.131 (#10443) Bumps [boto3](https://github.com/boto/boto3) from 1.34.130 to 1.34.131. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.130...1.34.131) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 befd7adceb0..cfe71cf6649 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.130 # Required for Celery Broker AWS (SQS) support +boto3==1.34.131 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 8889b92757d2ba7a16472aa77fdbe8a2cbd6b1bb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:25:57 -0500 Subject: [PATCH 42/65] chore(deps): update redis:7.2.5-alpine docker digest from 7.2.5 to 7.2.5-alpine (docker-compose.yml) (#10442) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6f5953d3909..e2aa562e388 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -159,7 +159,7 @@ services: volumes: - defectdojo_rabbitmq:/var/lib/rabbitmq redis: - image: redis:7.2.5-alpine@sha256:0389bb8416d7c6ed065c25745179bf5d358e5d9472dd30a687ab36ffbb650262 + image: redis:7.2.5-alpine@sha256:01cb7ee5a842520da74d523f2eed2bd5ddab54ad21a1f0de3dbd3db05411e39a profiles: - mysql-redis - postgres-redis From a9473534ee5e304d0cb4326d7a8fafa223e59eee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:50:33 -0500 Subject: [PATCH 43/65] chore(deps): update postgres:16.3-alpine docker digest from 16.3 to 16.3-alpine (docker-compose.yml) (#10441) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e2aa562e388..2b4ad96205f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -141,7 +141,7 @@ services: volumes: - defectdojo_data:/var/lib/mysql postgres: - image: postgres:16.3-alpine@sha256:2463c8fa10dd52951104d1195ed25ea5c25ebcd2c394e5020385f6a15d5ffb30 + image: postgres:16.3-alpine@sha256:de3d7b6e4b5b3fe899e997579d6dfe95a99539d154abe03f0b6839133ed05065 profiles: - postgres-rabbitmq - postgres-redis From 773488b3629627bd47d3a6c81ba85cb9aeab3f5c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:38:08 -0500 Subject: [PATCH 44/65] chore(deps): update redis:7.2.5-alpine docker digest from 7.2.5 to 7.2.5-alpine (docker-compose.yml) (#10444) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2b4ad96205f..36dec075328 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -159,7 +159,7 @@ services: volumes: - defectdojo_rabbitmq:/var/lib/rabbitmq redis: - image: redis:7.2.5-alpine@sha256:01cb7ee5a842520da74d523f2eed2bd5ddab54ad21a1f0de3dbd3db05411e39a + image: redis:7.2.5-alpine@sha256:de14eedfbd1fc871d0f5aa1773fd80743930e45354d035b6f3b551e7ffa44df8 profiles: - mysql-redis - postgres-redis From d5f8925ae9d9f8955c4de4d5a4df480e28252c3c Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:12:35 +0200 Subject: [PATCH 45/65] feat(email notif): Scan_added - put findings to `
` (#10253) --- dojo/templates/notifications/mail/scan_added.tpl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/dojo/templates/notifications/mail/scan_added.tpl b/dojo/templates/notifications/mail/scan_added.tpl index ce09eecd4ca..513b24818db 100644 --- a/dojo/templates/notifications/mail/scan_added.tpl +++ b/dojo/templates/notifications/mail/scan_added.tpl @@ -16,40 +16,48 @@ {% blocktranslate %}{{ finding_count }} findings have been updated for while a scan was uploaded{% endblocktranslate %}: {{product}} / {{ engagement.name }} / {{ test }}

- {% blocktranslate %}New findings{% endblocktranslate %}:
+
+ {% blocktranslate %}New findings{% endblocktranslate %} ({{ findings_new | length }})
{% for finding in findings_new %} {% url 'view_finding' finding.id as finding_url %} {{ finding.title }} ({{ finding.severity }})
{% empty %} {% trans "None" %}
{% endfor %} +

- {% blocktranslate %}Reactivated findings{% endblocktranslate %}:
+

+ {% blocktranslate %}Reactivated findings{% endblocktranslate %} ({{ findings_reactivated | length }})
{% for finding in findings_reactivated %} {% url 'view_finding' finding.id as finding_url %} {{ finding.title }} ({{ finding.severity }})
{% empty %} {% trans "None" %}
{% endfor %} +

- {% blocktranslate %}Closed findings{% endblocktranslate %}:
+

+ {% blocktranslate %}Closed findings{% endblocktranslate %} ({{ findings_mitigated | length }})
{% for finding in findings_mitigated %} {% url 'view_finding' finding.id as finding_url %} {{ finding.title }} ({{ finding.severity }})
{% empty %} {% trans "None" %}
{% endfor %} +

- {% blocktranslate %}Untouched findings{% endblocktranslate %}:
+

+ {% blocktranslate %}Untouched findings{% endblocktranslate %} ({{ findings_untouched | length }})
{% for finding in findings_untouched %} {% url 'view_finding' finding.id as finding_url %} {{ finding.title }} ({{ finding.severity }})
{% empty %} {% trans "None" %}
{% endfor %} +



{% trans "Kind regards" %}, From c8e1b09547406a00bcb3a017475ff60630982955 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:13:34 +0200 Subject: [PATCH 46/65] Shuffle tests (#10335) --- docker/entrypoint-unit-tests-devDocker.sh | 2 +- docker/entrypoint-unit-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/entrypoint-unit-tests-devDocker.sh b/docker/entrypoint-unit-tests-devDocker.sh index c590974b1b4..6872d8668fc 100755 --- a/docker/entrypoint-unit-tests-devDocker.sh +++ b/docker/entrypoint-unit-tests-devDocker.sh @@ -53,7 +53,7 @@ EOF echo "Unit Tests" echo "------------------------------------------------------------" -python3 manage.py test unittests -v 3 --keepdb --no-input +python3 manage.py test unittests -v 3 --keepdb --no-input --shuffle # you can select a single file to "test" unit tests # python3 manage.py test unittests.tools.test_npm_audit_scan_parser.TestNpmAuditParser --keepdb -v 3 diff --git a/docker/entrypoint-unit-tests.sh b/docker/entrypoint-unit-tests.sh index 6c45ce489d6..a356283c377 100755 --- a/docker/entrypoint-unit-tests.sh +++ b/docker/entrypoint-unit-tests.sh @@ -79,4 +79,4 @@ python3 manage.py migrate echo "Unit Tests" echo "------------------------------------------------------------" -python3 manage.py test unittests -v 3 --keepdb --no-input +python3 manage.py test unittests -v 3 --keepdb --no-input --shuffle From aafeaf272c9463d4f45aa714fb2e8906351cf871 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:21:32 +0200 Subject: [PATCH 47/65] feat(api - user contact): Add all user data (#10416) --- dojo/api_v2/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index fe8fe2d60b7..4de5d536d07 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -559,6 +559,8 @@ def validate(self, data): class UserContactInfoSerializer(serializers.ModelSerializer): + user_profile = UserSerializer(many=False, source="user", read_only=True) + class Meta: model = UserContactInfo fields = "__all__" From 9dcb7f9bc6cd7505f59db95709334ddc2de3b29b Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:21:57 +0200 Subject: [PATCH 48/65] fix(Risk_Acceptance): Remove redundancy in strings of Treatments (#10361) --- dojo/models.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dojo/models.py b/dojo/models.py index 415bc6b4567..5de06d42743 100644 --- a/dojo/models.py +++ b/dojo/models.py @@ -3614,22 +3614,22 @@ class Risk_Acceptance(models.Model): TREATMENT_FIX = 'F' TREATMENT_TRANSFER = 'T' - TREATMENT_CHOICES = [ - (TREATMENT_ACCEPT, 'Accept (The risk is acknowledged, yet remains)'), - (TREATMENT_AVOID, 'Avoid (Do not engage with whatever creates the risk)'), - (TREATMENT_MITIGATE, 'Mitigate (The risk still exists, yet compensating controls make it less of a threat)'), - (TREATMENT_FIX, 'Fix (The risk is eradicated)'), - (TREATMENT_TRANSFER, 'Transfer (The risk is transferred to a 3rd party)'), - ] - TREATMENT_TRANSLATIONS = { - 'A': 'Accept (The risk is acknowledged, yet remains)', - 'V': 'Avoid (Do not engage with whatever creates the risk)', - 'M': 'Mitigate (The risk still exists, yet compensating controls make it less of a threat)', - 'F': 'Fix (The risk is eradicated)', - 'T': 'Transfer (The risk is transferred to a 3rd party)', + TREATMENT_ACCEPT: _('Accept (The risk is acknowledged, yet remains)'), + TREATMENT_AVOID: _('Avoid (Do not engage with whatever creates the risk)'), + TREATMENT_MITIGATE: _('Mitigate (The risk still exists, yet compensating controls make it less of a threat)'), + TREATMENT_FIX: _('Fix (The risk is eradicated)'), + TREATMENT_TRANSFER: _('Transfer (The risk is transferred to a 3rd party)'), } + TREATMENT_CHOICES = [ + (TREATMENT_ACCEPT, TREATMENT_TRANSLATIONS[TREATMENT_ACCEPT]), + (TREATMENT_AVOID, TREATMENT_TRANSLATIONS[TREATMENT_AVOID]), + (TREATMENT_MITIGATE, TREATMENT_TRANSLATIONS[TREATMENT_MITIGATE]), + (TREATMENT_FIX, TREATMENT_TRANSLATIONS[TREATMENT_FIX]), + (TREATMENT_TRANSFER, TREATMENT_TRANSLATIONS[TREATMENT_TRANSFER]), + ] + name = models.CharField(max_length=300, null=False, blank=False, help_text=_("Descriptive name which in the future may also be used to group risk acceptances together across engagements and products")) accepted_findings = models.ManyToManyField(Finding) From 08ff9e949c4b1cdb5c4471ac91d94c2d39ed5c51 Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:22:32 +0200 Subject: [PATCH 49/65] Ruff: add and fix INP (#10089) --- docker/install_chrome_dependencies.py | 1 + dojo/importers/__init__.py | 0 dojo/settings/attribute-maps/__init__.py | 0 dojo/tools/nancy/__init__.py | 0 dojo/tools/pwn_sast/__init__.py | 0 ruff.toml | 1 + 6 files changed, 2 insertions(+) create mode 100644 dojo/importers/__init__.py create mode 100644 dojo/settings/attribute-maps/__init__.py create mode 100644 dojo/tools/nancy/__init__.py create mode 100644 dojo/tools/pwn_sast/__init__.py diff --git a/docker/install_chrome_dependencies.py b/docker/install_chrome_dependencies.py index 5f4f714a430..2bf949c86ca 100644 --- a/docker/install_chrome_dependencies.py +++ b/docker/install_chrome_dependencies.py @@ -1,3 +1,4 @@ +# noqa: INP001 """ This solution is largely based on the Playwright's browser dependencies script at https://github.com/microsoft/playwright/blob/main/utils/linux-browser-dependencies/inside_docker/list_dependencies.js diff --git a/dojo/importers/__init__.py b/dojo/importers/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dojo/settings/attribute-maps/__init__.py b/dojo/settings/attribute-maps/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dojo/tools/nancy/__init__.py b/dojo/tools/nancy/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/dojo/tools/pwn_sast/__init__.py b/dojo/tools/pwn_sast/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ruff.toml b/ruff.toml index f787b3be903..fd293dc6ddf 100644 --- a/ruff.toml +++ b/ruff.toml @@ -47,6 +47,7 @@ select = [ "EM", "ICN", "LOG", + "INP", "SLOT", "PD", "PGH", From 4c1198989849b8e164cb90003fa849a0bc057c5a Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:24:08 +0200 Subject: [PATCH 50/65] Ruff: Add safe S* rules, fix order for EXE (#10084) --- ruff.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ruff.toml b/ruff.toml index fd293dc6ddf..b6d1566e9f1 100644 --- a/ruff.toml +++ b/ruff.toml @@ -39,12 +39,13 @@ select = [ "UP", "YTT", "ASYNC", - "EXE", "TRIO", + "S2", "S5", "S7", "C4", "T10", "DJ003", "DJ012", "DJ013", "EM", + "EXE", "ICN", "LOG", "INP", From 9b05b1060171bf99325140601b8848e7d30d3a7e Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:24:43 +0200 Subject: [PATCH 51/65] fix(passwords): Merge clean location of login related templates (#10340) --- .../mail => login}/forgot_password.tpl | 0 dojo/templates/{dojo => login}/forgot_username.html | 0 .../mail => login}/forgot_username.tpl | 0 .../{dojo => login}/forgot_username_done.html | 0 .../{dojo => login}/forgot_username_subject.html | 0 dojo/templates/{dojo => login}/password_reset.html | 0 .../{dojo => login}/password_reset_complete.html | 0 .../{dojo => login}/password_reset_confirm.html | 0 .../{dojo => login}/password_reset_done.html | 0 dojo/user/urls.py | 12 ++++++------ dojo/user/views.py | 6 +++--- 11 files changed, 9 insertions(+), 9 deletions(-) rename dojo/templates/{notifications/mail => login}/forgot_password.tpl (100%) rename dojo/templates/{dojo => login}/forgot_username.html (100%) rename dojo/templates/{notifications/mail => login}/forgot_username.tpl (100%) rename dojo/templates/{dojo => login}/forgot_username_done.html (100%) rename dojo/templates/{dojo => login}/forgot_username_subject.html (100%) rename dojo/templates/{dojo => login}/password_reset.html (100%) rename dojo/templates/{dojo => login}/password_reset_complete.html (100%) rename dojo/templates/{dojo => login}/password_reset_confirm.html (100%) rename dojo/templates/{dojo => login}/password_reset_done.html (100%) diff --git a/dojo/templates/notifications/mail/forgot_password.tpl b/dojo/templates/login/forgot_password.tpl similarity index 100% rename from dojo/templates/notifications/mail/forgot_password.tpl rename to dojo/templates/login/forgot_password.tpl diff --git a/dojo/templates/dojo/forgot_username.html b/dojo/templates/login/forgot_username.html similarity index 100% rename from dojo/templates/dojo/forgot_username.html rename to dojo/templates/login/forgot_username.html diff --git a/dojo/templates/notifications/mail/forgot_username.tpl b/dojo/templates/login/forgot_username.tpl similarity index 100% rename from dojo/templates/notifications/mail/forgot_username.tpl rename to dojo/templates/login/forgot_username.tpl diff --git a/dojo/templates/dojo/forgot_username_done.html b/dojo/templates/login/forgot_username_done.html similarity index 100% rename from dojo/templates/dojo/forgot_username_done.html rename to dojo/templates/login/forgot_username_done.html diff --git a/dojo/templates/dojo/forgot_username_subject.html b/dojo/templates/login/forgot_username_subject.html similarity index 100% rename from dojo/templates/dojo/forgot_username_subject.html rename to dojo/templates/login/forgot_username_subject.html diff --git a/dojo/templates/dojo/password_reset.html b/dojo/templates/login/password_reset.html similarity index 100% rename from dojo/templates/dojo/password_reset.html rename to dojo/templates/login/password_reset.html diff --git a/dojo/templates/dojo/password_reset_complete.html b/dojo/templates/login/password_reset_complete.html similarity index 100% rename from dojo/templates/dojo/password_reset_complete.html rename to dojo/templates/login/password_reset_complete.html diff --git a/dojo/templates/dojo/password_reset_confirm.html b/dojo/templates/login/password_reset_confirm.html similarity index 100% rename from dojo/templates/dojo/password_reset_confirm.html rename to dojo/templates/login/password_reset_confirm.html diff --git a/dojo/templates/dojo/password_reset_done.html b/dojo/templates/login/password_reset_done.html similarity index 100% rename from dojo/templates/dojo/password_reset_done.html rename to dojo/templates/login/password_reset_done.html diff --git a/dojo/user/urls.py b/dojo/user/urls.py index 22fb861e22f..adf3dd80cb7 100644 --- a/dojo/user/urls.py +++ b/dojo/user/urls.py @@ -30,26 +30,26 @@ if settings.FORGOT_PASSWORD: urlpatterns.extend([ re_path(r'^password_reset/$', views.DojoPasswordResetView.as_view( - template_name='dojo/password_reset.html', + template_name='login/password_reset.html', ), name="password_reset"), re_path(r'^password_reset/done/$', auth_views.PasswordResetDoneView.as_view( - template_name='dojo/password_reset_done.html', + template_name='login/password_reset_done.html', ), name='password_reset_done'), re_path(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,40})/$', auth_views.PasswordResetConfirmView.as_view( - template_name='dojo/password_reset_confirm.html', + template_name='login/password_reset_confirm.html', ), name='password_reset_confirm'), re_path(r'^reset/done/$', auth_views.PasswordResetCompleteView.as_view( - template_name='dojo/password_reset_complete.html', + template_name='login/password_reset_complete.html', ), name='password_reset_complete'), ]) if settings.FORGOT_USERNAME: urlpatterns.extend([ re_path(r'^forgot_username_done/$', auth_views.PasswordResetDoneView.as_view( - template_name='dojo/forgot_username_done.html', + template_name='login/forgot_username_done.html', ), name="forgot_username_done"), re_path(r'^forgot_username/$', views.DojoForgotUsernameView.as_view( - template_name='dojo/forgot_username.html', + template_name='login/forgot_username.html', success_url=reverse_lazy("forgot_username_done") ), name="forgot_username"), ]) diff --git a/dojo/user/views.py b/dojo/user/views.py index c971d932c16..ea60c93fc1b 100644 --- a/dojo/user/views.py +++ b/dojo/user/views.py @@ -612,8 +612,8 @@ def send_mail(self, subject_template_name, email_template_name, from_email = get_system_setting('email_from') url = hyperlink.parse(settings.SITE_URL) - subject_template_name = 'dojo/forgot_username_subject.html' - email_template_name = 'notifications/mail/forgot_username.tpl' + subject_template_name = 'login/forgot_username_subject.html' + email_template_name = 'login/forgot_username.tpl' context['site_name'] = url.host context['protocol'] = url.scheme context['domain'] = settings.SITE_URL[len(f'{url.scheme}://'):] @@ -638,7 +638,7 @@ def send_mail(self, subject_template_name, email_template_name, from_email = get_system_setting('email_from') url = hyperlink.parse(settings.SITE_URL) - email_template_name = 'notifications/mail/forgot_password.tpl' + email_template_name = 'login/forgot_password.tpl' context['site_name'] = url.host context['protocol'] = url.scheme context['domain'] = settings.SITE_URL[len(f'{url.scheme}://'):] From e6c776714c5c02a6b55c8294e3c1a9d3bfe5d24c Mon Sep 17 00:00:00 2001 From: kiblik <5609770+kiblik@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:25:03 +0200 Subject: [PATCH 52/65] Ruff: add and fix RSE (#10093) * Ruff: add and fix RSE * Ruff: Fix RSE --- dojo/api_v2/views.py | 2 +- dojo/authorization/authorization.py | 6 +++--- dojo/decorators.py | 2 +- dojo/engagement/views.py | 8 ++++---- dojo/finding/views.py | 12 ++++++------ dojo/metrics/views.py | 2 +- dojo/notifications/views.py | 2 +- dojo/product/views.py | 6 +++--- dojo/reports/views.py | 10 +++++----- dojo/risk_acceptance/helper.py | 2 +- dojo/survey/views.py | 8 ++++---- dojo/test/views.py | 2 +- dojo/views.py | 8 ++++---- ruff.toml | 1 + 14 files changed, 36 insertions(+), 35 deletions(-) diff --git a/dojo/api_v2/views.py b/dojo/api_v2/views.py index 588f5bb1cef..cbc61ff2125 100644 --- a/dojo/api_v2/views.py +++ b/dojo/api_v2/views.py @@ -2964,7 +2964,7 @@ def report_generate(request, obj, options): report_name = "Finding" else: - raise Http404() + raise Http404 result = { "product_type": product_type, diff --git a/dojo/authorization/authorization.py b/dojo/authorization/authorization.py index 28885137156..8538101cf52 100644 --- a/dojo/authorization/authorization.py +++ b/dojo/authorization/authorization.py @@ -243,17 +243,17 @@ def user_has_global_permission(user, permission): def user_has_configuration_permission_or_403(user, permission): if not user_has_configuration_permission(user, permission): - raise PermissionDenied() + raise PermissionDenied def user_has_permission_or_403(user, obj, permission): if not user_has_permission(user, obj, permission): - raise PermissionDenied() + raise PermissionDenied def user_has_global_permission_or_403(user, permission): if not user_has_global_permission(user, permission): - raise PermissionDenied() + raise PermissionDenied def get_roles_for_permission(permission): diff --git a/dojo/decorators.py b/dojo/decorators.py index 664989f8ffc..c919a2995bc 100644 --- a/dojo/decorators.py +++ b/dojo/decorators.py @@ -182,7 +182,7 @@ def _wrapped(request, *args, **kw): dojo_user = Dojo_User.objects.filter(username=username).first() if dojo_user: Dojo_User.enable_force_password_reset(dojo_user) - raise Ratelimited() + raise Ratelimited return fn(request, *args, **kw) return _wrapped return decorator diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index b2fc5bff906..f0c542e2d96 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -114,7 +114,7 @@ def engagement_calendar(request): if not get_system_setting('enable_calendar'): - raise Resolver404() + raise Resolver404 if 'lead' not in request.GET or '0' in request.GET.getlist('lead'): engagements = get_authorized_engagements(Permissions.Engagement_View) @@ -1205,7 +1205,7 @@ def add_risk_acceptance(request, eid, fid=None): finding = get_object_or_404(Finding, id=fid) if not eng.product.enable_full_risk_acceptance: - raise PermissionDenied() + raise PermissionDenied if request.method == 'POST': form = RiskAcceptanceForm(request.POST, request.FILES) @@ -1283,7 +1283,7 @@ def view_edit_risk_acceptance(request, eid, raid, edit_mode=False): eng = get_object_or_404(Engagement, pk=eid) if edit_mode and not eng.product.enable_full_risk_acceptance: - raise PermissionDenied() + raise PermissionDenied risk_acceptance_form = None errors = False @@ -1455,7 +1455,7 @@ def reinstate_risk_acceptance(request, eid, raid): eng = get_object_or_404(Engagement, pk=eid) if not eng.product.enable_full_risk_acceptance: - raise PermissionDenied() + raise PermissionDenied ra_helper.reinstate(risk_acceptance, risk_acceptance.expiration_date) diff --git a/dojo/finding/views.py b/dojo/finding/views.py index d54baafb40c..f7624c996ce 100644 --- a/dojo/finding/views.py +++ b/dojo/finding/views.py @@ -1212,7 +1212,7 @@ def post(self, request: HttpRequest, finding_id): # Handle the case of a successful form if success: return redirect_to_return_url_or_else(request, reverse("view_test", args=(finding.test.id,))) - raise PermissionDenied() + raise PermissionDenied @user_is_authorized(Finding, Permissions.Finding_Edit, "fid") @@ -1500,7 +1500,7 @@ def apply_template_cwe(request, fid): extra_tags="alert-danger", ) else: - raise PermissionDenied() + raise PermissionDenied @user_is_authorized(Finding, Permissions.Finding_Edit, "fid") @@ -1614,7 +1614,7 @@ def simple_risk_accept(request, fid): finding = get_object_or_404(Finding, id=fid) if not finding.test.engagement.product.enable_simple_risk_acceptance: - raise PermissionDenied() + raise PermissionDenied ra_helper.simple_risk_accept(finding) @@ -1741,7 +1741,7 @@ def clear_finding_review(request, fid): # the review or one of the users requested to provide the review, then # do not allow the user to clear the review. if user != finding.review_requested_by and user not in finding.reviewers.all(): - raise PermissionDenied() + raise PermissionDenied # in order to clear a review for a finding, we need to capture why and how it was reviewed # we can do this with a Note @@ -2058,7 +2058,7 @@ def delete_stub_finding(request, fid): extra_tags="alert-danger", ) else: - raise PermissionDenied() + raise PermissionDenied @user_is_authorized(Stub_Finding, Permissions.Finding_Edit, "fid") @@ -2442,7 +2442,7 @@ def delete_template(request, tid): extra_tags="alert-danger", ) else: - raise PermissionDenied() + raise PermissionDenied def download_finding_pic(request, token): diff --git a/dojo/metrics/views.py b/dojo/metrics/views.py index f0348f348e0..42e7bb31b9a 100644 --- a/dojo/metrics/views.py +++ b/dojo/metrics/views.py @@ -903,7 +903,7 @@ def view_engineer(request, eid): user = get_object_or_404(Dojo_User, pk=eid) if not (request.user.is_superuser or request.user.username == user.username): - raise PermissionDenied() + raise PermissionDenied now = timezone.now() findings = Finding.objects.filter(reporter=user, verified=True) diff --git a/dojo/notifications/views.py b/dojo/notifications/views.py index 10616dd1b11..f20e45224fe 100644 --- a/dojo/notifications/views.py +++ b/dojo/notifications/views.py @@ -25,7 +25,7 @@ def get_notifications(self, request: HttpRequest): def check_user_permissions(self, request: HttpRequest): if not request.user.is_superuser: - raise PermissionDenied() + raise PermissionDenied def get_form(self, request: HttpRequest, notifications: Notifications): # Set up the args for the form diff --git a/dojo/product/views.py b/dojo/product/views.py index 580bb2c6442..9a70751ae1a 100644 --- a/dojo/product/views.py +++ b/dojo/product/views.py @@ -839,7 +839,7 @@ def import_scan_results_prod(request, pid=None): def new_product(request, ptid=None): if get_authorized_product_types(Permissions.Product_Type_Add_Product).count() == 0: - raise PermissionDenied() + raise PermissionDenied jira_project_form = None error = False @@ -1822,7 +1822,7 @@ def edit_api_scan_configuration(request, pid, pascid): if product_api_scan_configuration.product.pk != int( pid): # user is trying to edit Tool Configuration from another product (trying to by-pass auth) - raise Http404() + raise Http404 if request.method == 'POST': form = Product_API_Scan_ConfigurationForm(request.POST, instance=product_api_scan_configuration) @@ -1868,7 +1868,7 @@ def delete_api_scan_configuration(request, pid, pascid): if product_api_scan_configuration.product.pk != int( pid): # user is trying to delete Tool Configuration from another product (trying to by-pass auth) - raise Http404() + raise Http404 if request.method == 'POST': form = Product_API_Scan_ConfigurationForm(request.POST) diff --git a/dojo/reports/views.py b/dojo/reports/views.py index 99d5480b775..a8102142764 100644 --- a/dojo/reports/views.py +++ b/dojo/reports/views.py @@ -115,7 +115,7 @@ def post(self, request: HttpRequest) -> HttpResponse: self._set_state(request) return render(request, self.get_template(), self.get_context()) else: - raise PermissionDenied() + raise PermissionDenied def _set_state(self, request: HttpRequest): self.request = request @@ -149,7 +149,7 @@ def get_template(self): elif self.report_format == 'HTML': return 'dojo/custom_html_report.html' else: - raise PermissionDenied() + raise PermissionDenied def get_context(self): return { @@ -360,7 +360,7 @@ def product_endpoint_report(request, pid): 'title': 'Generate Report', }) else: - raise Http404() + raise Http404 product_tab = Product_Tab(product, "Product Endpoint Report", tab="endpoints") return render(request, @@ -599,7 +599,7 @@ def generate_report(request, obj, host_view=False): 'host': report_url_resolver(request), 'user_id': request.user.id} else: - raise Http404() + raise Http404 report_form = ReportOptionsForm() @@ -655,7 +655,7 @@ def generate_report(request, obj, host_view=False): }) else: - raise Http404() + raise Http404 paged_findings = get_page_items(request, findings.qs.distinct().order_by('numerical_severity'), 25) product_tab = None diff --git a/dojo/risk_acceptance/helper.py b/dojo/risk_acceptance/helper.py index 0159517ebfe..9ceedfaab47 100644 --- a/dojo/risk_acceptance/helper.py +++ b/dojo/risk_acceptance/helper.py @@ -272,7 +272,7 @@ def prefetch_for_expiration(risk_acceptances): def simple_risk_accept(finding, perform_save=True): if not finding.test.engagement.product.enable_simple_risk_acceptance: - raise PermissionDenied() + raise PermissionDenied logger.debug('accepting finding %i:%s', finding.id, finding) finding.risk_accepted = True diff --git a/dojo/survey/views.py b/dojo/survey/views.py index 3dc704fe6e9..091d68492e1 100644 --- a/dojo/survey/views.py +++ b/dojo/survey/views.py @@ -377,7 +377,7 @@ def edit_questionnaire_questions(request, sid): survey = get_object_or_404(Engagement_Survey, id=sid) if not user_has_configuration_permission(request.user, 'dojo.add_engagement_survey') and \ not user_has_configuration_permission(request.user, 'dojo.change_engagement_survey'): - raise PermissionDenied() + raise PermissionDenied answered_surveys = Answered_Survey.objects.filter(survey=survey) reverted = False @@ -548,7 +548,7 @@ def edit_question(request, qid): elif type == 'dojo | choice question': form = EditChoiceQuestionForm(instance=question) else: - raise Http404() + raise Http404 if request.method == 'POST': if type == 'dojo | text question': @@ -556,7 +556,7 @@ def edit_question(request, qid): elif type == 'dojo | choice question': form = EditChoiceQuestionForm(request.POST, instance=question) else: - raise Http404() + raise Http404 if form.is_valid(): form.save() @@ -759,7 +759,7 @@ def answer_empty_survey(request, esid): 'You must be logged in to answer questionnaire. Otherwise, enable anonymous response in system settings.', extra_tags='alert-danger') # will render 403 - raise PermissionDenied() + raise PermissionDenied questions = [ q.get_form()( diff --git a/dojo/test/views.py b/dojo/test/views.py index bcb38514cd8..d15d518863d 100644 --- a/dojo/test/views.py +++ b/dojo/test/views.py @@ -402,7 +402,7 @@ def copy_test(request, tid): def test_calendar(request): if not get_system_setting('enable_calendar'): - raise Resolver404() + raise Resolver404 if 'lead' not in request.GET or '0' in request.GET.getlist('lead'): tests = get_authorized_tests(Permissions.Test_View) diff --git a/dojo/views.py b/dojo/views.py index 1baee23ad8f..09a0dcad73e 100644 --- a/dojo/views.py +++ b/dojo/views.py @@ -39,7 +39,7 @@ def action_history(request, cid, oid): ct = ContentType.objects.get_for_id(cid) obj = ct.get_object_for_this_type(pk=oid) except (KeyError, ObjectDoesNotExist): - raise Http404() + raise Http404 product_id = None active_tab = None @@ -136,7 +136,7 @@ def manage_files(request, oid, obj_type): user_has_permission_or_403(request.user, obj, Permissions.Finding_Edit) obj_vars = ('view_finding', 'finding_set') else: - raise Http404() + raise Http404 files_formset = ManageFileFormSet(queryset=obj.files.all()) error = False @@ -194,7 +194,7 @@ def manage_files(request, oid, obj_type): def protected_serve(request, path, document_root=None, show_indexes=False): file = FileUpload.objects.get(file=path) if not file: - raise Http404() + raise Http404 object_set = list(file.engagement_set.all()) + list(file.test_set.all()) + list(file.finding_set.all()) # Should only one item (but not sure what type) in the list, so O(n=1) for obj in object_set: @@ -218,7 +218,7 @@ def access_file(request, fid, oid, obj_type, url=False): obj = get_object_or_404(Finding, pk=oid) user_has_permission_or_403(request.user, obj, Permissions.Finding_View) else: - raise Http404() + raise Http404 # If reaching this far, user must have permission to get file file = get_object_or_404(FileUpload, pk=fid) redirect_url = f'{settings.MEDIA_ROOT}/{file.file.url.lstrip(settings.MEDIA_URL)}' diff --git a/ruff.toml b/ruff.toml index b6d1566e9f1..1349d475e92 100644 --- a/ruff.toml +++ b/ruff.toml @@ -50,6 +50,7 @@ select = [ "LOG", "INP", "SLOT", + "RSE", "PD", "PGH", "TRY003", From 25130cdf2d82ba436f8523a32fc884e96861c448 Mon Sep 17 00:00:00 2001 From: Antoine Ruffino <138585151+a-ruff@users.noreply.github.com> Date: Fri, 21 Jun 2024 23:25:11 +0200 Subject: [PATCH 53/65] Enhance Kubescape parser (#10369) * Enhance Kubescape parser * Fix typo. * Update settings check-sum * Update settings check-sum --- dojo/settings/.settings.dist.py.sha256sum | 2 +- dojo/settings/settings.dist.py | 4 +- dojo/tools/kubescape/parser.py | 113 +++++++++++++++++----- unittests/tools/test_kubescape_parser.py | 6 +- 4 files changed, 97 insertions(+), 28 deletions(-) diff --git a/dojo/settings/.settings.dist.py.sha256sum b/dojo/settings/.settings.dist.py.sha256sum index 4de58bdb1b8..95d13b9ae0f 100644 --- a/dojo/settings/.settings.dist.py.sha256sum +++ b/dojo/settings/.settings.dist.py.sha256sum @@ -1 +1 @@ -e9aab91c011f6aa1933791c57e7c37b165e5369606c459f772c4269c56212b53 +ed4d321ce9ae47f9500965e8494a069fb464a9bd4ea3edf994020523f0dea085 diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index 4362b844053..af42b07d84e 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -1267,7 +1267,8 @@ def saml2_attrib_map_format(dict): 'Snyk Code Scan': ['vuln_id_from_tool', 'file_path'], 'Bearer CLI': ['title', 'severity'], 'Nancy Scan': ['title', 'vuln_id_from_tool'], - 'Wiz Scan': ['title', 'description', 'severity'] + 'Wiz Scan': ['title', 'description', 'severity'], + 'Kubescape JSON Importer': ['title', 'component_name'] } # Override the hardcoded settings here via the env var @@ -1485,6 +1486,7 @@ def saml2_attrib_map_format(dict): 'Nosey Parker Scan': DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR_HASH_CODE, 'Bearer CLI': DEDUPE_ALGO_HASH_CODE, 'Wiz Scan': DEDUPE_ALGO_HASH_CODE, + 'Kubescape JSON Importer': DEDUPE_ALGO_HASH_CODE } # Override the hardcoded settings here via the env var diff --git a/dojo/tools/kubescape/parser.py b/dojo/tools/kubescape/parser.py index a5797e8402c..be9cd6d741e 100644 --- a/dojo/tools/kubescape/parser.py +++ b/dojo/tools/kubescape/parser.py @@ -1,4 +1,5 @@ import json +import textwrap from dojo.models import Finding @@ -13,13 +14,36 @@ def get_label_for_scan_types(self, scan_type): def get_description_for_scan_types(self, scan_type): return "Import result of Kubescape JSON output." + def find_control_summary_by_id(self, data, control_id): + # Browse summaryDetails to look for matching control id. If the Control id is matching, return the first occurence. + try: + controls = data.get("summaryDetails", {}).get("controls", {}) + return controls.get(control_id, None) + except ValueError: + return None + + @staticmethod + def __hyperlink(link: str) -> str: + return "[" + link + "](" + link + ")" + def severity_mapper(self, input): - if input == 1: + if input <= 4: return "Low" - elif input == 2: + elif input <= 7: return "Medium" - elif input == 3: + elif input <= 9: return "High" + elif input <= 10: + return "Critical" + + def parse_resource_id(self, resource_id): + try: + parts = resource_id.split("/") + resource_type = parts[-2] + resource_name = parts[-1] + return resource_type, resource_name + except IndexError: + return None, None def get_findings(self, filename, test): findings = [] @@ -29,27 +53,70 @@ def get_findings(self, filename, test): data = {} for resource in data["resources"]: resourceid = resource["resourceID"] + resource_type, resource_name = self.parse_resource_id(resourceid) results = ([each for each in data["results"] if each.get('resourceID') == resourceid]) controls = results[0].get("controls", []) - try: - prioritizedResource = results[0]["prioritizedResource"]["severity"] - except KeyError: - prioritizedResource = "Info" + for control in controls: - controlID = control['controlID'] - description = control["name"] + "\n\n" - description += "**resourceID:** " + resourceid + "\n" - description += "**resource object:** " + str(resource["object"]) + "\n" - description += "**controlID:** " + controlID + "\n" - description += "**Rules:** " + str(control["rules"]) + "\n" - if self.severity_mapper(prioritizedResource) is None: - severity = "Info" - else: - severity = self.severity_mapper(prioritizedResource) - find = Finding(title=str(controlID), - test=test, - description=description, - severity=severity, - static_finding=True) - findings.append(find) + # This condition is true if the result doesn't contain the status for each control (old format) + retrocompatibility_condition = 'status' not in control or 'status' not in control['status'] + if retrocompatibility_condition or control["status"]["status"] == "failed": + control_name = control["name"] + if resource_type and resource_name and control_name: + title = f"{control_name} - {resource_type} {resource_name}" + else: + title = f"{control_name} - {resourceid}" + controlID = control['controlID'] + + # Find control details + controlSummary = self.find_control_summary_by_id(data, controlID) + if controlSummary is None: + severity = "Info" + mitigation = "" + else: + severity = self.severity_mapper(controlSummary.get("scoreFactor", 0)) + # Define mitigation if available + if "mitigation" in controlSummary: + mitigation = controlSummary["mitigation"] + else: + mitigation = "" + + armoLink = f"https://hub.armosec.io/docs/{controlID.lower()}" + description = "**Summary:** " + f"The ressource '{resourceid}' has failed the control '{control_name}'." + "\n" + if controlSummary is not None and "description" in controlSummary: + description += "**Description:** " + controlSummary["description"] + "\n" + + # Define category if available + if controlSummary is not None and "category" in controlSummary and "subCategory" in controlSummary["category"]: + category_name = controlSummary["category"]["name"] + category_subname = controlSummary["category"]["subCategory"]["name"] + category = f"{category_name} > {category_subname}" + description += "**Category:** " + category + "\n" + elif controlSummary is not None and "category" in controlSummary and "name" in controlSummary["category"]: + category = controlSummary["category"]["name"] + description += "**Category:** " + category + "\n" + + description += "View control details here: " + self.__hyperlink(armoLink) + + steps_to_reproduce = "The following rules have failed :" + "\n" + steps_to_reproduce += "\t**Rules:** " + str(json.dumps(control["rules"], indent=4)) + "\n" + + steps_to_reproduce += "Resource object may contain evidence:" + "\n" + steps_to_reproduce += "\t**Resource object:** " + str(json.dumps(resource["object"], indent=4)) + + references = armoLink + + find = Finding( + title=textwrap.shorten(title, 150), + test=test, + description=description, + mitigation=mitigation, + steps_to_reproduce=steps_to_reproduce, + references=references, + severity=severity, + component_name=resourceid, + static_finding=True, + dynamic_finding=False + ) + findings.append(find) return findings diff --git a/unittests/tools/test_kubescape_parser.py b/unittests/tools/test_kubescape_parser.py index bccbed220a7..c68cb2f1f7b 100644 --- a/unittests/tools/test_kubescape_parser.py +++ b/unittests/tools/test_kubescape_parser.py @@ -4,7 +4,7 @@ from ..dojo_test_case import DojoTestCase, get_unit_tests_path -class TestOrtParser(DojoTestCase): +class TestKubescapeParser(DojoTestCase): def test_parse_file_has_many_findings(self): with open(get_unit_tests_path() + "/scans/kubescape/many_findings.json") as testfile: parser = KubescapeParser() @@ -15,10 +15,10 @@ def test_parse_file_has_many_results(self): with open(get_unit_tests_path() + "/scans/kubescape/results.json") as testfile: parser = KubescapeParser() findings = parser.get_findings(testfile, Test()) - self.assertEqual(20, len(findings)) + self.assertEqual(0, len(findings)) def test_parse_file_with_a_failure(self): with open(get_unit_tests_path() + "/scans/kubescape/with_a_failure.json") as testfile: parser = KubescapeParser() findings = parser.get_findings(testfile, Test()) - self.assertEqual(18, len(findings)) + self.assertEqual(3, len(findings)) From 91de2e8a8b82e12bc3ff76176689c2898593a220 Mon Sep 17 00:00:00 2001 From: manuelsommer <47991713+manuel-sommer@users.noreply.github.com> Date: Sat, 22 Jun 2024 00:34:27 +0200 Subject: [PATCH 54/65] =?UTF-8?q?=E2=9C=A8=20=20add=20deepfence=20threatma?= =?UTF-8?q?pper=20(#9688)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: add deepfence threatmapper * :sparkler: finished * update * update deepfence threatmapper * fix according to review * fix ruff * fix ruff * :bug: fix * remove unecessary file * update sha sum --- .../parsers/file/deepfence_threatmapper.md | 8 +++ dojo/settings/.settings.dist.py.sha256sum | 2 +- dojo/settings/settings.dist.py | 2 + dojo/tools/deepfence_threatmapper/__init__.py | 1 + .../deepfence_threatmapper/compliance.py | 54 ++++++++++++++++++ dojo/tools/deepfence_threatmapper/malware.py | 39 +++++++++++++ dojo/tools/deepfence_threatmapper/parser.py | 40 +++++++++++++ dojo/tools/deepfence_threatmapper/secret.py | 42 ++++++++++++++ .../deepfence_threatmapper/vulnerability.py | 50 ++++++++++++++++ .../compliance_report.csv | 8 +++ .../compliance_report.xlsx | Bin 0 -> 11314 bytes .../deepfence_threatmapper/malware_report.csv | 10 ++++ .../malware_report.xlsx | Bin 0 -> 11497 bytes .../deepfence_threatmapper/secret_report.csv | 8 +++ .../deepfence_threatmapper/secret_report.xlsx | Bin 0 -> 11071 bytes .../vulnerability_report.csv | 4 ++ .../vulnerability_report.xlsx | Bin 0 -> 11599 bytes .../test_deepfence_threatmapper_parser.py | 43 ++++++++++++++ 18 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 docs/content/en/integrations/parsers/file/deepfence_threatmapper.md create mode 100644 dojo/tools/deepfence_threatmapper/__init__.py create mode 100644 dojo/tools/deepfence_threatmapper/compliance.py create mode 100644 dojo/tools/deepfence_threatmapper/malware.py create mode 100644 dojo/tools/deepfence_threatmapper/parser.py create mode 100644 dojo/tools/deepfence_threatmapper/secret.py create mode 100644 dojo/tools/deepfence_threatmapper/vulnerability.py create mode 100644 unittests/scans/deepfence_threatmapper/compliance_report.csv create mode 100644 unittests/scans/deepfence_threatmapper/compliance_report.xlsx create mode 100644 unittests/scans/deepfence_threatmapper/malware_report.csv create mode 100644 unittests/scans/deepfence_threatmapper/malware_report.xlsx create mode 100644 unittests/scans/deepfence_threatmapper/secret_report.csv create mode 100644 unittests/scans/deepfence_threatmapper/secret_report.xlsx create mode 100644 unittests/scans/deepfence_threatmapper/vulnerability_report.csv create mode 100644 unittests/scans/deepfence_threatmapper/vulnerability_report.xlsx create mode 100644 unittests/tools/test_deepfence_threatmapper_parser.py diff --git a/docs/content/en/integrations/parsers/file/deepfence_threatmapper.md b/docs/content/en/integrations/parsers/file/deepfence_threatmapper.md new file mode 100644 index 00000000000..84044fb72b4 --- /dev/null +++ b/docs/content/en/integrations/parsers/file/deepfence_threatmapper.md @@ -0,0 +1,8 @@ +--- +title: "Deepfence Threatmapper" +toc_hide: true +--- +Import compliance, malware, secret, vulnerability reports from [Deepfence Threatmapper](https://github.com/deepfence/ThreatMapper) in XLSX file format. + +### Sample Scan Data +Sample Threatmapper scans can be found [here](https://github.com/DefectDojo/django-DefectDojo/tree/master/unittests/scans/deepfence_threatmapper). In this link are both .xlsx and .csv listed. They contain the same content, but csv can be read in the Browser, but only xlsx is supported by the parser. \ No newline at end of file diff --git a/dojo/settings/.settings.dist.py.sha256sum b/dojo/settings/.settings.dist.py.sha256sum index 95d13b9ae0f..4885a819303 100644 --- a/dojo/settings/.settings.dist.py.sha256sum +++ b/dojo/settings/.settings.dist.py.sha256sum @@ -1 +1 @@ -ed4d321ce9ae47f9500965e8494a069fb464a9bd4ea3edf994020523f0dea085 +7b3bb14160f3ffce537d75895ee18cb0a561232fa964bae88b4861f7d289b176 diff --git a/dojo/settings/settings.dist.py b/dojo/settings/settings.dist.py index af42b07d84e..e207309417c 100644 --- a/dojo/settings/settings.dist.py +++ b/dojo/settings/settings.dist.py @@ -1265,6 +1265,7 @@ def saml2_attrib_map_format(dict): 'MobSF Scan': ['title', 'description', 'severity'], 'OSV Scan': ['title', 'description', 'severity'], 'Snyk Code Scan': ['vuln_id_from_tool', 'file_path'], + 'Deepfence Threatmapper Report': ['title', 'description', 'severity'], 'Bearer CLI': ['title', 'severity'], 'Nancy Scan': ['title', 'vuln_id_from_tool'], 'Wiz Scan': ['title', 'description', 'severity'], @@ -1486,6 +1487,7 @@ def saml2_attrib_map_format(dict): 'Nosey Parker Scan': DEDUPE_ALGO_UNIQUE_ID_FROM_TOOL_OR_HASH_CODE, 'Bearer CLI': DEDUPE_ALGO_HASH_CODE, 'Wiz Scan': DEDUPE_ALGO_HASH_CODE, + 'Deepfence Threatmapper Report': DEDUPE_ALGO_HASH_CODE, 'Kubescape JSON Importer': DEDUPE_ALGO_HASH_CODE } diff --git a/dojo/tools/deepfence_threatmapper/__init__.py b/dojo/tools/deepfence_threatmapper/__init__.py new file mode 100644 index 00000000000..3ad798a42b3 --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/__init__.py @@ -0,0 +1 @@ +__author__ = "manuel-sommer" diff --git a/dojo/tools/deepfence_threatmapper/compliance.py b/dojo/tools/deepfence_threatmapper/compliance.py new file mode 100644 index 00000000000..5cd4f5b6340 --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/compliance.py @@ -0,0 +1,54 @@ +from dojo.models import Finding + + +class DeepfenceThreatmapperCompliance: + def get_findings(self, row, headers, test): + description = "" + compliance_check_type = row[headers["compliance_check_type"]] + count = row[headers["count"]] + doc_id = row[headers["doc_id"]] + host_name = row[headers["host_name"]] + cloud_account_id = row[headers["cloud_account_id"]] + masked = row[headers["masked"]] + node_id = row[headers["node_id"]] + node_name = row[headers["node_name"]] + node_type = row[headers["node_type"]] + status = row[headers["status"]] + test_category = row[headers["test_category"]] + test_desc = row[headers["test_desc"]] + test_info = row[headers["test_info"]] + test_number = row[headers["test_number"]] + description += "**compliance_check_type:** " + str(compliance_check_type) + "\n" + description += "**host_name:** " + str(host_name) + "\n" + description += "**cloud_account_id:** " + str(cloud_account_id) + "\n" + description += "**masked:** " + str(masked) + "\n" + description += "**node_id:** " + str(node_id) + "\n" + description += "**node_name:** " + str(node_name) + "\n" + description += "**node_type:** " + str(node_type) + "\n" + description += "**status:** " + str(status) + "\n" + description += "**test_category:** " + str(test_category) + "\n" + description += "**test_desc:** " + str(test_desc) + "\n" + description += "**test_info:** " + str(test_info) + "\n" + description += "**test_number:** " + str(test_number) + "\n" + description += "**count:** " + str(count) + "\n" + description += "**doc_id:** " + str(doc_id) + "\n" + finding = Finding( + title="Threatmapper_Compliance_Report-" + test_number, + description=description, + severity=self.compliance_severity(status), + static_finding=False, + dynamic_finding=True, + test=test, + ) + return finding + + def compliance_severity(self, input): + if input == "pass": + output = "Info" + elif input == "info": + output = "Info" + elif input == "warn": + output = "Medium" + else: + output = "Info" + return output diff --git a/dojo/tools/deepfence_threatmapper/malware.py b/dojo/tools/deepfence_threatmapper/malware.py new file mode 100644 index 00000000000..f1931e42623 --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/malware.py @@ -0,0 +1,39 @@ +from dojo.models import Finding + + +class DeepfenceThreatmapperMalware: + def get_findings(self, row, headers, test): + description = "" + Rule_Name = row[headers["Rule Name"]] + Class = row[headers["Class"]] + File_Name = row[headers["File Name"]] + Summary = row[headers["Summary"]] + Severity = row[headers["Severity"]] + Node_Name = row[headers["Node Name"]] + NodeType = row[headers["NodeType"]] + Container_Name = row[headers["Container Name"]] + Kubernetes_Cluster_Name = row[headers["Kubernetes Cluster Name"]] + description += "**Summary:** " + str(Summary) + "\n" + description += "**Rule Name:** " + str(Rule_Name) + "\n" + description += "**Class:** " + str(Class) + "\n" + description += "**File Name:** " + str(File_Name) + "\n" + description += "**Node Name:** " + str(Node_Name) + "\n" + description += "**NodeType:** " + str(NodeType) + "\n" + description += "**Container Name:** " + str(Container_Name) + "\n" + description += "**Kubernetes Cluster Name:** " + str(Kubernetes_Cluster_Name) + "\n" + finding = Finding( + title=Rule_Name, + description=description, + file_path=File_Name, + severity=self.severity(Severity), + static_finding=False, + dynamic_finding=True, + test=test, + ) + return finding + + def severity(self, input): + if input is None: + return "Info" + else: + return input.capitalize() diff --git a/dojo/tools/deepfence_threatmapper/parser.py b/dojo/tools/deepfence_threatmapper/parser.py new file mode 100644 index 00000000000..3f5fd2a5a18 --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/parser.py @@ -0,0 +1,40 @@ +from openpyxl import load_workbook + +from dojo.tools.deepfence_threatmapper.compliance import DeepfenceThreatmapperCompliance +from dojo.tools.deepfence_threatmapper.malware import DeepfenceThreatmapperMalware +from dojo.tools.deepfence_threatmapper.secret import DeepfenceThreatmapperSecret +from dojo.tools.deepfence_threatmapper.vulnerability import DeepfenceThreatmapperVulnerability + + +class DeepfenceThreatmapperParser: + def get_scan_types(self): + return ["Deepfence Threatmapper Report"] + + def get_label_for_scan_types(self, scan_type): + return scan_type + + def get_description_for_scan_types(self, scan_type): + return "Deepfence Threatmapper report in XLSX format." + + def get_findings(self, filename, test): + workbook = load_workbook(filename) + worksheet = workbook.active + findings = [] + headers = {} + first = True + for row in worksheet.iter_rows(min_row=1, values_only=True): + if first: + first = False + for i in range(len(row)): + headers[row[i]] = i + elif headers.get("Rule Name") is not None and headers.get("Class") is not None: + findings.append(DeepfenceThreatmapperMalware().get_findings(row, headers, test)) + elif headers.get("Filename") is not None and headers.get("Content") is not None: + value = DeepfenceThreatmapperSecret().get_findings(row, headers, test) + if value is not None: + findings.append(value) + elif headers.get("@timestamp") is not None and headers.get("cve_attack_vector") is not None: + findings.append(DeepfenceThreatmapperVulnerability().get_findings(row, headers, test)) + elif headers.get("@timestamp") is not None and headers.get("compliance_check_type") is not None: + findings.append(DeepfenceThreatmapperCompliance().get_findings(row, headers, test)) + return findings diff --git a/dojo/tools/deepfence_threatmapper/secret.py b/dojo/tools/deepfence_threatmapper/secret.py new file mode 100644 index 00000000000..fd102be834a --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/secret.py @@ -0,0 +1,42 @@ +from dojo.models import Finding + + +class DeepfenceThreatmapperSecret: + def get_findings(self, row, headers, test): + description = "" + Filename = row[headers["Filename"]] + Content = row[headers["Content"]] + Name = row[headers["Name"]] + Rule = row[headers["Rule"]] + Severity = row[headers["Severity"]] + Node_Name = row[headers["Node Name"]] + Container_Name = row[headers["Container Name"]] + Kubernetes_Cluster_Name = row[headers["Kubernetes Cluster Name"]] + Signature = row[headers["Signature"]] + description += "**Filename:** " + str(Filename) + "\n" + description += "**Name:** " + str(Name) + "\n" + description += "**Rule:** " + str(Rule) + "\n" + description += "**Node Name:** " + str(Node_Name) + "\n" + description += "**Container Name:** " + str(Container_Name) + "\n" + description += "**Kubernetes Cluster Name:** " + str(Kubernetes_Cluster_Name) + "\n" + description += "**Content:** " + str(Content) + "\n" + description += "**Signature:** " + str(Signature) + "\n" + if Name is not None and Severity is not None: + finding = Finding( + title=str(Name), + description=description, + file_path=Filename, + severity=self.severity(Severity), + static_finding=False, + dynamic_finding=True, + test=test, + ) + else: + finding = None + return finding + + def severity(self, input): + if input is None: + return "Info" + else: + return input.capitalize() diff --git a/dojo/tools/deepfence_threatmapper/vulnerability.py b/dojo/tools/deepfence_threatmapper/vulnerability.py new file mode 100644 index 00000000000..61c1e505cdc --- /dev/null +++ b/dojo/tools/deepfence_threatmapper/vulnerability.py @@ -0,0 +1,50 @@ +from dojo.models import Finding + + +class DeepfenceThreatmapperVulnerability: + def get_findings(self, row, headers, test): + description = "" + cve_attack_vector = row[headers["cve_attack_vector"]] + cve_caused_by_package = row[headers["cve_caused_by_package"]] + cve_container_image = row[headers["cve_container_image"]] + cve_container_image_id = row[headers["cve_container_image_id"]] + cve_description = row[headers["cve_description"]] + cve_fixed_in = row[headers["cve_fixed_in"]] + cve_id = row[headers["cve_id"]] + cve_link = row[headers["cve_link"]] + cve_severity = row[headers["cve_severity"]] + cve_overall_score = row[headers["cve_overall_score"]] + cve_type = row[headers["cve_type"]] + host_name = row[headers["host_name"]] + cloud_account_id = row[headers["cloud_account_id"]] + masked = row[headers["masked"]] + description += "**cve_attack_vector:** " + str(cve_attack_vector) + "\n" + description += "**cve_caused_by_package:** " + str(cve_caused_by_package) + "\n" + description += "**cve_container_image:** " + str(cve_container_image) + "\n" + description += "**cve_container_image_id:** " + str(cve_container_image_id) + "\n" + description += "**cve_description:** " + str(cve_description) + "\n" + description += "**cve_severity:** " + str(cve_severity) + "\n" + description += "**cve_overall_score:** " + str(cve_overall_score) + "\n" + description += "**cve_type:** " + str(cve_type) + "\n" + description += "**host_name:** " + str(host_name) + "\n" + description += "**cloud_account_id:** " + str(cloud_account_id) + "\n" + description += "**masked:** " + str(masked) + "\n" + finding = Finding( + title="Threatmapper_Vuln_Report-" + cve_id, + description=description, + component_name=cve_caused_by_package, + severity=self.severity(cve_severity), + static_finding=False, + dynamic_finding=True, + mitigation=cve_fixed_in, + references=cve_link, + cve=cve_id, + test=test, + ) + return finding + + def severity(self, input): + if input is None: + return "Info" + else: + return input.capitalize() diff --git a/unittests/scans/deepfence_threatmapper/compliance_report.csv b/unittests/scans/deepfence_threatmapper/compliance_report.csv new file mode 100644 index 00000000000..573b460c545 --- /dev/null +++ b/unittests/scans/deepfence_threatmapper/compliance_report.csv @@ -0,0 +1,8 @@ +@timestamp,compliance_check_type,count,doc_id,host_name,cloud_account_id,masked,node_id,node_name,node_type,status,test_category,test_desc,test_info,test_number +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,149c4791fc6502e5a30f738d4eaba982,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,pass,Docker Files,3.6 - PASS,Ensure that /fenced/mnt/host/etc/docker directory permissions are set to 755 or more restrictively (Automated),gdpr_3.6 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,47edf84375c0bb90f48fa61684883b04,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,info,Docker Files,3.12 - INFO,Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated),gdpr_3.12 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,ad1965efb22e226df8a95a361a30cbc3,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,info,Docker Files,3.2 - INFO,Ensure that docker.service file permissions are appropriately set (Automated),gdpr_3.2 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,1db7418dc73082cdfc1c9e0d5ba5f6e0,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,warn,Audit,1.1.12 - WARN,1.1.12 Ensure auditing is configured for Dockerfiles and directories - /fenced/mnt/host/etc/containerd/config.toml (Automated),gdpr_1.1.12 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,2c3f915f3e72d6e16d192ae9aa71c704,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,pass,Docker Files,3.16 - PASS,Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated),gdpr_3.16 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,d158a60b1c623d11ce88cf68555e08af,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,info,Docker Files,3.4 - INFO,Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated),gdpr_3.4 +2024-01-25 11:17:30.272 +0000 UTC,gdpr,,,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,182758849647,False,4d1d5b7a279ce57b0f76be61b461d22c,cf-ngm-dev-cicd-ip-xxx-xxx-xxx-xxx.eu-central-1.compute.internal,host,info,Docker Files,3.14 - INFO,Ensure that the Docker server certificate key file permissions are set to 400 (Automated),gdpr_3.14 \ No newline at end of file diff --git a/unittests/scans/deepfence_threatmapper/compliance_report.xlsx b/unittests/scans/deepfence_threatmapper/compliance_report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2fc8e933b967feefa73400aac94e93fd6cf09810 GIT binary patch literal 11314 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 F{s-z62jl<% literal 0 HcmV?d00001 diff --git a/unittests/scans/deepfence_threatmapper/malware_report.csv b/unittests/scans/deepfence_threatmapper/malware_report.csv new file mode 100644 index 00000000000..3dd1bb8b6cd --- /dev/null +++ b/unittests/scans/deepfence_threatmapper/malware_report.csv @@ -0,0 +1,10 @@ +Rule Name,Class,File Name,Summary,Severity,Node Name,NodeType,Container Name,Kubernetes Cluster Name +MD5_Constants,Crypto Mining,/tmp/Deepfence/YaraHunter/df_db09257b02e615049e0aecc05be2dc2401735e67db4ab74225df777c62c39753/usr/sbin/mkfs.cramfs,The matched rule file's author is phoul (@phoul) .The file has a rule match that It is a crypto signature.Look for MD5 constants .The matched rule file's Date is 2014-01 .The matched rule file's version is 0.2 .,low,portal / secpipe-core-prd-ip-zzz-zzz-zzz-zzz.eu-west-1.compute.internal,container,portal,secpipe-core-prd +MD5_Constants,Crypto Mining,/tmp/Deepfence/YaraHunter/df_80ffd64c318595cf17a9ea482315b0c2a03572fb6e41f7ee53ec27786158c27c/usr/sbin/mkfs.cramfs,The matched rule file's author is phoul (@phoul) .The file has a rule match that It is a crypto signature.Look for MD5 constants .The matched rule file's Date is 2014-01 .The matched rule file's version is 0.2 .,low,portal / secpipe-core-prd-ip-uuu-uuu-uuu-uuu.eu-west-1.compute.internal,container,portal,secpipe-core-prd +CRC32_table,Crypto Mining,/tmp/Deepfence/YaraHunter/df_0dfa48a10ee6ca92c7d910ecd72a6207978f7f1bdc36870bf1587625f0270d37/lib/libz.so.1.2.13,The matched rule file's author is _pusher_ .The file has a rule match that It is a crypto signature.Look for CRC32 table .The matched rule file's Date is 2015-05 .The matched rule file's version is 0.1 .,low,nginx / secpipe-core-prd-ip-kkk-kkk-kkk-kkk.eu-west-1.compute.internal,container,nginx,secpipe-core-prd +CRC32_poly_Constant,Crypto Mining,/tmp/Deepfence/YaraHunter/df_0dfa48a10ee6ca92c7d910ecd72a6207978f7f1bdc36870bf1587625f0270d37/lib/libz.so.1.2.13,The matched rule file's author is _pusher_ .The file has a rule match that It is a crypto signature.Look for CRC32 [poly] .The matched rule file's Date is 2015-05 .The matched rule file's version is 0.1 .,low,nginx / secpipe-core-prd-ip-kkk-kkk-kkk-kkk.eu-west-1.compute.internal,container,nginx,secpipe-core-prd +MD5_Constants,Crypto Mining,/tmp/Deepfence/YaraHunter/df_cc54a20c0e1cee5e4951d047e13f69551cfddedbd67a05cc4e3de61939b10e7a/usr/sbin/mkfs.cramfs,The matched rule file's author is phoul (@phoul) .The file has a rule match that It is a crypto signature.Look for MD5 constants .The matched rule file's Date is 2014-01 .The matched rule file's version is 0.2 .,low,portal / secpipe-core-prd-ip-yyy-yyy-yyy-yyy.eu-west-1.compute.internal,container,portal,secpipe-core-prd +MD5_Constants,Crypto Mining,/tmp/Deepfence/YaraHunter/df_5e10a8e665e9def9227c98ec630c80d8c8b441c389c3d2b25d7c8d3b07c94eb4/sbin/mkfs.cramfs,The matched rule file's author is phoul (@phoul) .The file has a rule match that It is a crypto signature.Look for MD5 constants .The matched rule file's Date is 2014-01 .The matched rule file's version is 0.2 .,low,rabbitmq / secpipe-core-prd-ip-xxx-xxx-xxx-xxx.eu-west-1.compute.internal,container,rabbitmq,secpipe-core-prd +BASE64_table,Crypto Mining,/tmp/Deepfence/YaraHunter/df_5e10a8e665e9def9227c98ec630c80d8c8b441c389c3d2b25d7c8d3b07c94eb4/lib/x86_64-linux-gnu/libresolv-2.31.so,The matched rule file's author is _pusher_ .The file has a rule match that It is a crypto signature.Look for Base64 table .The matched rule file's Date is 2015-07 .The matched rule file's version is 0.1 .,low,rabbitmq / secpipe-core-prd-ip-xxx-xxx-xxx-xxx.eu-west-1.compute.internal,container,rabbitmq,secpipe-core-prd +BASE64_table,Crypto Mining,/tmp/Deepfence/YaraHunter/df_5e10a8e665e9def9227c98ec630c80d8c8b441c389c3d2b25d7c8d3b07c94eb4/opt/bitnami/erlang/lib/erlang/erts-13.1.3/bin/beam.smp,The matched rule file's author is _pusher_ .The file has a rule match that It is a crypto signature.Look for Base64 table .The matched rule file's Date is 2015-07 .The matched rule file's version is 0.1 .,low,rabbitmq / secpipe-core-prd-ip-xxx-xxx-xxx-xxx.eu-west-1.compute.internal,container,rabbitmq,secpipe-core-prd +CRC32_table,Crypto Mining,/tmp/Deepfence/YaraHunter/df_5e10a8e665e9def9227c98ec630c80d8c8b441c389c3d2b25d7c8d3b07c94eb4/lib/x86_64-linux-gnu/libz.so.1.2.11,The matched rule file's author is _pusher_ .The file has a rule match that It is a crypto signature.Look for CRC32 table .The matched rule file's Date is 2015-05 .The matched rule file's version is 0.1 .,low,rabbitmq / secpipe-core-prd-ip-xxx-xxx-xxx-xxx.eu-west-1.compute.internal,container,rabbitmq,secpipe-core-prd \ No newline at end of file diff --git a/unittests/scans/deepfence_threatmapper/malware_report.xlsx b/unittests/scans/deepfence_threatmapper/malware_report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0980439a07e9df9da6479c6c5773bdf58a58b08b GIT binary patch literal 11497 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 DmgZjG literal 0 HcmV?d00001 diff --git a/unittests/scans/deepfence_threatmapper/secret_report.csv b/unittests/scans/deepfence_threatmapper/secret_report.csv new file mode 100644 index 00000000000..ea8bbd8b4e0 --- /dev/null +++ b/unittests/scans/deepfence_threatmapper/secret_report.csv @@ -0,0 +1,8 @@ +Filename,Content,Name,Rule,Severity,Node Name,Container Name,Kubernetes Cluster Name,Signature +usr/share/doc/curl-8.3.0/TheArtOfHttpScripting.md,"""\n curl http://user:password@example.org/""",Username and password in URI,110,high,fluent-bit / secpipe-core-prd-ip-xxx-xxx-xxx-xxx.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd,"([\w+]{1,24})(://)([^$<]{1})([^\s"";]{1,}):([^$<]{1})([^\s"";/]{1,})@[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,24}([^\s]+)" +usr/share/doc/curl-8.3.0/TheArtOfHttpScripting.md,"""\n curl http://user:password@example.org/""",Username and password in URI,110,high,fluent-bit / secpipe-core-prd-ip-yyy-yyy-yyy-yyy.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd,"([\w+]{1,24})(://)([^$<]{1})([^\s"";]{1,}):([^$<]{1})([^\s"";/]{1,})@[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,24}([^\s]+)" +var/lib/yum/history/history-2023-10-12.sqlite,""".sqlite""",SQLite database file,12,low,fluent-bit / secpipe-core-prd-ip-yyy-yyy-yyy-yyy.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd, +usr/share/mime/magic,"""\n\u003e0=\u0000%-----BEGIN PGP PRIVATE KEY BLOCK-----""",Contains a private key,127,medium,fluent-bit / secpipe-core-prd-ip-yyy-yyy-yyy-yyy.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd,-----BEGIN (EC|RSA|DSA|OPENSSH|PGP) PRIVATE KEY +usr/share/doc/curl-8.3.0/TheArtOfHttpScripting.md,"""\n curl http://user:password@example.org/""",Username and password in URI,110,high,fluent-bit / secpipe-core-prd-ip-zzz-zzz-zzz-zzz.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd,"([\w+]{1,24})(://)([^$<]{1})([^\s"";]{1,}):([^$<]{1})([^\s"";/]{1,})@[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,24}([^\s]+)" +var/lib/yum/history/history-2023-10-12.sqlite,""".sqlite""",SQLite database file,12,low,fluent-bit / secpipe-core-prd-ip-zzz-zzz-zzz-zzz.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd, +usr/share/mime/magic,"""\n\u003e0=\u0000%-----BEGIN PGP PRIVATE KEY BLOCK-----""",Contains a private key,127,medium,fluent-bit / secpipe-core-prd-ip-zzz-zzz-zzz-zzz.eu-west-1.compute.internal,fluent-bit,secpipe-core-prd,-----BEGIN (EC|RSA|DSA|OPENSSH|PGP) PRIVATE KEY \ No newline at end of file diff --git a/unittests/scans/deepfence_threatmapper/secret_report.xlsx b/unittests/scans/deepfence_threatmapper/secret_report.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..67e9901bd068894e015c7537fd344dec16567521 GIT binary patch literal 11071 zcmeHtWn10&_V&izr4;w#R=l_tDDGa|-MwtINTERS;_k)WU5m@c-QD%SXO7HF=RD6B zI43WXD_64aB){Ctmx2rwG&TSh01p5F$N+}N-_7+P0Dx#{000XB52-C`XX|WY>#VQh zVQ=E3%j9ljO_~J_Ns|G91mFL^?Z0>hO5%p(x>(S~Z{9zOZZb+QRtmv$90B_<=@bRp zyJLHcjI`4%EMC$+KcI_b;#hM1z#LojVmli#ue7zP1%~!EDItgZ_qVI+5pXg0^c_;Q zy?PzvsHJ(5flVO9`dVK<(liB-=up?C#4ffbEM0&%r3b1tEW+*;0^`QCsAyw3JaQX`)!e=`F?k*? zI-qZU|3E!=yZn(6p|@?`INT<*`0We!HO5}!MY{<4KsyE=`(M4q3gx@!jsrY`9T12af%%&t*YI{S7u7V!`CF$4V`#1<%;)~qx zC%ax}FA2xQen(O3RvMge@8AMQN9`Cd;ZU;Hjo~_dHGQ2VDeXby+7d-qTwjnWGq6G- zF?lBT1AUB19UlQJmoONYKgnOKS5|Y`@U{$MT15G%G`OOUD`P))EX8j&K5q|2FqG%R z;Y1QnzmuWae3^H@HQCi2zN)f0k41%HnjvE7Ay75_|wWgu6BKKlH@S z&e6)y&d%yL@AWU8fdIQOFv@@TR-z;;)6Ih3g7h51;+EoygE8;SOn#_(fCfKMO$(wX zd+U3-LO|E3t1%*ZscMF3f}Ojlo%)p zgN1pxe^7jcgqrMx)gTbl&ya@Ay?skV^*SUwk6i4sVIr8_a+Jk|&C=;7(IA*JL)Dv~ z?gNz%OM%sOb)?C(rdux!qM&Qobf5>x_{D1kDLxbr!1(SI8U1aC_%-}_^P{P($Ea0D z_C4|zVX+Kx5eL6_urp~$za)ttZH&`aR#KDd$(pms!ys)N=$v8b^2Bs=pl^Bw{HOm; znXpLK4;fGZz&$wnK?C0brp%woQle@jzrl_E>^t!kLbDQZ)XbGtGC@5~)`9p#xBemU z!#XC3RB9CwjmX1_T`DI`{B%*D-t@wi`}u8Bl3D78d`j&P;zSi4XQvcG1CXIEE#30c z$WeK5=Vu!kiv`tc45Ac}{D=8;Ip3F~TgCndZL(uV!0yyySc8Q-jwrDTpWv4F>7#|L0%=NFcGWz5)`DRiu4GSCjsUi zX(?9egykMxWwjGE<|}@ArG+X++9;~L<@Ki1i(fv{63-I^5Z?E+6U8G}fu!{{!WfEw&7`UqFwqvj&sue1csdo;ynoA0+wlDq2`17X&3T|lzmqorp zk49TCu^CrmaPSmk&KIdm>CsD{lSeq=$q8cw;pEy(>leRtw$S&~vF6Ox)vGTSuCPH5 zA|x3Rr16%sTlsl%%d+Z&fs1@iGGj=e4|w%(d*q@Y?8O`OHa9)uM%H`S=sGV6peed? zu$_Ni$&tZ&+CGqmxM}Y=zdb@vMQ--YJd1E6=^I`_nOx?=s%Ste=k`)z)?$;favEup z<{LfIL}ulerN<1e@Fu(|^T@S|*1&%70+B?lObaCjeq|LI!ZUPw;6a(B>7VG=WU4qA zc3g2=*CgiUp*8hb3#N4)cn{xV$gbDeZk<|cYaNHvVj|lGzj(4OOopbxQ^!b`1*rZ7X#X{5s6_r!4*G&a(mJ zcj4l@?}XLdg~cjOh_RWCWp5AA^mJMA(}RNvGD>A7qYk1#X(Z)F z-Mk-({QAm{6N0pF%i%~&?q0skM!M*P6TwInm z@=zyppL>e8RH^6@-7qhe62{=GBDqoCQ8}UVH|dZ5h!D<%!7%k`o4%<>kf<4<3vJg$|fnriotrZ zm^k2fD2b((u6719AxhNp|Lnrg%P>Fjvcnd#_%;B6c6(q9y-gnQ^-A zbx@|^gPe6UrDOAsjMWBeCE$K)GtaEovQ2t$thzn)NgOdX z9!dLw#`R$$6m4&~n|)LIjpH>-Or>^Nbc~F&iKMQi&JI3u`6JI-i+nyOA`q$^}NQm7OZYshXTQ>Q17YSPbFoKUWdXs4-M)*YTHoJd7`B)-9biXKN2-)yr+n zFO2LsRhqu!64fMFZT#kE{_crpk*kBOz@Eqg5dc8>CwZMctWADrZMB-N9f%X#hq>ZK z=u~%Hl3|*Y632na0H!iSi0xx}wHS}sEtx``Ro$H53KiA-`2wX){1(~vEI(h!&Ux5g zNXx3Zq{~p;u)RCRM=_H^I_kRD&ljzy+jup>{bBZ07QtxMJtXHV%ekdI_MSIFg~9+b z5V9cNB!f>IBS``2QIKUpV3L-FFtYR2j2(fj)bs*r#}f@aran5gLsSL!*4QWbERv>P z`fui;1_ZrHJlqTsVhxYg-=t$v;EEpXC8Vp-u!u5Sh`AiHSB@w&3RR0OognI4i>%Zp zPWG4{gX9OXFiG1`X(OIUc_&+E%f*uKl8+N>&~_|Jb1W1Kc`evd0g7JGLz0E9{hf0D zU0p?dHf>o%Yb=-sg7Pvw-y~p50%DPlLMegQ^kw+jTFx@nYWjyCWT7`gd`Ds44Tbao z{UKbx*$rIAomU6=?{Fe7d-shvOTw+lOo3#B!^!RacAB2$?!MrwVLHpayBEzh%lZO* zHoN^SEZFt@Dzwe~>Fj+PluO72a600`=vtg}{3EISS~7l-2?P;)^$8kEPEuglgjtyO zP3L|obqGt?8;DjAi#(UKxxYkik(R4360f1^_~hv&YNau4 zt6U=R@JaJ?Qdj2bZq$A9EcGeoKZ_*Fs|IK4E%1?~kQ$p`yZgYMrXwPfJ@*NRvZDwt zx*CeQtc4YTMj{ug_^#CCUJCts=G71_tpGorAku5ts@co>o2;+$_dQFok`M^j%7?@r z?!{ZiCq4Ui(|(kyi&A-p4Qvq@@^6Ta4NZ6FCk`)1OFbeo>`>owNi9^x@h3-GtB#$b z#73RE*t`0l%l6e9OeAx;kp!?_glxGTLu3@QLRVU1o|k(=VopCh8!eXn&^LBV_)-nX z&f?gsZxEC-y`6dvP%FWTX6h;$v(AqQ=szv=F=BR2)R=I#v(>s?ZD-zRA3Ci&n11NF zZwzhrs7UszlEL>1cdxl#pYNOY)MWtD+}_@7>YkG5!5qJaa-&XV)JC;~;}0e3U-{n4 z#go(2-iQTp}bd`y-}vI>uU*+-*LW;q!miN_U?v0cvoXFa`$zQ2Y@eI+>f8I6M6_ zyZHTt_20S0)VB_4a7-P10z6T09Lv*nnKl7kWpolZ_um7^l4=bmDJcu{d^`h4T@8di z=cz(?0$EmGF5V7X*Jj4fztMP8O{e&yUlBIUf=NX=E9!~fS19R1#euE{h>5cLv$nBy zp*bK&fU`jjFF`!ak;<}#%SwdMDl^+Q6Q$r**$Sjcl3q&|TnT0KiQ&Rq{4mbHh{CjX zgR1f!@zqVh=fRgM7hNRSvE(Zv8b1+W^;hFug%J4MT8Nhr7}G$A;c6IbhQ7{K2g3ZC zPic?WEf&O#EzoFcil6%}PPlf?mfuxaiGF{Wh!+&j`2O`Y_L{Hh#$sMq&z4OD-d*Y9 zP4;{G{pqbN;$R4QOW!Fs1TW@wUOCr?C2GP)Bl3pW?6*2TU=#Ou<0scslvfX4VkGk4 zs*b;h;m+nJHYUu!?|)z0L#>f0f;yZwxc(QRVcnVGT`vQkpZQ$Z$DV87bT{8i#Rcn) z+6yT)(PKj(?o7$}Lt2c>_%D0Xgu$ABf^FE0V*N-V`x46MD3QDt7S{4C6l3Vd{C4Vu z|9QKm?`ApL=_a-~F%yZLa!YC!>G+nId>~@XqVmvFo_a$XB&xJ#{N=U$`&n(QJs-!D zji}>wD4ef}q|x%55XYWhmG*>d=*(CmwusVVpnbLNF^pj93^l(ac_VllsiF9^X-2Zj z^2M#_)iXa9Tv?oeTPvZHR}BWg`c!{gfhz$(!<&6C#mr3R?X z3g{@H-3es|_pIw4t%!67R@hIlY$fKvDPAfhzJS}K+%OsT95xg8qfG2KI-M0Hun>WI zOK5d3z3aE1R%5ESVLoh*MsEjfe)y^4(gK$;O)sqHdodEequ=KKoc>DR`)vKL?I(t= z1f8N%8OxCZvfjU`ze8F(+c@=lDh4o3@l$}#C?HIeR1;mB@kZC2X zPHXqwoNLMun!Pa1ZJwqM{NdfwihaXq*>jM@PNVla+$g6CW2%*>#@`s0V#8Hm-{5T^ z%`QTvYM>IAD!nhC%5_A?2;Zjd`rIiKgC2Bg_n3;_H|Zl$XfkWWi=}fOB$BQ;)i-4k zgYaF;Uj?3M0`IZX6$4sbyOzf{>^`+2&GS8zH6;VmFyZE#Kuy!;D0Rd>rf*n;Rh1o4 z6=6D*V>5Cus&&8oXqb9LrIGXG1Wiv zx4V|?KLox9e$cN!M~7y#onoQG;uRQRBmN(cOpB3S2ASArJF!1YRdri`6<%oZO3qO z27Dqy-fsUlTj6d;KeDWYA`ESwE!^uY#zjEn*XfgPb`RYPCt%QOf}s4#MMooX-MZVJ z+x6DBE-T$pfyMHQy4UNfj?x*ahty@DneEz|v*#1-6d$X*+RO$Ub6W!ZS^7CR3-d5y z*o73s;y&xgZm%03+_)caYfLxaCzp~Slyh9LA}90HRQZQ7FctDwR zAM7Opa@D5gfMfqP#oX5bVxO|7xCYM+-J{f-{XL&v<1P44r9HaxZtSxyQTgdi zNHtui)#9DpR7mtGfoI<=PK}}Mx;&iYZQxfIk4Haj?mVuzKfM@ z!N$kEg^~G5RdR-o`#r>z`^Xb%jw^VGJ81Rm{Ss0Y6=BnGT))~QC?{U!Jx4d&AcJkC z+;(~*9XWco!|dc(8wy-}B4y0igZ7E1+!&-Q;6v_LsB(}VbvR5?VdaVp#lplqW6mvu zCbu8Qx*gg~j5o}&K=^io`Jmc5YcRT1HRRC}&o_H-bmOu#Wo|T(X(jn{nQ9*2gLa6H zxIiyMq`jWf;5=VI3a~QQ=(v`XW@&2-8Fqm{v*Uq7VO$E9U?z0Zy#u6#K>!UrDU1fTglm6p?V@J^Rg^ zjW%U!ygO(D&2ctcO+8fB$O3YOFezcI_U`gEWfWN|d6|am!U$&l+foxxx(K^`@77V~ zq+v|iZKtI;)51qqO;X;reb3Bdr(v|H3)@drpE&uMODak;sz6mREc@Z5}w0Td2}^WDV*K+&0X4^rfZSN#*M)D7d#9}hvLWS5vF+9HbBl7 zw*KyS_p#Tl)i;z2PS4GhugvknMReMI#rp|8@Jl(#PcgsEReuV9HEzUx17<=M*scuC z!jLZ0+@+!`x_}BEWG{v4l#S&b;zpL$3_-##eUTLtgn+W+8~ks2ZJY({pln}mREeuh zwAJQEoeu4Y(S`=b)rr%_o8O|PzdQPi4W||-aED{=H2{G3w|MH0NGdgU#CDwpJLu-y zHW9-~Ky0)^C_E04P*>T-Y#Gr`utv9QFDH!3)zS_%yw+!wqPX{?HBaBY4rBMaggG{G zN@68;*zp77KH=uYdB#q*`KfgzV(v6Bc^I*8Uc!G77;asXz3H{pMOj6_tRAvB@=0Oc z7DEYZ^0yG)_+V19PAqs7+%N;l{2*Io;DGlfab0N=i>#`S<%6me1QLZSVzrCc$+p4pLG;sLE_ik&b#8s3K9A!bRfzPUL$ z6}?G=Xwk!R{Q98u3WSYyk;ZF3ENbb*AoY3ORXDn5Eg3~mgC3HKwO0n&NG0!>QjUz1 zChH!IG4j{Ui36iHq|ljS*%KLdq|i|&P44kfUKP7P%9%|nt)sY=g$B{(U(h_f4vHJe z^ZArUb-0wzde(f4f&!05gQ+;NRmEZoV$?CB70Wqz<^2BU1X(xg9d(nCVAL37u|T(c zJoaLT+hlY9#B2djPzC{Kh2uG4{squb$gd`8UMnM`M*M0Ox)*yIj&<-69IL&&{QigI z5<#{LLf8O5m^&y$&gc|)r4F3~q&sM_==(S|h}@%<*`dmmB_2s?-_Kd&?mzgOLTF+q z$2QJVPsSehHlJqGmmi#Bs9PpaoSo_>?#&!?C7%z|mCeRUU3Y`5`LlLH;~ zE0Nv}IcxdBz8_AgpQ841{Oa-FS}gYU>fodO_$sr(%85IH*WIgxZ(&`M^R=f}3%_e_ zjwT&QFwdLo=OZczj|hy(ATL00g=U7><;wLrE|IaN=xb1J?nzP&mKr+=#V&WS{kFZ6 z54=fy*K=6F-b1fLgA@_1-4My@NniZ&qAV9UHcu1&(a-MtdH@zSG?lQp0@fh|9@Vk3 z9wY_ga?aiT9p`!Es+t9g?YEg#x$yvcB$j$d0z3+O6CBtC!~ptmmU?Axdmu1_vH;!^ z_#H<0v^^9U)dXdGeLiYn4j0zAb>E|f4^KVz7VT7d=Fs2|v9hY4OEH(+c=IO@0HtT+d%QZ)qFBLeQL`Xw3F{m`z;?MD zJn-Nw#W<$LP-Y?@%~Qdf#P8U3Nw{_X_v0q`ou$k+2?D0+N&{3Cxi!9Lp{bcb^j1k* z@il~nzQO5LwhaoHrWJT2EUbX30__6GN{!NW#Gl`EcH^ufz4#~>jl}>TkBj_-PmgZ} zlm%pkNWtl*Z5v8PIZ<_7=nU*EZFOqGS7NJ|23Fx3V_`mMJdM4G{E4h3Dj-Xc5cVTZ z_6^p_*5OEZrdN=_CB>q(G(uI7#} zWG8KQrVoEIrj7YM$1_L`K*1D604#q3*DyP(NE0vcUg!H2-Mu?yhh=`!J{4H0b4gii z-D9g>!r#Y54e6@4J-hG%!sR^Q|djXWsA+>Vv!P|LY)v9YAVK zhb`#0t~1m%YVdJnsx3{hkeXr+fv3g~fP<%*F)uE)OmH{;K$@A|#4CE6?82&}YJ!3E z`@7FEjr_Gt2dvZt-emFNI>x)Q1to&mhU&ge_vDpgtMv9AMr3k{-KEdB!ZwDxEHOQC zKZ4|g%tIT$#SO5}iD*?EY8HxG`*TOaz20BIZ${g05SKsa9kZh(M(_!mR(0dVj@>BA zf8i(vzP_DM_SnbMC~hiqngN_KUS)Hz<|rs%!}oe377nx$qwrGg*o5)anWtsv#*ThV z&9}5_UrUzU#n%y`T0z=}Fwj_mwf>-WRlPs15UN?(=I%dB4ifEzC_(2JLrTN5H&2OS zb=A!(I9VrV%x&?ylMPgqI!=ybO(jX}yROpvf`D_Ee zit%SY8`(LU{EyIJCjWDbh|!nnV!`fNfoT&RsM4Kqoy1r`Rk_|2vd_B3jcF>Kdn6k; zygrfzm8xwAL=EuVBseh*yn@q|)c>fPtLh(vAdEp%CZ1ah6--Zn$3>9Sl z3h>t%sDBCmc1!>p=|4?G{VMp^xsX2#HiJ`<|M!&0uQ z0J?%ZuVBDm%eTJ*{F(^<0iaL#>l^)%7XFIzS1gE0at^Z;Pl*A1xbg}>>uB9KuHW_7qRtO_-9szqX z>68WAy1w)j8EK_kSUjhP-UCE4Uwz{KfjRoqlkIfayu!x11{l)QsDcvi*Vm?|OTf+C z-Fryc`Wg@9ps4}=hD{*Mil?U+X_^9&WMA8b#p;k>%u>(6#LAJG>9_rV=J;Q1gMaz! zB_MglP8O6Pu=GQ4-}UrT3_w)QRYbax^u5n#nV;y@k=YakORdy|fcN8KnMB<)Mqx-eX(FQ>1*O3Av@xHL!871tGH z%Jr|1OHQ7O{{W0KeZWV=$|VfK5%}t-*(0y9YwcZU;SU-dZ}n$4Ga^;wZ#-r}pNn)6zGH%xcnBXid?wrV>UPie(^^kP&{<~L+io9GG3!oYKDVW7I#pM;oyc09oq1pjD zLVp$QA{8mS&&3J>U4zcY898QX+aP!FaIecXC)zqR)@3_=K^P{C2bL9>AJ%sGd>9(R z@Tl|+Pzn|c^Kk#5_y`#-*%7N=5Y)$zj?J@uLqmxdoSjD|eo;RW#PMl_#hLAs;~3Gv zi_Q#IZGOHBP(3UKR@K&$B-5I1J=cpZUcqGm-HFG~@epO+qPjzj?@p1@-?U3yA)GZm zn9944Shi>1p==Qr%e^V$6z~diA_?x3BKD;PIc{ZrZBzrVIf>p6(6%m~F$`XSO*i{{ zr&nH1`rlQ?-#-gA1sVe4{3ZKAe|h6YW&WxxC2GpH**pLrp}i;Q^|S@50GRg;Kp3a^ z1-1C$8dt@5Xob^PEM_TGYSqt=Jrp@drqu(^<+9dq-w67$pGWdOSC!HqgvxYFV9jr$ zEaF%?D4%STRGVo|YD(5b+aYP&<(V zurxdSQ@UJcmu3be$3m=NScblMUn90vw4)t9D44=?Jue7eed3vf{`vD(D-h#h&>SXb z+LAJ0(;HyzwYt6VddE`t$6}fj<3de_g*Bbpyt+iZ0&g2ap3GC8wSR1lj;-_6v-8TQ8UgiM*>O>cOrO_=L8mDf1>n-(nT`VuV?C7fpSKj z)gMRl_`-$sDx%tQ*WRUE&RkkYY(GidcJp1d=Z+9U@-~$m!bBCa$@PQx00|i$T2}M; z1aN2Y_7(OqvNwErC3gkUc1FD0S-6kos$+HZ^h^E)15f!h|g# z@S;BYu1VX5J2eCiip%4U&0@&mfnA-aF!1UAljC!zd431)1Zc*FQX2Q% zKqHgJR!GJzuh*XKEw6Mi(1^)8D{@qrDTj&I&a3qg0_b8Um`GOd6Rg) zq@WHdLczQn?p*kaeO?Jsl^-go9xma*CA9l1K?(=oGUVy655^+qmpxd@T!XxGmz{O$ zl2V$$D^FiHUWc?8QuCSBQuB=n>M@rqUNp-lUc1g0j+{EPMJrxMzYf1CH@VxfgSj&h zRo1g(zhaZ{f5-F$`=9LCcm=Db^5sbpDg*@fA9n0$Zs1^Itm@=oVPod_o98e2U~Rj| z1$YwFfA%}c#|bx9snCthp$FzLDwRk~CVI2eoEc+eip%FbROq#4r&gsMVQXo1q8XmL zc}2O7I_{jCEvkRvL{a~GY}g~pM?Qu~u2$QSDw{GjukS4H{A6fVuWJ!(z}VG}qpQ2%wc<6sA*$Rl;cM4HP6V?cRXAWY z&Su2|qbJ8EJ&%PkU$C40$D*r%&{s`bbhpGVf~M6qE*61!3h7MkVIr4ks&@M!n%1lk z&JIT$G^GuVs_6{+dGU*Bn(TF5)jou|i`{5`oSR@KUew z$IUUuXhO(3Kx`Uu49MYiB(2I`vFPCPC_gQ&9@3O^=fWNB)eIk+#@m7c1Dip6rjzgv zbmq%7-BLQ_=5Z5jDv>u8F}1#~%F>;?V<20rF+4sn`;yL7xrZx7K4gGx59inoKFRX- zU4OW(?X0Qe?vM4W5L}@jpKa;{ubzcTlQ9w!IG8plBCypc@7qmZbCc=i=Fx4hmZ8^nvsh? zwA3{X8sj&wt|%vJ4!#TBZG4};7=RQ($=U8$6Z%OyNX5@yO;RDkRm%f8g|vy6o+B=1 zWhBWMyK9-G(19>^>*RKWmt(uv5~*MpG2S($*LmiBL(ec1%J(nAuE)sFekeNZY24;%Xj+^zfQia9|Y(_(WipD>*lT;r$EO z-8%J{9;NfWknk!tGuPfyy|)LL$fWv~D+yFI!xr{jN%MoXz`ESHjClKSgKuUdgQFIQ zZbM{AWlxi2Z`{W;b=VGnSYeHMTJwZyLS1m8Wz0#aw?O%Ps*UGmQE*Bz=FF+kD zJy(`1GMZ-p^a1wj5pnPJJyOh$uGo;KytpW;Scg3r!N`3qC1EA=we~q-7oeHvVt6FW z$^&Qpicw)-y7KV>Yy#CR-L{wA&FjO59a?uq<@%l6vimdwUQH}*&(o=rYr&vYe)%!5 zM%L{KA94o2iw#0D=$aieb=qr+=|o;YOd(q8TZcK4MShtBvY2k zmG)^v@EQk~GpG+_M`;ljUDZxpv9e4V$?M>8EnFzFD#}Ic!;+_a>!bQsNhBFrO%;(p zegcS_w4b&zl?q8B8VFW%nm8Q=*VzTbE++{lOh8k9GrAy+=sJ} zMGNtrmh1x8MeH5-Ri7PY-+V7cRC*Msc3LCr*S~QI#}F!N0+C0auZkbw5!b(veLNN331p|S~(?hNhQHf z6L0KY<&wWQzFOzAIvzCaS4v89eoDmJP|lAR(BD**M!;5Lca?lb&IK`65==w+Y~5oE zR5AcZiw9CBH zND+6kugZfQ%BaPUF1)@T9-eY_N+m;voU!157CEmJoGD#^u!6Fhu?Z>nlcr(4r)HWJ>cTje z`7Pg@*+wK@euyk}9fL=TelsKw{Q>T+antZ{ zgCrNGjuj_3=Yw;D8!QV$W(Nm6(bRJr+{@2?#6e4m0kFj7C|Ggqyyl!V96GSE`gbUZ zzDga$t!EYB|7e#9*E7}JFSRr+JOl*!A9nd$5#?xZV&dfZj}rX%8`ggn;8XGKpP*O) z!r;KCPLLoNv|Wmvw)#cn>tlOVGy+_UjX zXPwczg-ZjyZg^KVCfMN&`0n_{EgqfPJO{`6rf8T!>_Mzr*G(qjFR`|YW;US%wpWq@5`_KPZcFIlpBOnlL!?&v5md(X9I9^3Ne}9VC<2!or%Lgh7U`%(63^XNMaN>A&)&`RrW-x>C9LnwusU}Fg{v#7)G$Qh8k(eUWgt>>ZsnW8j-B> zZ{t>Rrvx<_b|c)bxjspuI8n>)`{7}kY0}PjkBmY`##r*|L+R+xTaZJ(OunR zA>O96e=*e_;PaQ9v<>F1ff-;TYTz&ZX1XDFXUU)HuTV)m!}tgnw^t4p+^A#6=VEAr zG`ZmAR>n^^jh@!K9k8DF{gPr~aISjN`c_7($K~Y* z=I66u@bhV|n5W{Z1)g9gYwT`-c2@7(Ab5_v@3&tH>%MkTbWDNTFm_!E-W2vhrI)Ze zuHAKUt*Jt4^uRW?dYIY^gm=j*_YR?F&q2L$9J$lxK|N6#RjW8Lj%Qf<60U}Kjk|$7 z`x83#Bifr%73uP+Tn7L~_%>~4Xono=rJA;VNCosxdP^3X%o_1wX`cm(W++efPFa8u z(=`3wBM?pCK2*41z731>ZxkLQ zN|o9yS={6>|BO%+J6p9(`^3nm9N>-a)7G!+DwNyhaD9N)jwNkpA}jHES5LiTZSX!| z@xXo`hs2@#SPY{(`8r*{AXK+gf&A4?ENyKazphF)ct=Zd$lD{D& zA?EG&#oLHV>EcX7DuoI3&oR}+O4!RPG_Z)(?F_gt^G z;yW#MMg)JBf3L+`S96g4mU>84wm7q0Q+@gb)=KfVysgQsw>GySz@Md`gSRjbdjq$S zVp!a3_0Z*c?Tr)ngT2~xQ#!en7_pr5oE0TmfVPsgehK~^dEL|~G}gzu+%`!##4;Z- zH7A@k?5kj?%8mNC`u$vS+QjeH#zDghboF_QR)VGLMuMX?{KHS6jITjgHgt|sulM)7dyKabK9_duD7tdYHb>`YFd-5s@0O4&DG3{g;`-Dd7IPBbOLKOy4KUbLC~RjW z(UAeN?Pn)PTT$T?k|;p22W=CNxgg|A;C*f^bort#RXFU|!ip6+@`Z_c#+(}l4IW?4 zbzAfqkQeN+VEA^T`GER5YY@P)3hHQyH{Q+*U|g22%7eaWT0!J+ z(oR=pVE(Ot3a}#A=(vW9W@&2_1#XFR&8d+7kUw#0cJ`BXeU_k0Se8ZZD;=(-`HN1q zTg>9DFwK&RpWXsHE?oU+P}3Sz%gtAb1+TtnOmS>1y)F6TBKS$wGnz=G@Q&kp&RUBi zHNkCh0^MOYTm3_bypaXe3gOqp(VE)}Jc?-2RI;*Q4O9`H**SMNHhb-KK%`s+W@0Tq) zUuhyPT>2bvdt8dl;l6)xF?wG(yYG{`v^!1LESZfHf$t}D7@Pqu@Tyyc{C?X2C11oU z&G%Nn$F;>Lgd1Mh)%0zd!@0BAwA+f;BOoBEoOn#!cXQQ`+)tecY2SdE@I74TH;uyJ zPSf0_qDwme@4P6UN>wQv%R6rxSXRFY5k~b!exD$OC_BE!kJoMGD&Sbm_TfR3yv#&j zZFtH*zlX9C3%TBk)h7j7@a-Y0&HM z3ivu>=GZDwnn|+z@*)|&W&X63BaS+!Gv+kA7=+$Qz7H|r$fX9jHY^JB4`V&|Oh!YY zaM-TolYTv47e00i_$;70rorl>ro10qXGvx0&dsA1H3b_aH6%bKNFHLF`vO0j*Y`f@ zkn_9d(b}Uc*f%aY`>_;>iPLKBMMKA7QdZmCnkaf`!R{s5z-{1>!i4arDk+IrX zYX-<9HRy{3Kv2O)Fq+zP*Nc0`dOURNVyM)rHqAOu+5hYCZkgELedGhHSJq(l`f)4?68jTud)ENy6vsVejKYu7u>Q7TqyEdNX< z1SnMwNV5DCjXqe#Q}LZs`5+n=7BmIkVV@Mj?$6JENHP9!leS)Fti zM)`;CKyej~myHc5Oja*BbxTIOa&9mKOA8q)j|in^3gg$conusof~*3Y*V;5b5*GK_ zX=aloW<-*_#Y9hiL_OiMp$=s!S^By4Kyz+t*gu3k^1}I?WIc%lV2~BtV)I5k2}B1l zkOYLV%=VSrAlWL4$gXyfBiOtJt`2-5qStn>2?o-bhFVDwhJ1@+ZJyX~qtMTW zOu_~GDoI)+e3k^CWywTY-ElH;YwF@nx+NH?=dL zNtp4Hfrb_99<1lwz7OWD+?Hh105-4k(5QRP|2cVY2FZ{)Vqsd81e#K^7?o0j>XYR6)BX zp74ENUA!*ug&c5Y2Y9yK(8M`Y=}~sM09@;9*RY^NqV$T3(C$sN3h=mi#k_1Kwg;%Y zCZscjO#rm>%j(C)V&syT{v=zjN9F9KZ;H}(#;j97>-z?kZwzHZxc{DAGDo7xQN-I( z2QeF!N|vM-F~F^J&=6|03Z0HOR$IGED^~Y(;%KQj%}x;GTO1OF6f~Cu^5u0=l)G8A zLAcuv*APm1M_UE2s}RifUx&4 zGv>pgk_+m>?@u?gop?=eon2UYR7KFAad#UEY7nSlI$)(D@FGnJ*EZgjFDMbhHvHhz zct=(tzDjS`ZbYh()K&U)BVuj1%L3|-`w^%ZXdcoKAJ@+@C#w1VP@_=H%8w@!9&djE zzX^T2UPAGVZ`79J4Wf78w3;gy_Lq&K{AbQmAl}V{s{20f$Ku8^#~FxI#>;F@)*L0( zD}){oq{9A|H>iA+JJw;mwdU#BxnD-&Q}aJrwyh;g?c!^TQm!EHLmGTsfwOw2d0DkT zt`wqC(dyp?m!}wi)n_AH2b2FP^ou6{V?}^;pjB>w4HbvYn0?u&pK{3#xBhK%2HV5tpf7G`!njKD|E+ZDe zA13^ODamEh<~n6brJZQga88p9CuE+;4St3;Wd)*cB96hYe@_fJet~AE*?R8?&#{6zub@M&Rt7h^++h7i%IHN}|`!sc*b*oA!%?st;Yd zA=F^a0`R^meEpOg0O5$mQ20|!bv1OV^hf4PzoUnn^CWm9@P1-#-aCE`a@7xADu~W( zi_z0dlUXUgXOAJGl4W?-Ucm+|!*;(5^^gqiKzqH8z46?YYJ3{t2KOGe<%VRM`$dX> zC?6ygIt8wiIu7}hLn`JU9R4*N`IYq7 zj_seM960~_^8a7|_E(0#wj%#zSn~RJhQBr@e`WA%iSs9e_?Nu-AF}+%7yViA{L1C; zA^J}q5D)~E5D>ox>|d$>?hyYVLXNB{|p^b@>gCi3~CR;zP~pe!KfWU$~ZN literal 0 HcmV?d00001 diff --git a/unittests/tools/test_deepfence_threatmapper_parser.py b/unittests/tools/test_deepfence_threatmapper_parser.py new file mode 100644 index 00000000000..2dc584b2259 --- /dev/null +++ b/unittests/tools/test_deepfence_threatmapper_parser.py @@ -0,0 +1,43 @@ +from dojo.models import Test +from dojo.tools.deepfence_threatmapper.parser import DeepfenceThreatmapperParser + +from ..dojo_test_case import DojoTestCase + + +class TestDeepfenceThreatmapperParser(DojoTestCase): + + def test_parse_file_compliance_report(self): + testfile = open("unittests/scans/deepfence_threatmapper/compliance_report.xlsx", "rb") + parser = DeepfenceThreatmapperParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(7, len(findings)) + self.assertEqual(findings[0].title, "Threatmapper_Compliance_Report-gdpr_3.6") + self.assertEqual(findings[0].severity, "Info") + + def test_parse_file_malware_report(self): + testfile = open("unittests/scans/deepfence_threatmapper/malware_report.xlsx", "rb") + parser = DeepfenceThreatmapperParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(9, len(findings)) + self.assertEqual(findings[0].title, "MD5_Constants") + self.assertEqual(findings[0].severity, "Low") + self.assertEqual(findings[0].file_path, "/tmp/Deepfence/YaraHunter/df_db09257b02e615049e0aecc05be2dc2401735e67db4ab74225df777c62c39753/usr/sbin/mkfs.cramfs") + + def test_parse_file_secret_report(self): + testfile = open("unittests/scans/deepfence_threatmapper/secret_report.xlsx", "rb") + parser = DeepfenceThreatmapperParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(7, len(findings)) + self.assertEqual(findings[0].title, "Username and password in URI") + self.assertEqual(findings[0].severity, "High") + self.assertEqual(findings[0].file_path, "usr/share/doc/curl-8.3.0/TheArtOfHttpScripting.md") + + def test_parse_file_vulnerability_report(self): + testfile = open("unittests/scans/deepfence_threatmapper/vulnerability_report.xlsx", "rb") + parser = DeepfenceThreatmapperParser() + findings = parser.get_findings(testfile, Test()) + self.assertEqual(3, len(findings)) + self.assertEqual(findings[0].title, "Threatmapper_Vuln_Report-CVE-2021-36084") + self.assertEqual(findings[0].severity, "Low") + self.assertEqual(findings[0].mitigation, "2.5-10.amzn2.0.1") + self.assertEqual(findings[0].cve, "CVE-2021-36084") From 1bb36842e0ff11c3739ae2edd41713cc0f7c2991 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 24 Jun 2024 18:25:44 +0000 Subject: [PATCH 55/65] 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 f6e63072c2d..688f4f5d52f 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.35.4", + "version": "2.36.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index d87d6e4c64f..423f4050e5c 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.35.4' +__version__ = '2.36.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 f8489d347c9..44d22f12954 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.35.4" +appVersion: "2.36.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.136 +version: 1.6.137-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From 324f0df045d4ea76a912dc63f3da84b90d13d1a8 Mon Sep 17 00:00:00 2001 From: DefectDojo Date: Mon, 24 Jun 2024 18:32:03 +0000 Subject: [PATCH 56/65] Update helm lock file Signed-off-by: DefectDojo --- helm/defectdojo/Chart.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index b485770474c..8774f3f689a 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -4,15 +4,15 @@ dependencies: version: 9.19.1 - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 15.5.1 + version: 15.5.9 - name: postgresql-ha repository: https://charts.bitnami.com/bitnami version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.3.1 + version: 14.3.3 - name: redis repository: https://charts.bitnami.com/bitnami - version: 19.5.0 -digest: sha256:f7d84de0e09aa04522aca1b64fb2a297ad028c507144046f16da47d6750007dd -generated: "2024-05-30T16:46:40.020662037Z" + version: 19.5.5 +digest: sha256:8b025085ec71a05b7b62f4b85a1afdabf884d5fa878494671989ec03939872c8 +generated: "2024-06-24T18:31:53.752292333Z" From 5941b6341802a96ddd84f0f9a1308b7f8aa7cf76 Mon Sep 17 00:00:00 2001 From: DefectDojo Date: Mon, 24 Jun 2024 18:57:05 +0000 Subject: [PATCH 57/65] Update helm lock file Signed-off-by: DefectDojo --- helm/defectdojo/Chart.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/helm/defectdojo/Chart.lock b/helm/defectdojo/Chart.lock index 28c80976067..74468c83ba1 100644 --- a/helm/defectdojo/Chart.lock +++ b/helm/defectdojo/Chart.lock @@ -4,15 +4,15 @@ dependencies: version: 9.19.1 - name: postgresql repository: https://charts.bitnami.com/bitnami - version: 15.5.6 + version: 15.5.9 - name: postgresql-ha repository: https://charts.bitnami.com/bitnami version: 9.4.11 - name: rabbitmq repository: https://charts.bitnami.com/bitnami - version: 14.4.3 + version: 14.4.4 - name: redis repository: https://charts.bitnami.com/bitnami - version: 19.5.4 -digest: sha256:dfc4c827cf13859928ebf770e5a384721ea67ecedab22fd7baf0e6ede28c6fd4 -generated: "2024-06-17T17:37:48.301414062Z" + version: 19.5.5 +digest: sha256:7ad88ea953ebef3acbd1270eeae206e4e650f2fb20f754e0d912688795500b18 +generated: "2024-06-24T18:56:55.876075791Z" From 37879a410e045412e7a55bb4b3512ea00020455d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:52:51 +0100 Subject: [PATCH 58/65] Bump nginx from `69f8c2c` to `a45ee5d` (#10448) Bumps nginx from `69f8c2c` to `a45ee5d`. --- updated-dependencies: - dependency-name: nginx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile.nginx-alpine | 2 +- Dockerfile.nginx-debian | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.nginx-alpine b/Dockerfile.nginx-alpine index c5e01860a49..b9a55ac4158 100644 --- a/Dockerfile.nginx-alpine +++ b/Dockerfile.nginx-alpine @@ -140,7 +140,7 @@ COPY manage.py ./ COPY dojo/ ./dojo/ RUN env DD_SECRET_KEY='.' python3 manage.py collectstatic --noinput && true -FROM nginx:1.27.0-alpine@sha256:69f8c2c72671490607f52122be2af27d4fc09657ff57e42045801aa93d2090f7 +FROM nginx:1.27.0-alpine@sha256:a45ee5d042aaa9e81e013f97ae40c3dda26fbe98f22b6251acdf28e579560d55 ARG uid=1001 ARG appuser=defectdojo COPY --from=collectstatic /app/static/ /usr/share/nginx/html/static/ diff --git a/Dockerfile.nginx-debian b/Dockerfile.nginx-debian index 14edac5c529..a1fd76d05fe 100644 --- a/Dockerfile.nginx-debian +++ b/Dockerfile.nginx-debian @@ -75,7 +75,7 @@ COPY dojo/ ./dojo/ RUN env DD_SECRET_KEY='.' python3 manage.py collectstatic --noinput && true -FROM nginx:1.27.0-alpine@sha256:69f8c2c72671490607f52122be2af27d4fc09657ff57e42045801aa93d2090f7 +FROM nginx:1.27.0-alpine@sha256:a45ee5d042aaa9e81e013f97ae40c3dda26fbe98f22b6251acdf28e579560d55 ARG uid=1001 ARG appuser=defectdojo COPY --from=collectstatic /app/static/ /usr/share/nginx/html/static/ From dfd0e3ba30b0ad70590975334d0fe80102bf94f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 08:54:09 +0100 Subject: [PATCH 59/65] Bump coverage from 7.5.3 to 7.5.4 (#10447) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.5.3 to 7.5.4. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.5.3...7.5.4) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... 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 cfe71cf6649..27f0d8b515f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ asteval==0.9.33 bleach==6.1.0 bleach[css] celery==5.4.0 -coverage==7.5.3 +coverage==7.5.4 defusedxml==0.7.1 django_celery_results==2.5.1 django-auditlog==2.3.0 From 0bd2ac0ef1f03ae3aea939e6d79b76d5a6a1d8e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 23:35:55 +0100 Subject: [PATCH 60/65] Bump boto3 from 1.34.131 to 1.34.132 (#10452) Bumps [boto3](https://github.com/boto/boto3) from 1.34.131 to 1.34.132. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.131...1.34.132) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 27f0d8b515f..694ec7c6ef8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.131 # Required for Celery Broker AWS (SQS) support +boto3==1.34.132 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From e70066f0751143364cf19052c6d9fc544324b137 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:12:14 +0100 Subject: [PATCH 61/65] Bump debugpy from 1.8.1 to 1.8.2 (#10457) Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.8.1 to 1.8.2. - [Release notes](https://github.com/microsoft/debugpy/releases) - [Commits](https://github.com/microsoft/debugpy/compare/v1.8.1...v1.8.2) --- updated-dependencies: - dependency-name: debugpy dependency-type: direct:production update-type: version-update:semver-patch ... 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 694ec7c6ef8..3e6af145b01 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,7 +51,7 @@ social-auth-app-django==5.4.1 social-auth-core==4.5.4 Python-jose==3.3.0 gitpython==3.1.43 -debugpy==1.8.1 +debugpy==1.8.2 python-gitlab==4.6.0 cpe==1.2.1 packageurl-python==0.15.1 From c8d83c28cb065e47f5e48d892a692eb470a45d73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 03:48:55 +0100 Subject: [PATCH 62/65] Bump redis from 5.0.6 to 5.0.7 (#10465) Bumps [redis](https://github.com/redis/redis-py) from 5.0.6 to 5.0.7. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](https://github.com/redis/redis-py/compare/v5.0.6...v5.0.7) --- updated-dependencies: - dependency-name: redis dependency-type: direct:production update-type: version-update:semver-patch ... 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 3e6af145b01..34aa44e7c41 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ psycopg2-binary==2.9.9 cryptography==42.0.8 python-dateutil==2.9.0.post0 pytz==2024.1 -redis==5.0.6 +redis==5.0.7 requests==2.32.3 sqlalchemy==2.0.31 # Required by Celery broker transport urllib3==1.26.18 From 34d87a152927a69bdaf25d0a036ac5f3ee22f978 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 03:49:46 +0100 Subject: [PATCH 63/65] Bump boto3 from 1.34.132 to 1.34.135 (#10470) Bumps [boto3](https://github.com/boto/boto3) from 1.34.132 to 1.34.135. - [Release notes](https://github.com/boto/boto3/releases) - [Changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst) - [Commits](https://github.com/boto/boto3/compare/1.34.132...1.34.135) --- updated-dependencies: - dependency-name: boto3 dependency-type: direct:production update-type: version-update:semver-patch ... 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 34aa44e7c41..27eb0b2603f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -75,7 +75,7 @@ django-ratelimit==4.1.0 argon2-cffi==23.1.0 blackduck==1.1.3 pycurl==7.45.3 # Required for Celery Broker AWS (SQS) support -boto3==1.34.132 # Required for Celery Broker AWS (SQS) support +boto3==1.34.135 # Required for Celery Broker AWS (SQS) support netaddr==1.3.0 vulners==2.1.7 fontawesomefree==6.5.1 From 2d2f2ab423cd96474b98cba867389f798c5eeb2f Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 1 Jul 2024 15:04:36 +0000 Subject: [PATCH 64/65] 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 688f4f5d52f..ae18f7927c5 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.36.0-dev", + "version": "2.36.0", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 423f4050e5c..b6ae12017f9 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.0-dev' +__version__ = '2.36.0' __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 3be83c4a9f4..3ede21350c9 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.36.0-dev" +appVersion: "2.36.0" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.137-dev +version: 1.6.137 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From d2d2ced09029d373ec8737231bfb4d32af921e03 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 1 Jul 2024 15:39:46 +0000 Subject: [PATCH 65/65] 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 ae18f7927c5..ab3201e6a41 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.36.0", + "version": "2.37.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index b6ae12017f9..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.0' +__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 3ede21350c9..ab21a0409cb 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.36.0" +appVersion: "2.37.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.137 +version: 1.6.138-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap