From 00d33f8f66b3bdd33cdf45c45bddbefa4d33e0b9 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 1 Nov 2023 08:14:15 +0100 Subject: [PATCH 01/81] chore: unittests for vulnerability checks (#720) --- .../access_control/services/authorization.py | 13 +++- .../services/roles_permissions.py | 6 ++ .../access_control/api/test_authentication.py | 3 + ...test_authorization_vulnerability_checks.py | 66 +++++++++++++++++++ .../fixtures/unittests_fixtures.json | 48 ++++++++++++++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 backend/unittests/access_control/api/test_authorization_vulnerability_checks.py diff --git a/backend/application/access_control/services/authorization.py b/backend/application/access_control/services/authorization.py index 89b4be6ee..81a138aa1 100644 --- a/backend/application/access_control/services/authorization.py +++ b/backend/application/access_control/services/authorization.py @@ -9,11 +9,14 @@ from application.commons.services.global_request import get_current_user from application.core.models import Branch, Observation, Product, Product_Member from application.core.queries.product_member import get_product_member -from application.import_observations.models import Api_Configuration +from application.import_observations.models import ( + Api_Configuration, + Vulnerability_Check, +) from application.rules.models import Rule -def user_has_permission( # pylint: disable=too-many-return-statements +def user_has_permission( # pylint: disable=too-many-return-statements,too-many-branches obj, permission: int, user: User = None ) -> bool: # There are a lot of different objects that need to be checked for permissions. @@ -81,6 +84,12 @@ def user_has_permission( # pylint: disable=too-many-return-statements ): return user_has_permission(obj.product, permission, user) + if ( + isinstance(obj, Vulnerability_Check) + and permission in Permissions.get_vulnerability_check_permissions() + ): + return user_has_permission(obj.product, permission, user) + raise NoAuthorizationImplementedError( f"No authorization implemented for class {type(obj).__name__} and permission {permission}" ) diff --git a/backend/application/access_control/services/roles_permissions.py b/backend/application/access_control/services/roles_permissions.py index a2b501b9d..1f42a787b 100644 --- a/backend/application/access_control/services/roles_permissions.py +++ b/backend/application/access_control/services/roles_permissions.py @@ -122,6 +122,12 @@ def get_api_configuration_permissions(cls): Permissions.Api_Configuration_Create, } + @classmethod + def get_vulnerability_check_permissions(cls): + return { + Permissions.Product_View, + } + def get_roles_with_permissions(): return { diff --git a/backend/unittests/access_control/api/test_authentication.py b/backend/unittests/access_control/api/test_authentication.py index d0f64ecb3..81d3df225 100644 --- a/backend/unittests/access_control/api/test_authentication.py +++ b/backend/unittests/access_control/api/test_authentication.py @@ -227,6 +227,9 @@ def test_authentication(self, mock_user): ["delete", "get", "put", "patch"], "/api/api_configurations/1/" ) + self._check_authentication(["get"], "/api/vulnerability_checks/") + self._check_authentication(["get"], "/api/vulnerability_checks/1/") + self._check_authentication(["get", "post"], "/api/general_rules/") self._check_authentication( ["delete", "get", "put", "patch"], "/api/general_rules/1/" diff --git a/backend/unittests/access_control/api/test_authorization_vulnerability_checks.py b/backend/unittests/access_control/api/test_authorization_vulnerability_checks.py new file mode 100644 index 000000000..fb1d7b841 --- /dev/null +++ b/backend/unittests/access_control/api/test_authorization_vulnerability_checks.py @@ -0,0 +1,66 @@ +from unittests.access_control.api.test_authorization import ( + APITest, + TestAuthorizationBase, +) + + +class TestAuthorizationVulnerabilityChecks(TestAuthorizationBase): + def test_authorization_vulnerability_checks(self): + expected_data = "OrderedDict([('count', 3), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('branch_name', ''), ('scanner_name', 'scanner_internal_no_branch'), ('filename', 'filename_internal_no_branch'), ('api_configuration_name', ''), ('scanner', 'scanner_internal_no_branch / 1.0.0'), ('first_import', '2022-12-15T17:10:35.521000+01:00'), ('last_import', '2022-12-15T17:10:35.854000+01:00'), ('last_import_observations_new', 1), ('last_import_observations_updated', 2), ('last_import_observations_resolved', 3), ('product', 1), ('branch', None)]), OrderedDict([('id', 2), ('branch_name', 'db_branch_internal_dev'), ('scanner_name', 'scanner_internal_dev'), ('filename', ''), ('api_configuration_name', 'api_configuration_internal_dev'), ('scanner', 'scanner_internal_dev'), ('first_import', '2022-12-16T17:10:35.521000+01:00'), ('last_import', '2022-12-16T17:10:35.854000+01:00'), ('last_import_observations_new', 4), ('last_import_observations_updated', 5), ('last_import_observations_resolved', 6), ('product', 1), ('branch', 1)]), OrderedDict([('id', 3), ('branch_name', 'db_branch_external'), ('scanner_name', 'scanner_external'), ('filename', 'filename_external'), ('api_configuration_name', ''), ('scanner', 'scanner_external'), ('first_import', '2022-12-17T17:10:35.521000+01:00'), ('last_import', '2022-12-17T17:10:35.854000+01:00'), ('last_import_observations_new', 7), ('last_import_observations_updated', 8), ('last_import_observations_resolved', 9), ('product', 2), ('branch', 3)])])])" + self._test_api( + APITest( + "db_admin", + "get", + "/api/vulnerability_checks/", + None, + 200, + expected_data, + ) + ) + + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('branch_name', ''), ('scanner_name', 'scanner_internal_no_branch'), ('filename', 'filename_internal_no_branch'), ('api_configuration_name', ''), ('scanner', 'scanner_internal_no_branch / 1.0.0'), ('first_import', '2022-12-15T17:10:35.521000+01:00'), ('last_import', '2022-12-15T17:10:35.854000+01:00'), ('last_import_observations_new', 1), ('last_import_observations_updated', 2), ('last_import_observations_resolved', 3), ('product', 1), ('branch', None)]), OrderedDict([('id', 2), ('branch_name', 'db_branch_internal_dev'), ('scanner_name', 'scanner_internal_dev'), ('filename', ''), ('api_configuration_name', 'api_configuration_internal_dev'), ('scanner', 'scanner_internal_dev'), ('first_import', '2022-12-16T17:10:35.521000+01:00'), ('last_import', '2022-12-16T17:10:35.854000+01:00'), ('last_import_observations_new', 4), ('last_import_observations_updated', 5), ('last_import_observations_resolved', 6), ('product', 1), ('branch', 1)])])])" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/vulnerability_checks/", + None, + 200, + expected_data, + ) + ) + + expected_data = "{'id': 1, 'branch_name': '', 'scanner_name': 'scanner_internal_no_branch', 'filename': 'filename_internal_no_branch', 'api_configuration_name': '', 'scanner': 'scanner_internal_no_branch / 1.0.0', 'first_import': '2022-12-15T17:10:35.521000+01:00', 'last_import': '2022-12-15T17:10:35.854000+01:00', 'last_import_observations_new': 1, 'last_import_observations_updated': 2, 'last_import_observations_resolved': 3, 'product': 1, 'branch': None}" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/vulnerability_checks/1/", + None, + 200, + expected_data, + ) + ) + + expected_data = "{'message': 'No Vulnerability_Check matches the given query.'}" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/vulnerability_checks/3/", + None, + 404, + expected_data, + ) + ) + + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/vulnerability_checks/99999/", + None, + 404, + expected_data, + ) + ) diff --git a/backend/unittests/fixtures/unittests_fixtures.json b/backend/unittests/fixtures/unittests_fixtures.json index 2ac0a1aab..a9211dc7b 100644 --- a/backend/unittests/fixtures/unittests_fixtures.json +++ b/backend/unittests/fixtures/unittests_fixtures.json @@ -503,6 +503,54 @@ "api_key": "__secret__" } }, + { + "model": "import_observations.vulnerability_check", + "pk": 1, + "fields": { + "product": 1, + "branch": null, + "filename": "filename_internal_no_branch", + "api_configuration_name": "", + "scanner": "scanner_internal_no_branch / 1.0.0", + "first_import": "2022-12-15T16:10:35.521Z", + "last_import": "2022-12-15T16:10:35.854Z", + "last_import_observations_new": 1, + "last_import_observations_updated": 2, + "last_import_observations_resolved": 3 + } + }, + { + "model": "import_observations.vulnerability_check", + "pk": 2, + "fields": { + "product": 1, + "branch": 1, + "filename": "", + "api_configuration_name": "api_configuration_internal_dev", + "scanner": "scanner_internal_dev", + "first_import": "2022-12-16T16:10:35.521Z", + "last_import": "2022-12-16T16:10:35.854Z", + "last_import_observations_new": 4, + "last_import_observations_updated": 5, + "last_import_observations_resolved": 6 + } + }, + { + "model": "import_observations.vulnerability_check", + "pk": 3, + "fields": { + "product": 2, + "branch": 3, + "filename": "filename_external", + "api_configuration_name": "", + "scanner": "scanner_external", + "first_import": "2022-12-17T16:10:35.521Z", + "last_import": "2022-12-17T16:10:35.854Z", + "last_import_observations_new": 7, + "last_import_observations_updated": 8, + "last_import_observations_resolved": 9 + } + }, { "model": "rules.rule", "pk": 1, From a215967e377d005ed42cc5ece90f906e1145f36d Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 1 Nov 2023 17:42:16 +0100 Subject: [PATCH 02/81] chore: test for import_observations (#722) * chore: test for import_observations * chore: check references and evidences * chore black * chore: don't copy files * chore: add epss mock --- .../application/core/queries/observation.py | 2 +- .../application/import_observations/apps.py | 45 +-- .../services/import_observations.py | 5 +- .../unittests/fixtures/data_1/bandit.sarif | 127 ++++++++ .../unittests/fixtures/data_2/bandit.sarif | 61 ++++ .../import_observations_fixtures.json | 98 +++++++ .../import_observations/services/__init__.py | 0 .../services/test_import_observations.py | 274 ++++++++++++++++++ 8 files changed, 590 insertions(+), 22 deletions(-) create mode 100644 backend/unittests/fixtures/data_1/bandit.sarif create mode 100644 backend/unittests/fixtures/data_2/bandit.sarif create mode 100644 backend/unittests/fixtures/import_observations_fixtures.json create mode 100644 backend/unittests/import_observations/services/__init__.py create mode 100644 backend/unittests/import_observations/services/test_import_observations.py diff --git a/backend/application/core/queries/observation.py b/backend/application/core/queries/observation.py index 2fc67d828..74ea6f02f 100644 --- a/backend/application/core/queries/observation.py +++ b/backend/application/core/queries/observation.py @@ -54,7 +54,7 @@ def get_observations_for_vulnerability_check( filename: str, api_configuration_name: str, ) -> QuerySet[Observation]: - return get_observations().filter( + return Observation.objects.filter( product=product, branch=branch, upload_filename=filename, diff --git a/backend/application/import_observations/apps.py b/backend/application/import_observations/apps.py index 2f4db7d04..11b8cd73d 100644 --- a/backend/application/import_observations/apps.py +++ b/backend/application/import_observations/apps.py @@ -38,33 +38,38 @@ def register_module(self, module_name): from application.commons.services.log_message import ( # pylint: disable=import-outside-toplevel format_log_message, ) - from application.import_observations.parsers.base_parser import ( # pylint: disable=import-outside-toplevel - BaseParser, - ) - from application.import_observations.services.parser_registry import ( # noqa E501 pylint: disable=import-outside-toplevel - register_parser, - ) try: # Check if it is a Python module if find_spec( f"application.import_observations.parsers.{module_name}.parser" ): - # Import the module and register the classname - module = import_module( # nosemgrep - f"application.import_observations.parsers.{module_name}.parser" - ) - # nosemgrep because of rule python.lang.security.audit.non-literal-import.non-literal-import - # This is the price you pay for a dynamic parser registry. We accept the risk. - for attribute_name in dir(module): - attribute = getattr(module, attribute_name) - if ( - isclass(attribute) - and issubclass(attribute, BaseParser) - and attribute is not BaseParser - ): - register_parser(attribute) + _register_parser(module_name) except Exception: logger.exception( # noqa: F401 pylint: disable=import-outside-toplevel,unused-import format_log_message(message=f"Failed to load {module_name}") ) + + +def _register_parser(module_name): + from application.import_observations.parsers.base_parser import ( # pylint: disable=import-outside-toplevel + BaseParser, + ) + from application.import_observations.services.parser_registry import ( # noqa E501 pylint: disable=import-outside-toplevel + register_parser, + ) + + # Import the module and register the classname + module = import_module( # nosemgrep + f"application.import_observations.parsers.{module_name}.parser" + ) + # nosemgrep because of rule python.lang.security.audit.non-literal-import.non-literal-import + # This is the price you pay for a dynamic parser registry. We accept the risk. + for attribute_name in dir(module): + attribute = getattr(module, attribute_name) + if ( + isclass(attribute) + and issubclass(attribute, BaseParser) + and attribute is not BaseParser + ): + register_parser(attribute) diff --git a/backend/application/import_observations/services/import_observations.py b/backend/application/import_observations/services/import_observations.py index 7b7d063f0..0fdd1fd00 100644 --- a/backend/application/import_observations/services/import_observations.py +++ b/backend/application/import_observations/services/import_observations.py @@ -1,3 +1,4 @@ +import os from dataclasses import dataclass from typing import Optional, Tuple @@ -84,7 +85,9 @@ def file_upload_observations( imported_observations = parser_instance.get_observations(data) filename = ( - file_upload_parameters.file.name if file_upload_parameters.file.name else "" + os.path.basename(file_upload_parameters.file.name) + if file_upload_parameters.file.name + else "" ) import_parameters = ImportParameters( diff --git a/backend/unittests/fixtures/data_1/bandit.sarif b/backend/unittests/fixtures/data_1/bandit.sarif new file mode 100644 index 000000000..ab9d1cf5d --- /dev/null +++ b/backend/unittests/fixtures/data_1/bandit.sarif @@ -0,0 +1,127 @@ +{ + "runs": [ + { + "tool": { + "driver": { + "name": "Bandit", + "rules": [ + { + "id": "B104", + "name": "hardcoded_bind_all_interfaces", + "helpUri": "https://bandit.readthedocs.io/en/1.7.4/plugins/b104_hardcoded_bind_all_interfaces.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true, + "endTimeUtc": "2022-10-21T04:19:27Z" + } + ], + "results": [ + { + "message": { + "text": "Possible binding to all interfaces (dist)." + }, + "locations": [ + { + "physicalLocation": { + "region": { + "snippet": { + "text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n" + }, + "startLine": 14 + }, + "artifactLocation": { + "uri": "backend/config/settings/dist.py" + }, + "contextRegion": { + "snippet": { + "text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n" + }, + "endLine": 15, + "startLine": 13 + } + } + } + ], + "properties": { + "issue_confidence": "MEDIUM", + "issue_severity": "MEDIUM" + }, + "ruleId": "B104", + "ruleIndex": 0 + }, + { + "message": { + "text": "Possible binding to all interfaces (local)." + }, + "locations": [ + { + "physicalLocation": { + "region": { + "snippet": { + "text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n" + }, + "startLine": 14 + }, + "artifactLocation": { + "uri": "backend/config/settings/local.py" + }, + "contextRegion": { + "snippet": { + "text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n" + }, + "endLine": 15, + "startLine": 13 + } + } + } + ], + "properties": { + "issue_confidence": "MEDIUM", + "issue_severity": "MEDIUM" + }, + "ruleId": "B104", + "ruleIndex": 0 + }, + { + "message": { + "text": "Possible binding to all interfaces (dev)." + }, + "locations": [ + { + "physicalLocation": { + "region": { + "snippet": { + "text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n" + }, + "startLine": 14 + }, + "artifactLocation": { + "uri": "backend/config/settings/dev.py" + }, + "contextRegion": { + "snippet": { + "text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n" + }, + "endLine": 15, + "startLine": 13 + } + } + } + ], + "properties": { + "issue_confidence": "MEDIUM", + "issue_severity": "HIGH" + }, + "ruleId": "B104", + "ruleIndex": 0 + } + ] + } + ], + "version": "2.1.0", + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json" +} \ No newline at end of file diff --git a/backend/unittests/fixtures/data_2/bandit.sarif b/backend/unittests/fixtures/data_2/bandit.sarif new file mode 100644 index 000000000..dc372ca4c --- /dev/null +++ b/backend/unittests/fixtures/data_2/bandit.sarif @@ -0,0 +1,61 @@ +{ + "runs": [ + { + "tool": { + "driver": { + "name": "Bandit", + "rules": [ + { + "id": "B104", + "name": "hardcoded_bind_all_interfaces", + "helpUri": "https://bandit.readthedocs.io/en/1.7.4/plugins/b104_hardcoded_bind_all_interfaces.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true, + "endTimeUtc": "2022-10-21T04:19:27Z" + } + ], + "results": [ + { + "message": { + "text": "Possible binding to all interfaces (local)." + }, + "locations": [ + { + "physicalLocation": { + "region": { + "snippet": { + "text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n" + }, + "startLine": 14 + }, + "artifactLocation": { + "uri": "backend/config/settings/local.py" + }, + "contextRegion": { + "snippet": { + "text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n" + }, + "endLine": 15, + "startLine": 13 + } + } + } + ], + "properties": { + "issue_confidence": "MEDIUM", + "issue_severity": "HIGH" + }, + "ruleId": "B104", + "ruleIndex": 0 + } + ] + } + ], + "version": "2.1.0", + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json" +} \ No newline at end of file diff --git a/backend/unittests/fixtures/import_observations_fixtures.json b/backend/unittests/fixtures/import_observations_fixtures.json new file mode 100644 index 000000000..603a5cfea --- /dev/null +++ b/backend/unittests/fixtures/import_observations_fixtures.json @@ -0,0 +1,98 @@ +[ + { + "model": "access_control.user", + "pk": 1, + "fields": { + "password": "", + "last_login": null, + "is_superuser": false, + "username": "-product-1-api_token-", + "first_name": "", + "last_name": "", + "email": "", + "is_staff": false, + "is_active": true, + "date_joined": "2022-12-12T18:48:08.514Z", + "full_name": "-product-1-api_token-", + "is_external": true, + "groups": [], + "user_permissions": [] + } + }, + { + "model": "access_control.api_token", + "pk": 1, + "fields": { + "api_token_hash": "argon2$argon2id$v=19$m=102400,t=2,p=8$bUc4bk13R2RLSElVMlVoRENLeGoyaA$NMzcg5d9N6jufieKF+nADLa4AdLGdMb5lFVPN8zKPm0", + "user": 1 + } + }, + { + "model": "core.product", + "pk": 1, + "fields": { + "name": "db_product_import", + "description": "", + "repository_prefix": "", + "repository_default_branch": 1, + "security_gate_passed": true, + "security_gate_active": null, + "security_gate_threshold_critical": null, + "security_gate_threshold_high": null, + "security_gate_threshold_medium": null, + "security_gate_threshold_low": null, + "security_gate_threshold_none": null, + "security_gate_threshold_unkown": null, + "apply_general_rules": true, + "notification_ms_teams_webhook": "", + "last_observation_change": "2022-12-16T16:13:18.283Z", + "product_group": null + } + }, + { + "model": "core.branch", + "pk": 1, + "fields": { + "product": 1, + "name": "db_branch_import" + } + }, + { + "model": "core.product_member", + "pk": 1, + "fields": { + "product": 1, + "user": 5, + "role": 5 + } + }, + { + "model": "core.parser", + "pk": 1, + "fields": { + "name": "SARIF", + "type": "SAST", + "source": "File" + } + }, + { + "model": "rules.rule", + "pk": 1, + "fields": { + "name": "db_product_rule_import", + "description": "", + "product": 1, + "parser": 1, + "scanner_prefix": "", + "title": "", + "origin_component_name_version": "", + "origin_docker_image_name_tag": "", + "origin_endpoint_url": "", + "origin_service_name": "", + "origin_source_file": ".*dev.*", + "new_severity": "", + "new_status": "Not affected", + "enabled": true + } + } +] \ No newline at end of file diff --git a/backend/unittests/import_observations/services/__init__.py b/backend/unittests/import_observations/services/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/unittests/import_observations/services/test_import_observations.py b/backend/unittests/import_observations/services/test_import_observations.py new file mode 100644 index 000000000..cd4f1ca58 --- /dev/null +++ b/backend/unittests/import_observations/services/test_import_observations.py @@ -0,0 +1,274 @@ +from unittest.mock import call, patch + +from django.core.files.base import File +from django.core.management import call_command + +from application.access_control.models import User +from application.core.models import ( + Branch, + Evidence, + Observation, + Observation_Log, + Parser, + Product, + Reference, +) +from application.import_observations.apps import _register_parser +from application.import_observations.models import Vulnerability_Check +from application.import_observations.services.import_observations import ( + FileUploadParameters, + file_upload_observations, +) +from application.rules.models import Rule +from unittests.base_test_case import BaseTestCase + + +class TestImportObservations(BaseTestCase): + def setUp(self): + Observation.objects.all().delete() + Observation_Log.objects.all().delete() + Rule.objects.all().delete() + Vulnerability_Check.objects.all().delete() + call_command("loaddata", "unittests/fixtures/import_observations_fixtures.json") + _register_parser("sarif") + super().setUp() + + @patch("application.commons.services.global_request.get_current_request") + @patch( + "application.import_observations.services.import_observations.check_security_gate" + ) + @patch( + "application.import_observations.services.import_observations.set_repository_default_branch" + ) + @patch( + "application.import_observations.services.import_observations.push_observations_to_issue_tracker" + ) + @patch( + "application.import_observations.services.import_observations.epss_apply_observation" + ) + def test_file_upload_observations_with_branch( + self, + mock_epss_apply_observation, + mock_push_observations_to_issue_tracker, + mock_set_repository_default_branch, + mock_check_security_gate, + mock_get_current_request, + ): + mock_get_current_request.return_value = RequestMock(User.objects.get(id=1)) + + self._file_upload_observations( + Branch.objects.get(id=1), + "test_service", + "test_docker_image_name_tag", + "test_endpoint_url", + ) + + product = Product.objects.get(id=1) + mock_check_security_gate.assert_has_calls([call(product), call(product)]) + mock_set_repository_default_branch.assert_has_calls( + [call(product), call(product)] + ) + self.assertEqual(mock_push_observations_to_issue_tracker.call_count, 2) + self.assertEqual(mock_epss_apply_observation.call_count, 4) + + @patch("application.commons.services.global_request.get_current_request") + @patch( + "application.import_observations.services.import_observations.check_security_gate" + ) + @patch( + "application.import_observations.services.import_observations.set_repository_default_branch" + ) + @patch( + "application.import_observations.services.import_observations.push_observations_to_issue_tracker" + ) + @patch( + "application.import_observations.services.import_observations.epss_apply_observation" + ) + def test_file_upload_observations_without_branch( + self, + mock_epss_apply_observation, + mock_push_observations_to_issue_tracker, + mock_set_repository_default_branch, + mock_check_security_gate, + mock_get_current_request, + ): + mock_get_current_request.return_value = RequestMock(User.objects.get(id=1)) + self._file_upload_observations(None, None, None, None) + + product = Product.objects.get(id=1) + mock_check_security_gate.assert_has_calls([call(product), call(product)]) + mock_set_repository_default_branch.assert_has_calls( + [call(product), call(product)] + ) + self.assertEqual(mock_push_observations_to_issue_tracker.call_count, 2) + self.assertEqual(mock_epss_apply_observation.call_count, 4) + + def _file_upload_observations( + self, branch, service, docker_image_name_tag, endpoint_url + ): + # --- First import --- + + file_upload_parameters = FileUploadParameters( + product=Product.objects.get(id=1), + branch=branch, + parser=Parser.objects.get(id=1), + file=File(open("unittests/fixtures/data_1/bandit.sarif", "r")), + service=service, + docker_image_name_tag=docker_image_name_tag, + endpoint_url=endpoint_url, + ) + + new, updated, resolved = file_upload_observations(file_upload_parameters) + + self.assertEqual(new, 2) + self.assertEqual(updated, 0) + self.assertEqual(resolved, 0) + + product = Product.objects.get(id=1) + + observations = Observation.objects.filter(product=1).order_by("id") + self.assertEqual(len(observations), 3) + + self.assertEqual(observations[0].product, product) + self.assertEqual(observations[0].branch, branch) + if service: + self.assertEqual(observations[0].origin_service_name, service) + else: + self.assertEqual(observations[0].origin_service_name, "") + if docker_image_name_tag: + self.assertEqual( + observations[0].origin_docker_image_name_tag, docker_image_name_tag + ) + else: + self.assertEqual(observations[0].origin_docker_image_name_tag, "") + if endpoint_url: + self.assertEqual(observations[0].origin_endpoint_url, endpoint_url) + else: + self.assertEqual(observations[0].origin_endpoint_url, "") + + self.assertEqual(observations[0].current_status, Observation.STATUS_OPEN) + self.assertEqual(observations[1].current_status, Observation.STATUS_OPEN) + self.assertEqual( + observations[2].current_status, Observation.STATUS_NOT_AFFECTED + ) + + observation_logs = Observation_Log.objects.filter( + observation__product=1 + ).order_by("id") + self.assertEqual(len(observation_logs), 4) + + self.assertEqual(observation_logs[0].observation, observations[0]) + self.assertEqual(observation_logs[1].observation, observations[1]) + + self.assertEqual(observation_logs[2].observation, observations[2]) + self.assertEqual(observation_logs[2].severity, observations[2].current_severity) + self.assertEqual(observation_logs[2].status, Observation.STATUS_OPEN) + self.assertEqual(observation_logs[2].comment, "Set by parser") + + self.assertEqual(observation_logs[3].observation, observations[2]) + self.assertEqual(observation_logs[3].severity, "") + self.assertEqual(observation_logs[3].status, observations[2].current_status) + self.assertEqual( + observation_logs[3].comment, + "Updated by product rule db_product_rule_import", + ) + + references = Reference.objects.filter(observation__product=product).order_by( + "id" + ) + self.assertEqual(len(references), 3) + + self.assertEqual(references[0].observation, observations[0]) + self.assertEqual( + references[0].url, + "https://bandit.readthedocs.io/en/1.7.4/plugins/b104_hardcoded_bind_all_interfaces.html", + ) + + evidences = Evidence.objects.filter(observation__product=product).order_by("id") + self.assertEqual(len(evidences), 6) + + vulnerability_checks = Vulnerability_Check.objects.filter(product=1) + self.assertEqual(len(vulnerability_checks), 1) + + self.assertEqual(vulnerability_checks[0].product, product) + self.assertEqual(vulnerability_checks[0].branch, branch) + self.assertEqual(vulnerability_checks[0].filename, "bandit.sarif") + self.assertEqual(vulnerability_checks[0].api_configuration_name, "") + self.assertEqual(vulnerability_checks[0].scanner, "Bandit") + self.assertEqual(vulnerability_checks[0].last_import_observations_new, 2) + self.assertEqual(vulnerability_checks[0].last_import_observations_updated, 0) + self.assertEqual(vulnerability_checks[0].last_import_observations_resolved, 0) + + # --- Second import with some changes --- + + file_upload_parameters = FileUploadParameters( + product=Product.objects.get(id=1), + branch=branch, + parser=Parser.objects.get(id=1), + file=File(open("unittests/fixtures/data_2/bandit.sarif", "r")), + service=service, + docker_image_name_tag=docker_image_name_tag, + endpoint_url=endpoint_url, + ) + + new, updated, resolved = file_upload_observations(file_upload_parameters) + + self.assertEqual(new, 0) + self.assertEqual(updated, 1) + self.assertEqual(resolved, 1) + + observations = Observation.objects.filter(product=1).order_by("id") + self.assertEqual(len(observations), 3) + + self.assertEqual(observations[0].current_status, Observation.STATUS_RESOLVED) + self.assertEqual(observations[1].current_status, Observation.STATUS_OPEN) + self.assertEqual(observations[2].current_status, Observation.STATUS_RESOLVED) + + observation_logs = Observation_Log.objects.filter( + observation__product=1 + ).order_by("id") + self.assertEqual(len(observation_logs), 7) + + self.assertEqual(observation_logs[4].observation, observations[1]) + self.assertEqual(observation_logs[4].severity, Observation.SEVERITY_HIGH) + self.assertEqual(observation_logs[4].status, "") + self.assertEqual(observation_logs[4].comment, "Updated by parser") + + self.assertEqual(observation_logs[5].observation, observations[0]) + self.assertEqual(observation_logs[5].severity, "") + self.assertEqual(observation_logs[5].status, Observation.STATUS_RESOLVED) + self.assertEqual( + observation_logs[5].comment, "Observation not found in latest scan" + ) + + self.assertEqual(observation_logs[6].observation, observations[2]) + self.assertEqual(observation_logs[6].severity, "") + self.assertEqual(observation_logs[6].status, Observation.STATUS_RESOLVED) + self.assertEqual( + observation_logs[6].comment, "Observation not found in latest scan" + ) + + references = Reference.objects.filter(observation__product=product).order_by( + "id" + ) + self.assertEqual(len(references), 3) + + evidences = Evidence.objects.filter(observation__product=product).order_by("id") + self.assertEqual(len(evidences), 6) + + vulnerability_checks = Vulnerability_Check.objects.filter(product=1) + self.assertEqual(len(vulnerability_checks), 1) + + self.assertEqual(vulnerability_checks[0].product, product) + self.assertEqual(vulnerability_checks[0].branch, branch) + self.assertEqual(vulnerability_checks[0].filename, "bandit.sarif") + self.assertEqual(vulnerability_checks[0].api_configuration_name, "") + self.assertEqual(vulnerability_checks[0].scanner, "Bandit") + self.assertEqual(vulnerability_checks[0].last_import_observations_new, 0) + self.assertEqual(vulnerability_checks[0].last_import_observations_updated, 1) + self.assertEqual(vulnerability_checks[0].last_import_observations_resolved, 1) + + +class RequestMock: + def __init__(self, user): + self.user = user From f26e509e58c31becc5c9bd2cf20947ab6ee00401 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 1 Nov 2023 19:17:39 +0100 Subject: [PATCH 03/81] chore: new tagline (#723) --- .github/workflows/publish_docs.yml | 2 +- docs/getting_started/about.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish_docs.yml b/.github/workflows/publish_docs.yml index 97fd6867d..8ab081f0b 100644 --- a/.github/workflows/publish_docs.yml +++ b/.github/workflows/publish_docs.yml @@ -4,7 +4,7 @@ on: push: branches: - main - - feat/tfsec + - chore/doc-about permissions: contents: write diff --git a/docs/getting_started/about.md b/docs/getting_started/about.md index dafeba9f2..e09487f2e 100644 --- a/docs/getting_started/about.md +++ b/docs/getting_started/about.md @@ -1,7 +1,7 @@ # About SecObserve !!! note "SecObserve in a nutshell" - SecObserve gathers results about potential security flaws from various vulnerability scanning tools and makes them available for assessment and reporting. + SecObserve is an open source vulnerability management system for software development teams that supports a variety of open source vulnerability scanners and integrates easily into CI/CD pipelines. ![Dashboard](../assets/images/screenshot_dashboard.png) From c2d000830e3f4d3cc1932bf05f69af84cecef6f6 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 2 Nov 2023 15:35:08 +0100 Subject: [PATCH 04/81] fix: signin after oidc errors (#726) * fix: signin after oidc errors * fix: remove unnecessary line --- frontend/src/access_control/authProvider.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/access_control/authProvider.ts b/frontend/src/access_control/authProvider.ts index aa715ace7..2b34183ef 100644 --- a/frontend/src/access_control/authProvider.ts +++ b/frontend/src/access_control/authProvider.ts @@ -56,19 +56,32 @@ const authProvider: AuthProvider = { }, checkError: (error) => { if (error) { - const status = error.status; - if (status === 401 || status === 403) { + if (oidc_signed_in()) { + if (window.__RUNTIME_CONFIG__.OIDC_ENABLE == "true") { + const user_manager = new UserManager(oidcConfig); + return user_manager.signinRedirect(); + } return Promise.reject({ message: error.message }); } } return Promise.resolve(); }, checkAuth: () => { + // if (window.__RUNTIME_CONFIG__.OIDC_ENABLE == "true") { + // const user_manager = new UserManager(oidcConfig); + // const user = await user_manager.getUser(); + // if (user && !user.expired) { + // console.log("user_manager.getUser() OK") + // return Promise.resolve(); + // } else { + // console.log("user_manager.getUser() not OK") + // return user_manager.signinRedirect(); + // } + // } if (oidc_signed_in() || jwt_signed_in()) { return Promise.resolve(); - } else { - return Promise.reject({ message: false }); } + return Promise.reject({ message: false }); }, getPermissions: () => Promise.reject(), getIdentity: async () => { From 97678588f966bfcf25dbcd46aa9747a106694dab Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Thu, 2 Nov 2023 18:35:26 +0100 Subject: [PATCH 05/81] fix: formatting of multiline SARIF code snippets (#727) * fix: formatting of multiline SARIF code snippets * fix: code quality * fix: unittest --- backend/application/core/services/observation.py | 8 ++++++++ .../import_observations/parsers/sarif/parser.py | 7 +++++-- .../import_observations/parsers/sarif/test_parser.py | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/backend/application/core/services/observation.py b/backend/application/core/services/observation.py index 763c9e8cf..03522fd96 100644 --- a/backend/application/core/services/observation.py +++ b/backend/application/core/services/observation.py @@ -304,3 +304,11 @@ def clip_fields(model: str, my_object) -> None: value = getattr(my_object, field.name) if value and len(value) > max_length: setattr(my_object, field.name, value[: max_length - 4] + " ...") + value = getattr(my_object, field.name) + if value.count("```") == 1: + # There is an open code block, that we have to close + setattr( + my_object, + field.name, + value[: max_length - 9] + "\n```\n\n...", + ) diff --git a/backend/application/import_observations/parsers/sarif/parser.py b/backend/application/import_observations/parsers/sarif/parser.py index 80fc1e2c8..1055c2dce 100644 --- a/backend/application/import_observations/parsers/sarif/parser.py +++ b/backend/application/import_observations/parsers/sarif/parser.py @@ -240,7 +240,7 @@ def get_parser_severity( return parser_severity - def get_description( + def get_description( # pylint: disable=too-many-branches self, sarif_snippet: Optional[str], sarif_rule: Rule, @@ -283,7 +283,10 @@ def get_description( # Newlines at the end of the description are removed while sarif_snippet.endswith("\n"): sarif_snippet = sarif_snippet[:-1] - description += f"**Snippet:** ```{sarif_snippet}```\n\n" + if "\n" in sarif_snippet: + description += f"**Snippet:**\n\n```\n\n{sarif_snippet}\n```\n\n" + else: + description += f"**Snippet:** `{sarif_snippet}`\n\n" sarif_properties = result.get("properties", {}) if sarif_properties and isinstance(sarif_properties, dict): diff --git a/backend/unittests/import_observations/parsers/sarif/test_parser.py b/backend/unittests/import_observations/parsers/sarif/test_parser.py index d2dfb946c..a1ae6cf45 100644 --- a/backend/unittests/import_observations/parsers/sarif/test_parser.py +++ b/backend/unittests/import_observations/parsers/sarif/test_parser.py @@ -136,7 +136,7 @@ def test_bandit(self): self.assertEqual("hardcoded_bind_all_interfaces", observation.title) description = """Possible binding to all interfaces. -**Snippet:** ```ALLOWED_HOSTS = env("ALLOWED_HOSTS", default=["localhost", "0.0.0.0", "127.0.0.1"])``` +**Snippet:** `ALLOWED_HOSTS = env("ALLOWED_HOSTS", default=["localhost", "0.0.0.0", "127.0.0.1"])` **Issue_Confidence:** MEDIUM From 1d2f067e93218873aa8033fae438a32a7e1b183e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:58:41 +0100 Subject: [PATCH 06/81] chore(deps): update dependency @types/node to v20.8.10 (#688) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- end_to_end_tests/package-lock.json | 8 ++++---- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index 104ae4089..170b490a4 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.1", "devDependencies": { "@playwright/test": "1.39.0", - "@types/node": "20.8.9" + "@types/node": "20.8.10" } }, "node_modules/@playwright/test": { @@ -28,9 +28,9 @@ } }, "node_modules/@types/node": { - "version": "20.8.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", - "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index 214a6ccb9..038690a0a 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -9,6 +9,6 @@ "author": "", "devDependencies": { "@playwright/test": "1.39.0", - "@types/node": "20.8.9" + "@types/node": "20.8.10" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 20d542fa2..7ccc898a5 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -42,7 +42,7 @@ "@microsoft/eslint-formatter-sarif": "3.0.0", "@trivago/prettier-plugin-sort-imports": "4.2.1", "@types/jest": "29.5.6", - "@types/node": "20.8.9", + "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.33", "@types/react-dom": "18.2.14", @@ -2271,9 +2271,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", - "integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==", + "version": "20.8.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", + "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/frontend/package.json b/frontend/package.json index be7c876ff..0f8bfcaab 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -48,7 +48,7 @@ ], "devDependencies": { "@types/jest": "29.5.6", - "@types/node": "20.8.9", + "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.33", "@types/react-dom": "18.2.14", From baaa60a84cb1e1c652125b5506ad09ea3cc6961a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:59:04 +0100 Subject: [PATCH 07/81] chore(deps): update typescript-eslint monorepo to v6.9.1 (#712) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 88 +++++++++++++++++++------------------- frontend/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7ccc898a5..d1e1f0db6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -46,8 +46,8 @@ "@types/prop-types": "15.7.9", "@types/react": "18.2.33", "@types/react-dom": "18.2.14", - "@typescript-eslint/eslint-plugin": "6.9.0", - "@typescript-eslint/parser": "6.9.0", + "@typescript-eslint/eslint-plugin": "6.9.1", + "@typescript-eslint/parser": "6.9.1", "@vitejs/plugin-react": "4.1.0", "eslint": "8.52.0", "eslint-plugin-react": "7.33.2", @@ -2373,16 +2373,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz", - "integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz", + "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/type-utils": "6.9.0", - "@typescript-eslint/utils": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/type-utils": "6.9.1", + "@typescript-eslint/utils": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2408,15 +2408,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.0.tgz", - "integrity": "sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz", + "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", "debug": "^4.3.4" }, "engines": { @@ -2436,13 +2436,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz", - "integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz", + "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0" + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2453,13 +2453,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz", - "integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz", + "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.0", - "@typescript-eslint/utils": "6.9.0", + "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/utils": "6.9.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2480,9 +2480,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz", - "integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz", + "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2493,13 +2493,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz", - "integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz", + "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/visitor-keys": "6.9.0", + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/visitor-keys": "6.9.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2520,17 +2520,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz", - "integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz", + "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.0", - "@typescript-eslint/types": "6.9.0", - "@typescript-eslint/typescript-estree": "6.9.0", + "@typescript-eslint/scope-manager": "6.9.1", + "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/typescript-estree": "6.9.1", "semver": "^7.5.4" }, "engines": { @@ -2545,12 +2545,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz", - "integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz", + "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.0", + "@typescript-eslint/types": "6.9.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/frontend/package.json b/frontend/package.json index 0f8bfcaab..26a556fda 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@types/react-dom": "18.2.14", "rewire": "7.0.0", "typescript": "5.2.2", - "@typescript-eslint/eslint-plugin": "6.9.0", - "@typescript-eslint/parser": "6.9.0", + "@typescript-eslint/eslint-plugin": "6.9.1", + "@typescript-eslint/parser": "6.9.1", "eslint": "8.52.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-security": "1.7.1", From 58f7e895c6d9afada60f5bb7910b6fc144726e19 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:59:34 +0100 Subject: [PATCH 08/81] fix(deps): update material-ui monorepo to v5.14.16 (#714) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 86 +++++++++++++++++++------------------- frontend/package.json | 4 +- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d1e1f0db6..b92622787 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,8 +14,8 @@ "@fortawesome/free-brands-svg-icons": "6.4.2", "@fortawesome/free-solid-svg-icons": "6.4.2", "@fortawesome/react-fontawesome": "0.2.0", - "@mui/icons-material": "5.14.15", - "@mui/material": "5.14.15", + "@mui/icons-material": "5.14.16", + "@mui/material": "5.14.16", "@textea/json-viewer": "3.2.2", "@types/inflection": "1.13.1", "@types/recharts": "1.8.26", @@ -1338,14 +1338,14 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.21", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.21.tgz", - "integrity": "sha512-eTKWx3WV/nwmRUK4z4K1MzlMyWCsi3WJ3RtV4DiXZeRh4qd4JCyp1Zzzi8Wv9xM4dEBmqQntFoei716PzwmFfA==", + "version": "5.0.0-beta.22", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.22.tgz", + "integrity": "sha512-l4asGID5tmyerx9emJfXOKLyXzaBtdXNIFE3M+IrSZaFtGFvaQKHhc3+nxxSxPf1+G44psjczM0ekRQCdXx9HA==", "dependencies": { "@babel/runtime": "^7.23.2", "@floating-ui/react-dom": "^2.0.2", - "@mui/types": "^7.2.7", - "@mui/utils": "^5.14.15", + "@mui/types": "^7.2.8", + "@mui/utils": "^5.14.16", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", "prop-types": "^15.8.1" @@ -1369,18 +1369,18 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.15.tgz", - "integrity": "sha512-ZCDzBWtCKjAYAlKKM3PA/jG/3uVIDT9ZitOtVixIVmTCQyc5jSV1qhJX8+qIGz4RQZ9KLzPWO2tXd0O5hvzouQ==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.16.tgz", + "integrity": "sha512-97isBjzH2v1K7oB4UH2f4NOkBShOynY6dhnoR2XlUk/g6bb7ZBv2I3D1hvvqPtpEigKu93e7f/jAYr5d9LOc5w==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" } }, "node_modules/@mui/icons-material": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.15.tgz", - "integrity": "sha512-Dqu21vN/mVNzebJ+ofnKG+CeJYIhHuDs5+0fMEpdpzRt6UojelzdrEkNv+XkO0e1JMclzeXIRx404FirK/CFRw==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.16.tgz", + "integrity": "sha512-wmOgslMEGvbHZjFLru8uH5E+pif/ciXAvKNw16q6joK6EWVWU5rDYWFknDaZhCvz8ZE/K8ZnJQ+lMG6GgHzXbg==", "dependencies": { "@babel/runtime": "^7.23.2" }, @@ -1403,17 +1403,17 @@ } }, "node_modules/@mui/material": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.15.tgz", - "integrity": "sha512-Gq65rHjvLzkxmhG8bvag851Oqsmru7qkUb/cCI2xu7dQzmY345f9xJRJi72sRGjhaqHXWeRKw/yIwp/7oQoeXg==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.16.tgz", + "integrity": "sha512-W4zZ4vnxgGk6/HqBwgsDHKU7x2l2NhX+r8gAwfg58Rhu3ikfY7NkIS6y8Gl3NkATc4GG1FNaGjjpQKfJx3U6Jw==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/base": "5.0.0-beta.21", - "@mui/core-downloads-tracker": "^5.14.15", - "@mui/system": "^5.14.15", - "@mui/types": "^7.2.7", - "@mui/utils": "^5.14.15", - "@types/react-transition-group": "^4.4.7", + "@mui/base": "5.0.0-beta.22", + "@mui/core-downloads-tracker": "^5.14.16", + "@mui/system": "^5.14.16", + "@mui/types": "^7.2.8", + "@mui/utils": "^5.14.16", + "@types/react-transition-group": "^4.4.8", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1", @@ -1447,12 +1447,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.15.tgz", - "integrity": "sha512-V2Xh+Tu6A07NoSpup0P9m29GwvNMYl5DegsGWqlOTJyAV7cuuVjmVPqxgvL8xBng4R85xqIQJRMjtYYktoPNuQ==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.16.tgz", + "integrity": "sha512-FNlL0pTSEBh8nXsVWreCHDSHk+jG8cBx1sxRbT8JVtL+PYbYPi802zfV4B00Kkf0LNRVRvAVQwojMWSR/MYGng==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/utils": "^5.14.15", + "@mui/utils": "^5.14.16", "prop-types": "^15.8.1" }, "engines": { @@ -1473,9 +1473,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.15.tgz", - "integrity": "sha512-mbOjRf867BysNpexe5Z/P8s3bWzDPNowmKhi7gtNDP/LPEeqAfiDSuC4WPTXmtvse1dCl30Nl755OLUYuoi7Mw==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.16.tgz", + "integrity": "sha512-FfvYvTG/Zd+KXMMImbcMYEeQAbONGuX5Vx3gBmmtB6KyA7Mvm9Pma1ly3R0gc44yeoFd+2wBjn1feS8h42HW5w==", "dependencies": { "@babel/runtime": "^7.23.2", "@emotion/cache": "^11.11.0", @@ -1504,15 +1504,15 @@ } }, "node_modules/@mui/system": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.15.tgz", - "integrity": "sha512-zr0Gdk1RgKiEk+tCMB900LaOpEC8NaGvxtkmMdL/CXgkqQZSVZOt2PQsxJWaw7kE4YVkIe4VukFVc43qcq9u3w==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.16.tgz", + "integrity": "sha512-uKnPfsDqDs8bbN54TviAuoGWOmFiQLwNZ3Wvj+OBkJCzwA6QnLb/sSeCB7Pk3ilH4h4jQ0BHtbR+Xpjy9wlOuA==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/private-theming": "^5.14.15", - "@mui/styled-engine": "^5.14.15", - "@mui/types": "^7.2.7", - "@mui/utils": "^5.14.15", + "@mui/private-theming": "^5.14.16", + "@mui/styled-engine": "^5.14.16", + "@mui/types": "^7.2.8", + "@mui/utils": "^5.14.16", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1543,9 +1543,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.7", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.7.tgz", - "integrity": "sha512-sofpWmcBqOlTzRbr1cLQuUDKaUYVZTw8ENQrtL39TECRNENEzwgnNPh6WMfqMZlMvf1Aj9DLg74XPjnLr0izUQ==", + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.8.tgz", + "integrity": "sha512-9u0ji+xspl96WPqvrYJF/iO+1tQ1L5GTaDOeG3vCR893yy7VcWwRNiVMmPdPNpMDqx0WV1wtEW9OMwK9acWJzQ==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0" }, @@ -1556,12 +1556,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.15", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.15.tgz", - "integrity": "sha512-QBfHovAvTa0J1jXuYDaXGk+Yyp7+Fm8GSqx6nK2JbezGqzCFfirNdop/+bL9Flh/OQ/64PeXcW4HGDdOge+n3A==", + "version": "5.14.16", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.16.tgz", + "integrity": "sha512-3xV31GposHkwRbQzwJJuooWpK2ybWdEdeUPtRjv/6vjomyi97F3+68l+QVj9tPTvmfSbr2sx5c/NuvDulrdRmA==", "dependencies": { "@babel/runtime": "^7.23.2", - "@types/prop-types": "^15.7.8", + "@types/prop-types": "^15.7.9", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, diff --git a/frontend/package.json b/frontend/package.json index 26a556fda..ef9f48502 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,8 +3,8 @@ "version": "1.0.1", "private": true, "dependencies": { - "@mui/icons-material": "5.14.15", - "@mui/material": "5.14.15", + "@mui/icons-material": "5.14.16", + "@mui/material": "5.14.16", "@types/inflection": "1.13.1", "@types/recharts": "1.8.26", "prop-types": "15.8.1", From 3a222f5e8746c53a8c6b6a977805bc71016c1fc5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:59:51 +0100 Subject: [PATCH 09/81] fix(deps): update react-router monorepo to v6.18.0 (#716) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 28 ++++++++++++++-------------- frontend/package.json | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b92622787..db1bb374f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -33,8 +33,8 @@ "react-chartjs-2": "5.2.0", "react-dom": "18.2.0", "react-oidc-context": "2.3.1", - "react-router": "6.17.0", - "react-router-dom": "6.17.0", + "react-router": "6.18.0", + "react-router-dom": "6.18.0", "runtime-env-cra": "0.2.4", "tss-react": "4.9.3" }, @@ -1660,9 +1660,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.10.0.tgz", - "integrity": "sha512-Lm+fYpMfZoEucJ7cMxgt4dYt8jLfbpwRCzAjm9UgSLOkmlqo9gupxt6YX3DY0Fk155NT9l17d/ydi+964uS9Lw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.11.0.tgz", + "integrity": "sha512-BHdhcWgeiudl91HvVa2wxqZjSHbheSgIiDvxrF1VjFzBzpTtuDPkOdOi3Iqvc08kXtFkLjhbS+ML9aM8mJS+wQ==", "engines": { "node": ">=14.0.0" } @@ -6439,11 +6439,11 @@ } }, "node_modules/react-router": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.17.0.tgz", - "integrity": "sha512-YJR3OTJzi3zhqeJYADHANCGPUu9J+6fT5GLv82UWRGSxu6oJYCKVmxUcaBQuGm9udpWmPsvpme/CdHumqgsoaA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.18.0.tgz", + "integrity": "sha512-vk2y7Dsy8wI02eRRaRmOs9g2o+aE72YCx5q9VasT1N9v+lrdB79tIqrjMfByHiY5+6aYkH2rUa5X839nwWGPDg==", "dependencies": { - "@remix-run/router": "1.10.0" + "@remix-run/router": "1.11.0" }, "engines": { "node": ">=14.0.0" @@ -6453,12 +6453,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.17.0.tgz", - "integrity": "sha512-qWHkkbXQX+6li0COUUPKAUkxjNNqPJuiBd27dVwQGDNsuFBdMbrS6UZ0CLYc4CsbdLYTckn4oB4tGDuPZpPhaQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.18.0.tgz", + "integrity": "sha512-Ubrue4+Ercc/BoDkFQfc6og5zRQ4A8YxSO3Knsne+eRbZ+IepAsK249XBH/XaFuOYOYr3L3r13CXTLvYt5JDjw==", "dependencies": { - "@remix-run/router": "1.10.0", - "react-router": "6.17.0" + "@remix-run/router": "1.11.0", + "react-router": "6.18.0" }, "engines": { "node": ">=14.0.0" diff --git a/frontend/package.json b/frontend/package.json index ef9f48502..0bcf3a5a2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,8 +15,8 @@ "ra-language-english": "4.15.2", "react": "18.2.0", "react-dom": "18.2.0", - "react-router": "6.17.0", - "react-router-dom": "6.17.0", + "react-router": "6.18.0", + "react-router-dom": "6.18.0", "tss-react": "4.9.3", "chart.js": "4.4.0", "react-chartjs-2": "5.2.0", From 54a6de6e05bb43a3ac1a1e1b930d93d26ed7acf7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:00:09 +0100 Subject: [PATCH 10/81] chore(deps): update dependency django to v4.2.7 (#721) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- backend/requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/requirements/base.txt b/backend/requirements/base.txt index 82fd4ed54..2021fda0d 100644 --- a/backend/requirements/base.txt +++ b/backend/requirements/base.txt @@ -3,7 +3,7 @@ whitenoise==6.6.0 # https://github.com/evansd/whitenoise # Django # ------------------------------------------------------------------------------ -django==4.2.6 # https://www.djangoproject.com/ +django==4.2.7 # https://www.djangoproject.com/ django-environ==0.11.2 # https://github.com/joke2k/django-environ django-model-utils==4.3.1 # https://github.com/jazzband/django-model-utils django-filter==23.3 # https://github.com/carltongibson/django-filter From 5880a9324986081c1d9486d9ce7e323394ed90ce Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:00:25 +0100 Subject: [PATCH 11/81] chore(deps): update dependency @types/react to v18.2.34 (#724) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index db1bb374f..bc1173528 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,7 +44,7 @@ "@types/jest": "29.5.6", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", - "@types/react": "18.2.33", + "@types/react": "18.2.34", "@types/react-dom": "18.2.14", "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", @@ -2300,9 +2300,9 @@ "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" }, "node_modules/@types/react": { - "version": "18.2.33", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz", - "integrity": "sha512-v+I7S+hu3PIBoVkKGpSYYpiBT1ijqEzWpzQD62/jm4K74hPpSP7FF9BnKG6+fg2+62weJYkkBWDJlZt5JO/9hg==", + "version": "18.2.34", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.34.tgz", + "integrity": "sha512-U6eW/alrRk37FU/MS2RYMjx0Va2JGIVXELTODaTIYgvWGCV4Y4TfTUzG8DdmpDNIT0Xpj/R7GfyHOJJrDttcvg==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", diff --git a/frontend/package.json b/frontend/package.json index 0bcf3a5a2..7cb4153e5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -50,7 +50,7 @@ "@types/jest": "29.5.6", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", - "@types/react": "18.2.33", + "@types/react": "18.2.34", "@types/react-dom": "18.2.14", "rewire": "7.0.0", "typescript": "5.2.2", From f0e8695030308cd37b4f210e2b4e88cacbb9eb2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:04:29 +0100 Subject: [PATCH 12/81] chore(deps): update dependency @types/jest to v29.5.7 (#713) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bc1173528..65765f70c 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -41,7 +41,7 @@ "devDependencies": { "@microsoft/eslint-formatter-sarif": "3.0.0", "@trivago/prettier-plugin-sort-imports": "4.2.1", - "@types/jest": "29.5.6", + "@types/jest": "29.5.7", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.34", @@ -2255,9 +2255,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.6", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", - "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", + "version": "29.5.7", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", + "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", "dev": true, "dependencies": { "expect": "^29.0.0", diff --git a/frontend/package.json b/frontend/package.json index 7cb4153e5..26f53a3ef 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -47,7 +47,7 @@ "not op_mini all" ], "devDependencies": { - "@types/jest": "29.5.6", + "@types/jest": "29.5.7", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.34", From 92aa88242882ac32045cc7f6951f2def8ec505a5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 08:04:49 +0100 Subject: [PATCH 13/81] chore(deps): update dependency @vitejs/plugin-react to v4.1.1 (#725) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 12 ++++++------ frontend/package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 65765f70c..3fe824dc8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -48,7 +48,7 @@ "@types/react-dom": "18.2.14", "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", - "@vitejs/plugin-react": "4.1.0", + "@vitejs/plugin-react": "4.1.1", "eslint": "8.52.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", @@ -2568,15 +2568,15 @@ "dev": true }, "node_modules/@vitejs/plugin-react": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.0.tgz", - "integrity": "sha512-rM0SqazU9iqPUraQ2JlIvReeaxOoRj6n+PzB1C0cBzIbd8qP336nC39/R9yPi3wVcah7E7j/kdU1uCUqMEU4OQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz", + "integrity": "sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==", "dev": true, "dependencies": { - "@babel/core": "^7.22.20", + "@babel/core": "^7.23.2", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", - "@types/babel__core": "^7.20.2", + "@types/babel__core": "^7.20.3", "react-refresh": "^0.14.0" }, "engines": { diff --git a/frontend/package.json b/frontend/package.json index 26f53a3ef..e96e6757e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -64,6 +64,6 @@ "prettier": "3.0.3", "@trivago/prettier-plugin-sort-imports": "4.2.1", "vite": "4.5.0", - "@vitejs/plugin-react": "4.1.0" + "@vitejs/plugin-react": "4.1.1" } } From 1b150acb8cadd322959e17610a88ecee45caf418 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:07:56 +0100 Subject: [PATCH 14/81] fix(deps): update react-admin monorepo to v4.15.3 (#729) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3fe824dc8..c4fa22272 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,10 +26,10 @@ "prop-types": "15.8.1", "query-string": "8.1.0", "ra-i18n-polyglot": "4.15.2", - "ra-input-rich-text": "4.15.2", + "ra-input-rich-text": "4.15.3", "ra-language-english": "4.15.2", "react": "18.2.0", - "react-admin": "4.15.2", + "react-admin": "4.15.3", "react-chartjs-2": "5.2.0", "react-dom": "18.2.0", "react-oidc-context": "2.3.1", @@ -6162,9 +6162,9 @@ } }, "node_modules/ra-input-rich-text": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/ra-input-rich-text/-/ra-input-rich-text-4.15.2.tgz", - "integrity": "sha512-fbe/sJwC5XB69B1raPyke4hmJOiurJwqku73AczXbIU6lzI6NvwsHyEaZjzHb1L+VpEDRu5gn8pQvjDwE9XsVw==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/ra-input-rich-text/-/ra-input-rich-text-4.15.3.tgz", + "integrity": "sha512-SHFrFpRPv3QdWA7hrQFz4e06gGQgFpfb4pAMg0sw1hryCuPr92+Fysrmvtgisg3sZ9NVleOV0uZewd2qHA0rDA==", "dependencies": { "@tiptap/core": "^2.0.3", "@tiptap/extension-color": "^2.0.3", @@ -6206,9 +6206,9 @@ } }, "node_modules/ra-ui-materialui": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/ra-ui-materialui/-/ra-ui-materialui-4.15.2.tgz", - "integrity": "sha512-RhWL/46yGVyOAu7QZ23wyiQhWBqDtACSpWeHRdT8MR3daCiKeWdGuhR0a53LY/ccdp2lVmO7ogQWaulszxwtJg==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/ra-ui-materialui/-/ra-ui-materialui-4.15.3.tgz", + "integrity": "sha512-QSqGb/2Xg23w5sj1/sXhF85Dq76Vnv1qWSdfMur5YPcc4ApoxHb8YTAGOolcl6Z09kfvtR5J0UXUyyFVLdgPSQ==", "dependencies": { "autosuggest-highlight": "^3.1.1", "clsx": "^1.1.1", @@ -6298,9 +6298,9 @@ } }, "node_modules/react-admin": { - "version": "4.15.2", - "resolved": "https://registry.npmjs.org/react-admin/-/react-admin-4.15.2.tgz", - "integrity": "sha512-J8dM5h2+eXOGCCWezFowVzMrS41XYh/T6mD4aK5NmGU35NUpDuvDRoVbbwUval7j15FxOXWfHlBsTnXBq3oamw==", + "version": "4.15.3", + "resolved": "https://registry.npmjs.org/react-admin/-/react-admin-4.15.3.tgz", + "integrity": "sha512-udhb+MzTcwW5TQjCkyUIOEQASHiT4XlkYm+6PjetO3oRLiL8GqqZlYDKUDF3lhWTvFRSmN7xpHvGRIPUyf9qgg==", "dependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", @@ -6310,7 +6310,7 @@ "ra-core": "^4.15.2", "ra-i18n-polyglot": "^4.15.2", "ra-language-english": "^4.15.2", - "ra-ui-materialui": "^4.15.2", + "ra-ui-materialui": "^4.15.3", "react-hook-form": "^7.43.9", "react-router": "^6.1.0", "react-router-dom": "^6.1.0" diff --git a/frontend/package.json b/frontend/package.json index e96e6757e..fdee39f96 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,9 +9,9 @@ "@types/recharts": "1.8.26", "prop-types": "15.8.1", "query-string": "8.1.0", - "react-admin": "4.15.2", + "react-admin": "4.15.3", "ra-i18n-polyglot": "4.15.2", - "ra-input-rich-text": "4.15.2", + "ra-input-rich-text": "4.15.3", "ra-language-english": "4.15.2", "react": "18.2.0", "react-dom": "18.2.0", From 32eb0d2f374a4afd316d1dc5e982d5034625e475 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:08:22 +0100 Subject: [PATCH 15/81] chore(deps): update dependency flake8-isort to v6.1.1 (#728) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- backend/requirements/dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/requirements/dev.txt b/backend/requirements/dev.txt index f7efa2a74..ff2077e76 100644 --- a/backend/requirements/dev.txt +++ b/backend/requirements/dev.txt @@ -7,7 +7,7 @@ watchgod==0.8.2 # https://github.com/samuelcolvin/watchgod # Code quality # ------------------------------------------------------------------------------ flake8==6.1.0 # https://github.com/PyCQA/flake8 -flake8-isort==6.1.0 # https://github.com/gforcada/flake8-isort +flake8-isort==6.1.1 # https://github.com/gforcada/flake8-isort black==23.10.1 # https://github.com/psf/black pylint-django==2.5.5 # https://github.com/PyCQA/pylint-django pre-commit==3.5.0 # https://github.com/pre-commit/pre-commit From 91981589f50787ff8c68e69b49b7ff290d64b0f1 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Sat, 4 Nov 2023 17:28:45 +0100 Subject: [PATCH 16/81] fix: editing of branches was not possible (#730) --- .../src/core/branches/BranchEmbeddedList.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/core/branches/BranchEmbeddedList.tsx b/frontend/src/core/branches/BranchEmbeddedList.tsx index 3c8e9b4da..7090c21db 100644 --- a/frontend/src/core/branches/BranchEmbeddedList.tsx +++ b/frontend/src/core/branches/BranchEmbeddedList.tsx @@ -5,13 +5,13 @@ import { DateField, ListContextProvider, Pagination, - TextField, WithRecord, useListController, } from "react-admin"; import { PERMISSION_BRANCH_DELETE, PERMISSION_BRANCH_EDIT } from "../../access_control/types"; import ObservationsCountField from "../../commons/custom_fields/ObservationsCountField"; +import TextUrlField from "../../commons/custom_fields/TextUrlField"; import BranchDelete from "./BranchDelete"; import BranchEdit from "./BranchEdit"; @@ -37,21 +37,21 @@ const BranchEmbeddedList = ({ product }: BranchEmbeddedListProps) => { listContext.data = []; } - function get_observations_url(record: any): string { - return `../observations?displayedFilters=%7B%7D&filter=%7B%22current_status%22%3A%22Open%22%2C%22branch%22%3A${record.id}%7D&order=ASC&sort=current_severity`; + function get_observations_url(product_id: number, branch_id: number): string { + return `#/products/${product_id}/show/observations?displayedFilters=%7B%7D&filter=%7B%22current_status%22%3A%22Open%22%2C%22branch%22%3A${branch_id}%7D&order=ASC&sort=current_severity`; } return (
- get_observations_url(record)} - > - + + ( + + )} + /> From c74f1c4b514dd71d7296e3cc8edc4852c1803dfb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 4 Nov 2023 17:29:53 +0100 Subject: [PATCH 17/81] chore(deps): update dependency eslint to v8.53.0 (#731) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c4fa22272..464c81762 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -49,7 +49,7 @@ "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", "@vitejs/plugin-react": "4.1.1", - "eslint": "8.52.0", + "eslint": "8.53.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-security": "1.7.1", @@ -976,9 +976,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1026,9 +1026,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", + "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3484,15 +3484,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", + "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.53.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", diff --git a/frontend/package.json b/frontend/package.json index fdee39f96..a1eb0ba7e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -56,7 +56,7 @@ "typescript": "5.2.2", "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", - "eslint": "8.52.0", + "eslint": "8.53.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-security": "1.7.1", "eslint-plugin-react-hooks": "4.6.0", From 2f34d96693a55f2862e444f1977cbc84c91775be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 4 Nov 2023 17:45:14 +0100 Subject: [PATCH 18/81] fix(deps): update dependency @textea/json-viewer to v3.2.3 (#732) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 464c81762..066f7e85f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,7 +16,7 @@ "@fortawesome/react-fontawesome": "0.2.0", "@mui/icons-material": "5.14.16", "@mui/material": "5.14.16", - "@textea/json-viewer": "3.2.2", + "@textea/json-viewer": "3.2.3", "@types/inflection": "1.13.1", "@types/recharts": "1.8.26", "axios": "1.6.0", @@ -1674,9 +1674,9 @@ "dev": true }, "node_modules/@textea/json-viewer": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-3.2.2.tgz", - "integrity": "sha512-CnAuqAvfIB2HBqjceSIsmJ6JNKP6FDEB40lKEC+4d0P8BnWZu0U9PQshL3vY14pwMiU6uBRIgPRlCT4WH7xnMg==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-3.2.3.tgz", + "integrity": "sha512-9fG/JU/wSzib2Naxna+J1PktIKG+9TWOB5ycphKwSSUwrid/d6wAMQYGCCAKmYt0qQq+EQ1jDuFjx7qzfm+cmg==", "dependencies": { "clsx": "^2.0.0", "copy-to-clipboard": "^3.3.3", diff --git a/frontend/package.json b/frontend/package.json index a1eb0ba7e..22baf2a7d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,7 +26,7 @@ "@fortawesome/free-brands-svg-icons": "6.4.2", "@fortawesome/react-fontawesome": "0.2.0", "axios": "1.6.0", - "@textea/json-viewer": "3.2.2", + "@textea/json-viewer": "3.2.3", "@emotion/react": "11.11.1", "@emotion/styled": "11.11.0", "runtime-env-cra": "0.2.4", From 432ac4c95bb0d764acf9bb48c97bf3bd2755c42c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:52:19 +0100 Subject: [PATCH 19/81] chore(deps): update react monorepo (#733) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 066f7e85f..540a09d1a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,8 +44,8 @@ "@types/jest": "29.5.7", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", - "@types/react": "18.2.34", - "@types/react-dom": "18.2.14", + "@types/react": "18.2.37", + "@types/react-dom": "18.2.15", "@typescript-eslint/eslint-plugin": "6.9.1", "@typescript-eslint/parser": "6.9.1", "@vitejs/plugin-react": "4.1.1", @@ -2300,9 +2300,9 @@ "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" }, "node_modules/@types/react": { - "version": "18.2.34", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.34.tgz", - "integrity": "sha512-U6eW/alrRk37FU/MS2RYMjx0Va2JGIVXELTODaTIYgvWGCV4Y4TfTUzG8DdmpDNIT0Xpj/R7GfyHOJJrDttcvg==", + "version": "18.2.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz", + "integrity": "sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2310,9 +2310,9 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", - "integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==", + "version": "18.2.15", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz", + "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==", "dev": true, "dependencies": { "@types/react": "*" diff --git a/frontend/package.json b/frontend/package.json index 22baf2a7d..63f0b2faa 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -50,8 +50,8 @@ "@types/jest": "29.5.7", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", - "@types/react": "18.2.34", - "@types/react-dom": "18.2.14", + "@types/react": "18.2.37", + "@types/react-dom": "18.2.15", "rewire": "7.0.0", "typescript": "5.2.2", "@typescript-eslint/eslint-plugin": "6.9.1", From b5bd39c7f0d27c0ea4822b5cb25457df034b2226 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:52:55 +0100 Subject: [PATCH 20/81] chore(deps): update dependency mkdocs-material to v9.4.8 (#734) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- mkdocs_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs_requirements.txt b/mkdocs_requirements.txt index 88094a9e2..59d90d664 100644 --- a/mkdocs_requirements.txt +++ b/mkdocs_requirements.txt @@ -1 +1 @@ -mkdocs-material==9.4.7 # https://github.com/squidfunk/mkdocs-material +mkdocs-material==9.4.8 # https://github.com/squidfunk/mkdocs-material From 128a33b4ee42f2e0c8fc81bf342d6d7cff8af9bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:53:17 +0100 Subject: [PATCH 21/81] fix(deps): update dependency @mui/material to v5.14.17 (#736) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 62 +++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 540a09d1a..4e85be6bb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,7 +15,7 @@ "@fortawesome/free-solid-svg-icons": "6.4.2", "@fortawesome/react-fontawesome": "0.2.0", "@mui/icons-material": "5.14.16", - "@mui/material": "5.14.16", + "@mui/material": "5.14.17", "@textea/json-viewer": "3.2.3", "@types/inflection": "1.13.1", "@types/recharts": "1.8.26", @@ -1338,14 +1338,14 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.22", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.22.tgz", - "integrity": "sha512-l4asGID5tmyerx9emJfXOKLyXzaBtdXNIFE3M+IrSZaFtGFvaQKHhc3+nxxSxPf1+G44psjczM0ekRQCdXx9HA==", + "version": "5.0.0-beta.23", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.23.tgz", + "integrity": "sha512-9L8SQUGAWtd/Qi7Qem26+oSSgpY7f2iQTuvcz/rsGpyZjSomMMO6lwYeQSA0CpWM7+aN7eGoSY/WV6wxJiIxXw==", "dependencies": { "@babel/runtime": "^7.23.2", "@floating-ui/react-dom": "^2.0.2", "@mui/types": "^7.2.8", - "@mui/utils": "^5.14.16", + "@mui/utils": "^5.14.17", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", "prop-types": "^15.8.1" @@ -1369,9 +1369,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.16.tgz", - "integrity": "sha512-97isBjzH2v1K7oB4UH2f4NOkBShOynY6dhnoR2XlUk/g6bb7ZBv2I3D1hvvqPtpEigKu93e7f/jAYr5d9LOc5w==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.17.tgz", + "integrity": "sha512-eE0uxrpJAEL2ZXkeGLKg8HQDafsiXY+6eNpP4lcv3yIjFfGbU6Hj9/P7Adt8jpU+6JIhmxvILGj2r27pX+zdrQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" @@ -1403,16 +1403,16 @@ } }, "node_modules/@mui/material": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.16.tgz", - "integrity": "sha512-W4zZ4vnxgGk6/HqBwgsDHKU7x2l2NhX+r8gAwfg58Rhu3ikfY7NkIS6y8Gl3NkATc4GG1FNaGjjpQKfJx3U6Jw==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.17.tgz", + "integrity": "sha512-+y0VeOLWfEA4Z98We/UH6KCo8+f2HLZDK45FY+sJf8kSojLy3VntadKtC/u0itqnXXb1Pr4wKB2tSIBW02zY4Q==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/base": "5.0.0-beta.22", - "@mui/core-downloads-tracker": "^5.14.16", - "@mui/system": "^5.14.16", + "@mui/base": "5.0.0-beta.23", + "@mui/core-downloads-tracker": "^5.14.17", + "@mui/system": "^5.14.17", "@mui/types": "^7.2.8", - "@mui/utils": "^5.14.16", + "@mui/utils": "^5.14.17", "@types/react-transition-group": "^4.4.8", "clsx": "^2.0.0", "csstype": "^3.1.2", @@ -1447,12 +1447,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.16.tgz", - "integrity": "sha512-FNlL0pTSEBh8nXsVWreCHDSHk+jG8cBx1sxRbT8JVtL+PYbYPi802zfV4B00Kkf0LNRVRvAVQwojMWSR/MYGng==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.17.tgz", + "integrity": "sha512-u4zxsCm9xmQrlhVPug+Ccrtsjv7o2+rehvrgHoh0siSguvVgVQq5O3Hh10+tp/KWQo2JR4/nCEwquSXgITS1+g==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/utils": "^5.14.16", + "@mui/utils": "^5.14.17", "prop-types": "^15.8.1" }, "engines": { @@ -1473,9 +1473,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.16.tgz", - "integrity": "sha512-FfvYvTG/Zd+KXMMImbcMYEeQAbONGuX5Vx3gBmmtB6KyA7Mvm9Pma1ly3R0gc44yeoFd+2wBjn1feS8h42HW5w==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.17.tgz", + "integrity": "sha512-AqpVjBEA7wnBvKPW168bNlqB6EN7HxTjLOY7oi275AzD/b1C7V0wqELy6NWoJb2yya5sRf7ENf4iNi3+T5cOgw==", "dependencies": { "@babel/runtime": "^7.23.2", "@emotion/cache": "^11.11.0", @@ -1504,15 +1504,15 @@ } }, "node_modules/@mui/system": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.16.tgz", - "integrity": "sha512-uKnPfsDqDs8bbN54TviAuoGWOmFiQLwNZ3Wvj+OBkJCzwA6QnLb/sSeCB7Pk3ilH4h4jQ0BHtbR+Xpjy9wlOuA==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.17.tgz", + "integrity": "sha512-Ccz3XlbCqka6DnbHfpL3o3TfOeWQPR+ewvNAgm8gnS9M0yVMmzzmY6z0w/C1eebb+7ZP7IoLUj9vojg/GBaTPg==", "dependencies": { "@babel/runtime": "^7.23.2", - "@mui/private-theming": "^5.14.16", - "@mui/styled-engine": "^5.14.16", + "@mui/private-theming": "^5.14.17", + "@mui/styled-engine": "^5.14.17", "@mui/types": "^7.2.8", - "@mui/utils": "^5.14.16", + "@mui/utils": "^5.14.17", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -1556,9 +1556,9 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.16", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.16.tgz", - "integrity": "sha512-3xV31GposHkwRbQzwJJuooWpK2ybWdEdeUPtRjv/6vjomyi97F3+68l+QVj9tPTvmfSbr2sx5c/NuvDulrdRmA==", + "version": "5.14.17", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.17.tgz", + "integrity": "sha512-yxnWgSS4J6DMFPw2Dof85yBkG02VTbEiqsikymMsnZnXDurtVGTIhlNuV24GTmFTuJMzEyTTU9UF+O7zaL8LEQ==", "dependencies": { "@babel/runtime": "^7.23.2", "@types/prop-types": "^15.7.9", diff --git a/frontend/package.json b/frontend/package.json index 63f0b2faa..521d2476d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@mui/icons-material": "5.14.16", - "@mui/material": "5.14.16", + "@mui/material": "5.14.17", "@types/inflection": "1.13.1", "@types/recharts": "1.8.26", "prop-types": "15.8.1", From 16180cbaecbe2e87c90f3c084eb096a8c7c68911 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:54:06 +0100 Subject: [PATCH 22/81] fix(deps): update dependency @types/recharts to v1.8.27 (#740) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4e85be6bb..16ed212c7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,7 +18,7 @@ "@mui/material": "5.14.17", "@textea/json-viewer": "3.2.3", "@types/inflection": "1.13.1", - "@types/recharts": "1.8.26", + "@types/recharts": "1.8.27", "axios": "1.6.0", "chart.js": "4.4.0", "markdown-to-jsx": "7.3.2", @@ -2327,9 +2327,9 @@ } }, "node_modules/@types/recharts": { - "version": "1.8.26", - "resolved": "https://registry.npmjs.org/@types/recharts/-/recharts-1.8.26.tgz", - "integrity": "sha512-aQj6sPwcklOtLl/tpbs1i33YaIQnmIZjxm5yzvV0BnzgDAp039AfuGDZOT5kochG6MyIdyIMzoSu49aBSJAqow==", + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@types/recharts/-/recharts-1.8.27.tgz", + "integrity": "sha512-FQPslOwKQacusDPowF+F6ARzwiNj9QGIckTp8duMxY+NBGs6UF1p6Wj3vXdRxHO78eae5qYB1wByEjK6kt8kXw==", "dependencies": { "@types/d3-shape": "^1", "@types/react": "*" diff --git a/frontend/package.json b/frontend/package.json index 521d2476d..d3641a8b1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,7 @@ "@mui/icons-material": "5.14.16", "@mui/material": "5.14.17", "@types/inflection": "1.13.1", - "@types/recharts": "1.8.26", + "@types/recharts": "1.8.27", "prop-types": "15.8.1", "query-string": "8.1.0", "react-admin": "4.15.3", From fa93a0373bc8a2230e2ac6283cc83429f20a4066 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:54:27 +0100 Subject: [PATCH 23/81] chore(deps): update dependency @types/jest to v29.5.8 (#741) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 16ed212c7..ec0522db2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -41,7 +41,7 @@ "devDependencies": { "@microsoft/eslint-formatter-sarif": "3.0.0", "@trivago/prettier-plugin-sort-imports": "4.2.1", - "@types/jest": "29.5.7", + "@types/jest": "29.5.8", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.37", @@ -2255,9 +2255,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", - "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", + "version": "29.5.8", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.8.tgz", + "integrity": "sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==", "dev": true, "dependencies": { "expect": "^29.0.0", diff --git a/frontend/package.json b/frontend/package.json index d3641a8b1..fcef59e3b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -47,7 +47,7 @@ "not op_mini all" ], "devDependencies": { - "@types/jest": "29.5.7", + "@types/jest": "29.5.8", "@types/node": "20.8.10", "@types/prop-types": "15.7.9", "@types/react": "18.2.37", From 93a44ddc74dad9aae93438849069fbaaea26597e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:58:27 +0100 Subject: [PATCH 24/81] chore(deps): update typescript-eslint monorepo to v6.10.0 (#737) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 106 ++++++++++++++++++------------------- frontend/package.json | 4 +- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ec0522db2..199213bb9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -46,8 +46,8 @@ "@types/prop-types": "15.7.9", "@types/react": "18.2.37", "@types/react-dom": "18.2.15", - "@typescript-eslint/eslint-plugin": "6.9.1", - "@typescript-eslint/parser": "6.9.1", + "@typescript-eslint/eslint-plugin": "6.10.0", + "@typescript-eslint/parser": "6.10.0", "@vitejs/plugin-react": "4.1.1", "eslint": "8.53.0", "eslint-plugin-react": "7.33.2", @@ -2265,9 +2265,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/node": { @@ -2341,9 +2341,9 @@ "integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==" }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, "node_modules/@types/stack-utils": { @@ -2373,16 +2373,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz", - "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz", + "integrity": "sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/type-utils": "6.9.1", - "@typescript-eslint/utils": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/type-utils": "6.10.0", + "@typescript-eslint/utils": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2408,15 +2408,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz", - "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.10.0.tgz", + "integrity": "sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4" }, "engines": { @@ -2436,13 +2436,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz", - "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz", + "integrity": "sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1" + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2453,13 +2453,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz", - "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz", + "integrity": "sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/utils": "6.9.1", + "@typescript-eslint/typescript-estree": "6.10.0", + "@typescript-eslint/utils": "6.10.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2480,9 +2480,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz", - "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.10.0.tgz", + "integrity": "sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2493,13 +2493,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz", - "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz", + "integrity": "sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/visitor-keys": "6.10.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2520,17 +2520,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz", - "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.10.0.tgz", + "integrity": "sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/scope-manager": "6.10.0", + "@typescript-eslint/types": "6.10.0", + "@typescript-eslint/typescript-estree": "6.10.0", "semver": "^7.5.4" }, "engines": { @@ -2545,12 +2545,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz", - "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz", + "integrity": "sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/types": "6.10.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3838,9 +3838,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", diff --git a/frontend/package.json b/frontend/package.json index fcef59e3b..e7c405ec7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@types/react-dom": "18.2.15", "rewire": "7.0.0", "typescript": "5.2.2", - "@typescript-eslint/eslint-plugin": "6.9.1", - "@typescript-eslint/parser": "6.9.1", + "@typescript-eslint/eslint-plugin": "6.10.0", + "@typescript-eslint/parser": "6.10.0", "eslint": "8.53.0", "eslint-plugin-react": "7.33.2", "eslint-plugin-security": "1.7.1", From 5ae831faa94384b035f76db8c02c5e1ab6ca528f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:58:44 +0100 Subject: [PATCH 25/81] chore(deps): update dependency @types/prop-types to v15.7.10 (#739) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 199213bb9..8fe676f43 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -43,7 +43,7 @@ "@trivago/prettier-plugin-sort-imports": "4.2.1", "@types/jest": "29.5.8", "@types/node": "20.8.10", - "@types/prop-types": "15.7.9", + "@types/prop-types": "15.7.10", "@types/react": "18.2.37", "@types/react-dom": "18.2.15", "@typescript-eslint/eslint-plugin": "6.10.0", @@ -2295,9 +2295,9 @@ "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==" }, "node_modules/@types/prop-types": { - "version": "15.7.9", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz", - "integrity": "sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==" + "version": "15.7.10", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz", + "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==" }, "node_modules/@types/react": { "version": "18.2.37", diff --git a/frontend/package.json b/frontend/package.json index e7c405ec7..5f3911a2b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,7 +49,7 @@ "devDependencies": { "@types/jest": "29.5.8", "@types/node": "20.8.10", - "@types/prop-types": "15.7.9", + "@types/prop-types": "15.7.10", "@types/react": "18.2.37", "@types/react-dom": "18.2.15", "rewire": "7.0.0", From 5ca371464f16b037b9cfee84172c3101990469d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 07:59:07 +0100 Subject: [PATCH 26/81] chore(deps): update dependency black to v23.11.0 (#743) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- backend/requirements/dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/requirements/dev.txt b/backend/requirements/dev.txt index ff2077e76..39bea767c 100644 --- a/backend/requirements/dev.txt +++ b/backend/requirements/dev.txt @@ -8,7 +8,7 @@ watchgod==0.8.2 # https://github.com/samuelcolvin/watchgod # ------------------------------------------------------------------------------ flake8==6.1.0 # https://github.com/PyCQA/flake8 flake8-isort==6.1.1 # https://github.com/gforcada/flake8-isort -black==23.10.1 # https://github.com/psf/black +black==23.11.0 # https://github.com/psf/black pylint-django==2.5.5 # https://github.com/PyCQA/pylint-django pre-commit==3.5.0 # https://github.com/pre-commit/pre-commit mypy==1.6.1 # https://github.com/python/mypy From c3baa831b510567fe363b54f259927c7d0d8493c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 08:04:57 +0100 Subject: [PATCH 27/81] fix(deps): update dependency @types/inflection to v1.13.2 (#738) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8fe676f43..5e4e7c2ea 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,7 @@ "@mui/icons-material": "5.14.16", "@mui/material": "5.14.17", "@textea/json-viewer": "3.2.3", - "@types/inflection": "1.13.1", + "@types/inflection": "1.13.2", "@types/recharts": "1.8.27", "axios": "1.6.0", "chart.js": "4.4.0", @@ -2226,9 +2226,9 @@ } }, "node_modules/@types/inflection": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@types/inflection/-/inflection-1.13.1.tgz", - "integrity": "sha512-iTQQWQk4oJ1BygX0ggBKOudHJHL4DmF+4vRZMU3ddHc6Cl/Mk6oo7HXnx4pn8wSY96DZolRMOvNUBuhAAwm18A==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@types/inflection/-/inflection-1.13.2.tgz", + "integrity": "sha512-VxXY8dNLrxn7nDvsud77K60uD3a9RSmKfa0k/N/zvP2G55R5/8DSO5Ferz3mQdlAo8jPnpQLilCx9rABdPHSVg==" }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.5", diff --git a/frontend/package.json b/frontend/package.json index 5f3911a2b..553c77d62 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,7 @@ "dependencies": { "@mui/icons-material": "5.14.16", "@mui/material": "5.14.17", - "@types/inflection": "1.13.1", + "@types/inflection": "1.13.2", "@types/recharts": "1.8.27", "prop-types": "15.8.1", "query-string": "8.1.0", From b5b4dbcda7f04c7bf4c7709d8017f0195ff65a66 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 08:05:23 +0100 Subject: [PATCH 28/81] chore(deps): update dependency @types/node to v20.9.0 (#742) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- end_to_end_tests/package-lock.json | 8 ++++---- end_to_end_tests/package.json | 2 +- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/end_to_end_tests/package-lock.json b/end_to_end_tests/package-lock.json index 170b490a4..db5b16ccb 100644 --- a/end_to_end_tests/package-lock.json +++ b/end_to_end_tests/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.1", "devDependencies": { "@playwright/test": "1.39.0", - "@types/node": "20.8.10" + "@types/node": "20.9.0" } }, "node_modules/@playwright/test": { @@ -28,9 +28,9 @@ } }, "node_modules/@types/node": { - "version": "20.8.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", - "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/end_to_end_tests/package.json b/end_to_end_tests/package.json index 038690a0a..8816533ed 100644 --- a/end_to_end_tests/package.json +++ b/end_to_end_tests/package.json @@ -9,6 +9,6 @@ "author": "", "devDependencies": { "@playwright/test": "1.39.0", - "@types/node": "20.8.10" + "@types/node": "20.9.0" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5e4e7c2ea..a20653d02 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -42,7 +42,7 @@ "@microsoft/eslint-formatter-sarif": "3.0.0", "@trivago/prettier-plugin-sort-imports": "4.2.1", "@types/jest": "29.5.8", - "@types/node": "20.8.10", + "@types/node": "20.9.0", "@types/prop-types": "15.7.10", "@types/react": "18.2.37", "@types/react-dom": "18.2.15", @@ -2271,9 +2271,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz", - "integrity": "sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==", + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/frontend/package.json b/frontend/package.json index 553c77d62..17f8d136a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -48,7 +48,7 @@ ], "devDependencies": { "@types/jest": "29.5.8", - "@types/node": "20.8.10", + "@types/node": "20.9.0", "@types/prop-types": "15.7.10", "@types/react": "18.2.37", "@types/react-dom": "18.2.15", From 67f681d9ed50435c32133ca0764bfff5aac95e8e Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 8 Nov 2023 10:51:43 +0100 Subject: [PATCH 29/81] feat: IaC SAST with trivy config (#744) * feat: IaC SAST with trivy config * chore: unittest --- .../parsers/sarif/parser.py | 67 +++++++++++----- .../parsers/sarif/files/trivy_config.sarif | 80 +++++++++++++++++++ .../parsers/sarif/test_parser.py | 50 +++++++++++- docs/assets/images/secobserve_process.drawio | 8 +- docs/assets/images/secobserve_process.svg | 2 +- .../github_actions_and_templates.md | 1 + docs/usage/supported_scanners.md | 1 + 7 files changed, 182 insertions(+), 27 deletions(-) create mode 100644 backend/unittests/import_observations/parsers/sarif/files/trivy_config.sarif diff --git a/backend/application/import_observations/parsers/sarif/parser.py b/backend/application/import_observations/parsers/sarif/parser.py index 1055c2dce..a694f4d82 100644 --- a/backend/application/import_observations/parsers/sarif/parser.py +++ b/backend/application/import_observations/parsers/sarif/parser.py @@ -115,11 +115,11 @@ def get_observations(self, data: dict) -> list[Observation]: def create_observation( self, - result, - observations, - sarif_scanner, - sarif_rules, - sarif_location, + result: dict, + observations: list[Observation], + sarif_scanner: str, + sarif_rules: dict[str, Rule], + sarif_location: Optional[dict], ): location = self.get_location_data(sarif_location) @@ -134,12 +134,11 @@ def create_observation( if parser_cvss3_score: parser_severity = "" - if sarif_rule.name: - title = sarif_rule.name - else: - title = sarif_rule_id + title = self.get_title(sarif_scanner, sarif_rule_id, sarif_rule) - description = self.get_description(location.snippet, sarif_rule, result) + description = self.get_description( + sarif_scanner, location.snippet, sarif_rule, title, result + ) sarif_cwe = None if sarif_rule.properties and isinstance(sarif_rule.properties, dict): @@ -193,7 +192,25 @@ def create_observation( observations.append(observation) - def get_location_data(self, sarif_location: dict) -> Location: + def get_title( + self, sarif_scanner: str, sarif_rule_id: str, sarif_rule: Rule + ) -> str: + if sarif_rule.name: + title = sarif_rule.name + else: + title = sarif_rule_id + + title = self.get_trivy_title(title, sarif_scanner, sarif_rule) + + return title + + def get_trivy_title(self, title: str, sarif_scanner: str, sarif_rule: Rule) -> str: + # Rule name and rule id of Trivy are not very descriptive + if sarif_scanner.lower().startswith("trivy") and sarif_rule.short_description: + title = sarif_rule.short_description + return title + + def get_location_data(self, sarif_location: Optional[dict]) -> Location: location = Location() if sarif_location: location.uri = ( @@ -242,19 +259,23 @@ def get_parser_severity( def get_description( # pylint: disable=too-many-branches self, + sarif_scanner: str, sarif_snippet: Optional[str], sarif_rule: Rule, + title: str, result: dict, ) -> str: description = "" sarif_message_text = result.get("message", {}).get("text") - if sarif_message_text: + if sarif_message_text and not sarif_scanner.lower().startswith("trivy"): + # Message text of Trivy has only redundant information description += f"{sarif_message_text}\n\n" if ( sarif_rule.short_description and sarif_rule.short_description not in sarif_message_text + and sarif_rule.short_description not in title ): description += ( f"**Rule short description:** {sarif_rule.short_description}\n\n" @@ -276,7 +297,9 @@ def get_description( # pylint: disable=too-many-branches sarif_rule.help and sarif_rule.help not in sarif_message_text and sarif_rule.help not in rule_short_description + and not sarif_scanner.lower().startswith("trivy") ): + # Help text of Trivy has only redundant information description += f"**Rule help:** {sarif_rule.help}\n\n" if sarif_snippet: @@ -319,7 +342,7 @@ def extract_component(self, origin_component_purl: str) -> Tuple[str, str]: return origin_component_name, origin_component_version - def get_rules(self, run: dict) -> dict: + def get_rules(self, run: dict) -> dict[str, Rule]: rules = {} sarif_rules = run.get("tool", {}).get("driver", {}).get("rules", []) @@ -383,13 +406,17 @@ def get_dependency_check_vulnerability_id( return "" def get_dependency_check_origin_component_purl( - self, sarif_scanner: str, location: dict - ): - logicalLocations = location.get("logicalLocations") - if sarif_scanner.lower().startswith("dependency-check") and logicalLocations: - fully_qualified_name = logicalLocations[0].get("fullyQualifiedName") - if fully_qualified_name and fully_qualified_name.startswith("pkg:"): - return fully_qualified_name + self, sarif_scanner: str, location: Optional[dict] + ) -> str: + if location: + logicalLocations = location.get("logicalLocations") + if ( + sarif_scanner.lower().startswith("dependency-check") + and logicalLocations + ): + fully_qualified_name = logicalLocations[0].get("fullyQualifiedName") + if fully_qualified_name and fully_qualified_name.startswith("pkg:"): + return fully_qualified_name return "" diff --git a/backend/unittests/import_observations/parsers/sarif/files/trivy_config.sarif b/backend/unittests/import_observations/parsers/sarif/files/trivy_config.sarif new file mode 100644 index 000000000..dc65bfefb --- /dev/null +++ b/backend/unittests/import_observations/parsers/sarif/files/trivy_config.sarif @@ -0,0 +1,80 @@ +{ + "version": "2.1.0", + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "tool": { + "driver": { + "fullName": "Trivy Vulnerability Scanner", + "informationUri": "https://github.com/aquasecurity/trivy", + "name": "Trivy", + "rules": [ + { + "id": "AVD-AZU-0014", + "name": "Misconfiguration", + "shortDescription": { + "text": "Ensure that the expiration date is set on all keys" + }, + "fullDescription": { + "text": "Expiration Date is an optional Key Vault Key behavior and is not set by default.\n\nSet when the resource will be become inactive." + }, + "defaultConfiguration": { + "level": "warning" + }, + "helpUri": "https://avd.aquasec.com/misconfig/avd-azu-0014", + "help": { + "text": "Misconfiguration AVD-AZU-0014\nType: Terraform Security Check\nSeverity: MEDIUM\nCheck: Ensure that the expiration date is set on all keys\nMessage: Key should have an expiry date specified.\nLink: [AVD-AZU-0014](https://avd.aquasec.com/misconfig/avd-azu-0014)\nExpiration Date is an optional Key Vault Key behavior and is not set by default.\n\nSet when the resource will be become inactive.", + "markdown": "**Misconfiguration AVD-AZU-0014**\n| Type | Severity | Check | Message | Link |\n| --- | --- | --- | --- | --- |\n|Terraform Security Check|MEDIUM|Ensure that the expiration date is set on all keys|Key should have an expiry date specified.|[AVD-AZU-0014](https://avd.aquasec.com/misconfig/avd-azu-0014)|\n\nExpiration Date is an optional Key Vault Key behavior and is not set by default.\n\nSet when the resource will be become inactive." + }, + "properties": { + "precision": "very-high", + "security-severity": "5.5", + "tags": [ + "misconfiguration", + "security", + "MEDIUM" + ] + } + } + ], + "version": "0.47.0" + } + }, + "results": [ + { + "ruleId": "AVD-AZU-0014", + "ruleIndex": 0, + "level": "warning", + "message": { + "text": "Artifact: modules/azure-cosmosdb/main.tf\nType: terraform\nVulnerability AVD-AZU-0014\nSeverity: MEDIUM\nMessage: Key should have an expiry date specified.\nLink: [AVD-AZU-0014](https://avd.aquasec.com/misconfig/avd-azu-0014)" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "modules/azure-cosmosdb/main.tf", + "uriBaseId": "ROOTPATH" + }, + "region": { + "startLine": 164, + "startColumn": 1, + "endLine": 176, + "endColumn": 1 + } + }, + "message": { + "text": "modules/azure-cosmosdb/main.tf" + } + } + ] + } + ], + "columnKind": "utf16CodeUnits", + "originalUriBaseIds": { + "ROOTPATH": { + "uri": "file:///home/example/" + } + } + } + ] +} diff --git a/backend/unittests/import_observations/parsers/sarif/test_parser.py b/backend/unittests/import_observations/parsers/sarif/test_parser.py index a1ae6cf45..acd82b9b7 100644 --- a/backend/unittests/import_observations/parsers/sarif/test_parser.py +++ b/backend/unittests/import_observations/parsers/sarif/test_parser.py @@ -174,8 +174,6 @@ def test_kics(self): self.assertEqual("Docker Socket Mounted In Container", observation.title) description = """There is a docker socket named 'docker.sock' mounted in a volume -**Rule short description:** Docker Socket Mounted In Container - **Rule full description:** Docker socket docker.sock should not be mounted on host. If the docker socket is mounted, it can allow its processes to execute docker commands. """ @@ -201,6 +199,54 @@ def test_kics(self): observation.unsaved_evidences[1][1], ) + def test_trivy_config(self): + with open(path.dirname(__file__) + "/files/trivy_config.sarif") as testfile: + parser = SARIFParser() + check, messages, data = parser.check_format(testfile) + observations = parser.get_observations(data) + + self.assertTrue(check) + self.assertEqual(0, len(messages)) + self.assertEqual(1, len(observations)) + + observation = observations[0] + self.assertEqual("Trivy / 0.47.0", observation.scanner) + self.assertEqual( + "Ensure that the expiration date is set on all keys", observation.title + ) + description = """**Rule full description:** Expiration Date is an optional Key Vault Key behavior and is not set by default. + +Set when the resource will be become inactive. + +**Precision:** very-high + +**Security-Severity:** 5.5 + +**Tags:** ['misconfiguration', 'security', 'MEDIUM'] + +""" + self.assertEqual(description, observation.description) + self.assertEqual( + "modules/azure-cosmosdb/main.tf", observation.origin_source_file + ) + self.assertEqual(164, observation.origin_source_line_start) + self.assertEqual(176, observation.origin_source_line_end) + self.assertEqual(Observation.SEVERITY_MEDIUM, observation.parser_severity) + self.assertEqual( + "https://avd.aquasec.com/misconfig/avd-azu-0014", + observation.unsaved_references[0], + ) + self.assertEqual("Rule", observation.unsaved_evidences[0][0]) + self.assertIn( + '"id": "AVD-AZU-0014"', + observation.unsaved_evidences[0][1], + ) + self.assertEqual("Result", observation.unsaved_evidences[1][0]) + self.assertIn( + '"ruleId": "AVD-AZU-0014"', + observation.unsaved_evidences[1][1], + ) + def test_dependency_check(self): with open(path.dirname(__file__) + "/files/dependency-check.sarif") as testfile: parser = SARIFParser() diff --git a/docs/assets/images/secobserve_process.drawio b/docs/assets/images/secobserve_process.drawio index a5c6b7c91..5442ed775 100644 --- a/docs/assets/images/secobserve_process.drawio +++ b/docs/assets/images/secobserve_process.drawio @@ -1,6 +1,6 @@ - + - + @@ -34,8 +34,8 @@ - - + + diff --git a/docs/assets/images/secobserve_process.svg b/docs/assets/images/secobserve_process.svg index a1c04753b..4c5becfe4 100644 --- a/docs/assets/images/secobserve_process.svg +++ b/docs/assets/images/secobserve_process.svg @@ -1,3 +1,3 @@ -
Project's CI/CD Pipeline
Project's CI/CD Pipeline
Upload
Upload
Check
Security Gate
Check...
View observations
Assess observations
Upload reports manually
View obs...
Scan
Scan
GitLab CI Templates / GitHub Actions
GitLab CI Templates / GitHub Actions
SCA


Dep. Check
Dep. Track
Grype
Trivy
SCA...
SAST
Application

Bandit
ESLint
FindSecBugs
Semgrep
SAST...
SAST
Infrastructure

Checkov
KICS
tfsec
SAST...
DAST


Cryptolyzer
DrHeader
OWASP ZAP
DAST...
Cloud
Infastructure


Prowler
Cloud...
Secrets


GitLeaks
Secrets...
Text is not SVG - cannot display
\ No newline at end of file +
Project's CI/CD Pipeline
Project's CI/CD Pipeline
Upload
Upload
Check
Security Gate
Check...
View observations
Assess observations
Upload reports manually
View obs...
Scan
Scan
GitLab CI Templates / GitHub Actions
GitLab CI Templates / GitHub Actions
SCA


Dep. Check
Dep. Track
Grype
Trivy
SCA...
SAST
Application

Bandit
ESLint
FindSecBugs
Semgrep
SAST...
SAST
Infrastructure

Checkov
KICS
tfsec
Trivy
SAST...
DAST


Cryptolyzer
DrHeader
OWASP ZAP
DAST...
Cloud
Infastructure


Prowler
Cloud...
Secrets


GitLeaks
Secrets...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docs/integrations/github_actions_and_templates.md b/docs/integrations/github_actions_and_templates.md index 6cf768d17..76903c44b 100644 --- a/docs/integrations/github_actions_and_templates.md +++ b/docs/integrations/github_actions_and_templates.md @@ -40,6 +40,7 @@ Most of the actions and templates use the same set of variables: | [Checkov](https://www.checkov.io/1.Welcome/Quick%20Start.html) | `actions/SAST/checkov` | `templates/SAST/checkov.yml` | [Apache 2.0](https://github.com/bridgecrewio/checkov/blob/main/LICENSE) | | [KICS](https://docs.kics.io/latest) | `actions/SAST/kics` | `templates/SAST/kics.yml` | [Apache 2.0](https://github.com/Checkmarx/kics/blob/master/LICENSE) | | [tfsec](https://aquasecurity.github.io/tfsec) | `actions/SAST/tfsec` | `templates/SAST/tfsec.yml` | [MIT](https://github.com/aquasecurity/tfsec/blob/master/LICENSE) | +| [Trivy](https://aquasecurity.github.io/trivy) | `actions/SCA/trivy_config` | `templates/SCA/trivy_config.yml` | [Apache 2.0](https://github.com/aquasecurity/trivy/blob/main/LICENSE) | | [Grype](https://github.com/anchore/grype) | `actions/SCA/grype_image` | `templates/SCA/grype_image.yml` | [Apache 2.0](https://github.com/anchore/grype/blob/main/LICENSE) | | [Trivy](https://aquasecurity.github.io/trivy) | `actions/SCA/trivy_filesystem` | `templates/SCA/trivy_filesystem.yml` | [Apache 2.0](https://github.com/aquasecurity/trivy/blob/main/LICENSE) | | [Trivy](https://aquasecurity.github.io/trivy) | `actions/SCA/trivy_image` | `templates/SCA/trivy_image.yml` | [Apache 2.0](https://github.com/aquasecurity/trivy/blob/main/LICENSE) | diff --git a/docs/usage/supported_scanners.md b/docs/usage/supported_scanners.md index 575ce0172..67dc21ea8 100644 --- a/docs/usage/supported_scanners.md +++ b/docs/usage/supported_scanners.md @@ -38,6 +38,7 @@ These scanners have been tested with SecObserve: | [Checkov](https://www.checkov.io/1.Welcome/Quick%20Start.html) | SARIF | Infrastructure SAST | File | | [KICS](https://docs.kics.io/latest) | SARIF | Infrastructure SAST | File | | [tfsec](https://aquasecurity.github.io/tfsec) | SARIF | Infrastructure SAST | File | +| [Trivy](https://aquasecurity.github.io/trivy) | SARIF | Infrastructure SAST | File | | [Gitleaks](https://gitleaks.io) | SARIF | Secrets | File | | [Trivy](https://aquasecurity.github.io/trivy) | SARIF | Secrets | File | | [CryptoLyzer](https://gitlab.com/coroner/cryptolyzer) ^2)^ | CryptoLyzer | DAST | File | From 47c8deeab25c68f4d17d6ca02b99571068b85de0 Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Wed, 8 Nov 2023 14:04:55 +0100 Subject: [PATCH 30/81] fix: re-signin after 401 (#745) --- frontend/src/access_control/authProvider.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/frontend/src/access_control/authProvider.ts b/frontend/src/access_control/authProvider.ts index 2b34183ef..af75d8e39 100644 --- a/frontend/src/access_control/authProvider.ts +++ b/frontend/src/access_control/authProvider.ts @@ -56,8 +56,8 @@ const authProvider: AuthProvider = { }, checkError: (error) => { if (error) { - if (oidc_signed_in()) { - if (window.__RUNTIME_CONFIG__.OIDC_ENABLE == "true") { + if (error.status === 401 || error.status === 403) { + if (oidc_signed_in()) { const user_manager = new UserManager(oidcConfig); return user_manager.signinRedirect(); } @@ -67,17 +67,6 @@ const authProvider: AuthProvider = { return Promise.resolve(); }, checkAuth: () => { - // if (window.__RUNTIME_CONFIG__.OIDC_ENABLE == "true") { - // const user_manager = new UserManager(oidcConfig); - // const user = await user_manager.getUser(); - // if (user && !user.expired) { - // console.log("user_manager.getUser() OK") - // return Promise.resolve(); - // } else { - // console.log("user_manager.getUser() not OK") - // return user_manager.signinRedirect(); - // } - // } if (oidc_signed_in() || jwt_signed_in()) { return Promise.resolve(); } From 22df866daa4aac16817567db554087a5dfe5f7df Mon Sep 17 00:00:00 2001 From: Stefan Fleckenstein Date: Fri, 10 Nov 2023 20:35:58 +0100 Subject: [PATCH 31/81] feat: services of products stored as objects (#751) --- .../access_control/services/authorization.py | 11 ++- .../services/roles_permissions.py | 16 ++++ backend/application/core/api/filters.py | 13 +++ backend/application/core/api/permissions.py | 11 +++ backend/application/core/api/serializers.py | 42 ++++++++- backend/application/core/api/views.py | 24 +++++- ...ice_observation_origin_service_and_more.py | 51 +++++++++++ .../migrations/0024_initialize_branches.py | 36 ++++++++ backend/application/core/models.py | 72 ++++++++++++++++ backend/application/core/queries/service.py | 53 ++++++++++++ .../services/import_observations.py | 5 ++ backend/config/api_router.py | 2 + .../access_control/api/test_authentication.py | 3 + .../test_authorization_api_configurations.py | 10 +-- .../api/test_authorization_branches.py | 10 +-- .../api/test_authorization_observations.py | 6 +- .../api/test_authorization_product_groups.py | 10 +-- .../api/test_authorization_product_rules.py | 10 +-- .../api/test_authorization_products.py | 10 +-- .../api/test_authorization_services.py | 85 +++++++++++++++++++ .../services/test_roles_permissions.py | 1 + .../fixtures/unittests_fixtures.json | 27 +++++- docs/getting_started/data_model.md | 5 ++ frontend/src/access_control/types.tsx | 3 + .../observations/ObservationEmbeddedList.tsx | 10 ++- .../src/core/observations/ObservationList.tsx | 8 +- frontend/src/core/products/ProductShow.tsx | 5 ++ frontend/src/core/services/ServiceDelete.tsx | 56 ++++++++++++ .../src/core/services/ServiceEmbeddedList.tsx | 79 +++++++++++++++++ 29 files changed, 634 insertions(+), 40 deletions(-) create mode 100644 backend/application/core/migrations/0023_service_observation_origin_service_and_more.py create mode 100644 backend/application/core/migrations/0024_initialize_branches.py create mode 100644 backend/application/core/queries/service.py create mode 100644 backend/unittests/access_control/api/test_authorization_services.py create mode 100644 frontend/src/core/services/ServiceDelete.tsx create mode 100644 frontend/src/core/services/ServiceEmbeddedList.tsx diff --git a/backend/application/access_control/services/authorization.py b/backend/application/access_control/services/authorization.py index 81a138aa1..c43d3b6a2 100644 --- a/backend/application/access_control/services/authorization.py +++ b/backend/application/access_control/services/authorization.py @@ -7,7 +7,13 @@ get_roles_with_permissions, ) from application.commons.services.global_request import get_current_user -from application.core.models import Branch, Observation, Product, Product_Member +from application.core.models import ( + Branch, + Observation, + Product, + Product_Member, + Service, +) from application.core.queries.product_member import get_product_member from application.import_observations.models import ( Api_Configuration, @@ -72,6 +78,9 @@ def user_has_permission( # pylint: disable=too-many-return-statements,too-many- if isinstance(obj, Branch) and permission in Permissions.get_branch_permissions(): return user_has_permission(obj.product, permission, user) + if isinstance(obj, Service) and permission in Permissions.get_service_permissions(): + return user_has_permission(obj.product, permission, user) + if ( isinstance(obj, Observation) and permission in Permissions.get_observation_permissions() diff --git a/backend/application/access_control/services/roles_permissions.py b/backend/application/access_control/services/roles_permissions.py index 1f42a787b..46d0e96f7 100644 --- a/backend/application/access_control/services/roles_permissions.py +++ b/backend/application/access_control/services/roles_permissions.py @@ -45,6 +45,9 @@ class Permissions(IntEnum): Branch_Delete = 1403 Branch_Create = 1404 + Service_View = 1501 + Service_Delete = 1503 + Observation_View = 2001 Observation_Edit = 2002 Observation_Delete = 2003 @@ -113,6 +116,13 @@ def get_branch_permissions(cls): Permissions.Branch_Create, } + @classmethod + def get_service_permissions(cls): + return { + Permissions.Service_View, + Permissions.Service_Delete, + } + @classmethod def get_api_configuration_permissions(cls): return { @@ -137,6 +147,7 @@ def get_roles_with_permissions(): Permissions.Product_Member_View, Permissions.Product_Rule_View, Permissions.Branch_View, + Permissions.Service_View, Permissions.Observation_View, Permissions.Api_Configuration_View, }, @@ -150,6 +161,7 @@ def get_roles_with_permissions(): Permissions.Product_Member_View, Permissions.Product_Rule_View, Permissions.Branch_View, + Permissions.Service_View, Permissions.Observation_View, Permissions.Observation_Edit, Permissions.Observation_Create, @@ -175,6 +187,8 @@ def get_roles_with_permissions(): Permissions.Branch_Edit, Permissions.Branch_Delete, Permissions.Branch_Create, + Permissions.Service_View, + Permissions.Service_Delete, Permissions.Observation_View, Permissions.Observation_Edit, Permissions.Observation_Create, @@ -205,6 +219,8 @@ def get_roles_with_permissions(): Permissions.Branch_Edit, Permissions.Branch_Delete, Permissions.Branch_Create, + Permissions.Service_View, + Permissions.Service_Delete, Permissions.Observation_View, Permissions.Observation_Edit, Permissions.Observation_Create, diff --git a/backend/application/core/api/filters.py b/backend/application/core/api/filters.py index 9122af94e..72d9626d5 100644 --- a/backend/application/core/api/filters.py +++ b/backend/application/core/api/filters.py @@ -17,6 +17,7 @@ Parser, Product, Product_Member, + Service, ) AGE_DAY = "Today" @@ -123,6 +124,17 @@ class Meta: fields = ["product", "name"] +class ServiceFilter(FilterSet): + ordering = OrderingFilter( + # tuple-mapping retains order + fields=(("name", "name")), + ) + + class Meta: + model = Service + fields = ["product", "name"] + + class ParserFilter(FilterSet): name = CharFilter(field_name="name", lookup_expr="icontains") type = ChoiceFilter(field_name="type", choices=Parser.TYPE_CHOICES) @@ -199,6 +211,7 @@ class Meta: # pylint: disable=duplicate-code "scanner", "upload_filename", "api_configuration_name", + "origin_service", ] def get_age(self, queryset, field_name, value): # pylint: disable=unused-argument diff --git a/backend/application/core/api/permissions.py b/backend/application/core/api/permissions.py index 045fb2bc6..bfe48ada6 100644 --- a/backend/application/core/api/permissions.py +++ b/backend/application/core/api/permissions.py @@ -68,6 +68,17 @@ def has_object_permission(self, request, view, obj): ) +class UserHasServicePermission(BasePermission): + def has_object_permission(self, request, view, obj): + return check_object_permission( + request, + obj, + Permissions.Service_View, + None, + Permissions.Service_Delete, + ) + + class UserHasObservationPermission(BasePermission): def has_permission(self, request, view): return check_post_permission( diff --git a/backend/application/core/api/serializers.py b/backend/application/core/api/serializers.py index 9d9487298..145b5eb46 100644 --- a/backend/application/core/api/serializers.py +++ b/backend/application/core/api/serializers.py @@ -30,6 +30,7 @@ Product, Product_Member, Reference, + Service, ) from application.core.queries.product_member import get_product_member from application.core.services.observation_log import create_observation_log @@ -335,6 +336,7 @@ def validate(self, attrs: dict): class BranchSerializer(ModelSerializer): + name_with_product = SerializerMethodField() is_default_branch = SerializerMethodField() open_critical_observation_count = SerializerMethodField() open_high_observation_count = SerializerMethodField() @@ -347,6 +349,9 @@ class Meta: model = Branch fields = "__all__" + def get_name_with_product(self, obj: Service) -> str: + return f"{obj.name} ({obj.product.name})" + def get_is_default_branch(self, obj: Branch) -> bool: return obj.product.repository_default_branch == obj @@ -368,11 +373,40 @@ def get_open_none_observation_count(self, obj: Branch) -> int: def get_open_unkown_observation_count(self, obj: Branch) -> int: return obj.open_unkown_observation_count - def validate_product(self, product: Product) -> Product: - if product and product.is_product_group: - raise ValidationError("Product must not be a product group") - return product +class ServiceSerializer(ModelSerializer): + name_with_product = SerializerMethodField() + open_critical_observation_count = SerializerMethodField() + open_high_observation_count = SerializerMethodField() + open_medium_observation_count = SerializerMethodField() + open_low_observation_count = SerializerMethodField() + open_none_observation_count = SerializerMethodField() + open_unkown_observation_count = SerializerMethodField() + + class Meta: + model = Service + fields = "__all__" + + def get_name_with_product(self, obj: Service) -> str: + return f"{obj.name} ({obj.product.name})" + + def get_open_critical_observation_count(self, obj: Service) -> int: + return obj.open_critical_observation_count + + def get_open_high_observation_count(self, obj: Service) -> int: + return obj.open_high_observation_count + + def get_open_medium_observation_count(self, obj: Service) -> int: + return obj.open_medium_observation_count + + def get_open_low_observation_count(self, obj: Service) -> int: + return obj.open_low_observation_count + + def get_open_none_observation_count(self, obj: Service) -> int: + return obj.open_none_observation_count + + def get_open_unkown_observation_count(self, obj: Service) -> int: + return obj.open_unkown_observation_count class ParserSerializer(ModelSerializer): diff --git a/backend/application/core/api/views.py b/backend/application/core/api/views.py index 11922abd5..ced6fd268 100644 --- a/backend/application/core/api/views.py +++ b/backend/application/core/api/views.py @@ -9,7 +9,7 @@ from rest_framework.decorators import action from rest_framework.exceptions import NotFound, ValidationError from rest_framework.filters import SearchFilter -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request from rest_framework.response import Response @@ -27,12 +27,14 @@ ProductFilter, ProductGroupFilter, ProductMemberFilter, + ServiceFilter, ) from application.core.api.permissions import ( UserHasBranchPermission, UserHasObservationPermission, UserHasProductMemberPermission, UserHasProductPermission, + UserHasServicePermission, ) from application.core.api.serializers import ( BranchSerializer, @@ -49,6 +51,7 @@ ProductGroupSerializer, ProductMemberSerializer, ProductSerializer, + ServiceSerializer, ) from application.core.models import ( Branch, @@ -57,6 +60,7 @@ Parser, Product, Product_Member, + Service, ) from application.core.queries.branch import get_branches from application.core.queries.observation import ( @@ -66,6 +70,7 @@ ) from application.core.queries.product import get_product_by_id, get_products from application.core.queries.product_member import get_product_members +from application.core.queries.service import get_services from application.core.services.assessment import remove_assessment, save_assessment from application.core.services.export_observations import ( export_observations_csv, @@ -303,7 +308,8 @@ class BranchViewSet(ModelViewSet): filterset_class = BranchFilter permission_classes = (IsAuthenticated, UserHasBranchPermission) queryset = Branch.objects.none() - filter_backends = [DjangoFilterBackend] + filter_backends = [SearchFilter, DjangoFilterBackend] + search_fields = ["name"] def get_queryset(self): return get_branches() @@ -316,6 +322,20 @@ def destroy(self, request: Request, *args: Any, **kwargs: Any) -> Response: return super().destroy(request, *args, **kwargs) +class ServiceViewSet( + GenericViewSet, ListModelMixin, RetrieveModelMixin, DestroyModelMixin +): + serializer_class = ServiceSerializer + filterset_class = ServiceFilter + permission_classes = (IsAuthenticated, UserHasServicePermission) + queryset = Service.objects.none() + filter_backends = [SearchFilter, DjangoFilterBackend] + search_fields = ["name"] + + def get_queryset(self): + return get_services() + + class ParserViewSet(GenericViewSet, ListModelMixin, RetrieveModelMixin): serializer_class = ParserSerializer filterset_class = ParserFilter diff --git a/backend/application/core/migrations/0023_service_observation_origin_service_and_more.py b/backend/application/core/migrations/0023_service_observation_origin_service_and_more.py new file mode 100644 index 000000000..fda52a2bc --- /dev/null +++ b/backend/application/core/migrations/0023_service_observation_origin_service_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 4.2.7 on 2023-11-08 17:07 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0022_branch_housekeeping"), + ] + + operations = [ + migrations.CreateModel( + name="Service", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255)), + ( + "product", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="core.product" + ), + ), + ], + ), + migrations.AddField( + model_name="observation", + name="origin_service", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="core.service", + ), + ), + migrations.AddIndex( + model_name="service", + index=models.Index(fields=["name"], name="core_servic_name_2e1bf5_idx"), + ), + migrations.AlterUniqueTogether( + name="service", + unique_together={("product", "name")}, + ), + ] diff --git a/backend/application/core/migrations/0024_initialize_branches.py b/backend/application/core/migrations/0024_initialize_branches.py new file mode 100644 index 000000000..b8e0c019c --- /dev/null +++ b/backend/application/core/migrations/0024_initialize_branches.py @@ -0,0 +1,36 @@ +import logging + +from django.db import migrations + +from application.commons.services.log_message import format_log_message + +logger = logging.getLogger("secobserve.migration") + + +def initialize_branches(apps, schema_editor): + Observation = apps.get_model("core", "Observation") + Service = apps.get_model("core", "Service") + for observation in Observation.objects.exclude(origin_service_name=""): + try: + try: + service = Service.objects.get( + product=observation.product, name=observation.origin_service_name + ) + except Service.DoesNotExist: + service = Service.objects.create( + product=observation.product, name=observation.origin_service_name + ) + observation.origin_service = service + observation.save() + except Exception as e: + logger.error(format_log_message(exception=e)) + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0023_service_observation_origin_service_and_more"), + ] + + operations = [ + migrations.RunPython(initialize_branches), + ] diff --git a/backend/application/core/models.py b/backend/application/core/models.py index 3a92760ef..ac179cc7b 100644 --- a/backend/application/core/models.py +++ b/backend/application/core/models.py @@ -267,6 +267,77 @@ def open_unkown_observation_count(self): ).count() +class Service(Model): + product = ForeignKey(Product, on_delete=CASCADE) + name = CharField(max_length=255) + + class Meta: + unique_together = ( + "product", + "name", + ) + indexes = [ + Index(fields=["name"]), + ] + + def __str__(self): + return self.name + + @property + def open_critical_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_CRITICAL, + current_status=Observation.STATUS_OPEN, + ).count() + + @property + def open_high_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_HIGH, + current_status=Observation.STATUS_OPEN, + ).count() + + @property + def open_medium_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_MEDIUM, + current_status=Observation.STATUS_OPEN, + ).count() + + @property + def open_low_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_LOW, + current_status=Observation.STATUS_OPEN, + ).count() + + @property + def open_none_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_NONE, + current_status=Observation.STATUS_OPEN, + ).count() + + @property + def open_unkown_observation_count(self): + return Observation.objects.filter( + origin_service=self, + branch=self.product.repository_default_branch, + current_severity=Observation.SEVERITY_UNKOWN, + current_status=Observation.STATUS_OPEN, + ).count() + + class Product_Member(Model): product = ForeignKey(Product, on_delete=CASCADE) user = ForeignKey(User, on_delete=CASCADE) @@ -410,6 +481,7 @@ class Observation(Model): origin_endpoint_query = TextField(max_length=2048, blank=True) origin_endpoint_fragment = TextField(max_length=2048, blank=True) origin_service_name = CharField(max_length=255, blank=True) + origin_service = ForeignKey(Service, on_delete=PROTECT, null=True) origin_source_file = CharField(max_length=255, blank=True) origin_source_line_start = IntegerField( null=True, validators=[MinValueValidator(0), MaxValueValidator(999999)] diff --git a/backend/application/core/queries/service.py b/backend/application/core/queries/service.py new file mode 100644 index 000000000..f8793643d --- /dev/null +++ b/backend/application/core/queries/service.py @@ -0,0 +1,53 @@ +from typing import Optional + +from django.db.models import Exists, OuterRef, Q +from django.db.models.query import QuerySet + +from application.commons.services.global_request import get_current_user +from application.core.models import Product, Product_Member, Service + + +def get_service_by_id(product: Product, service_id: int) -> Optional[Service]: + try: + return Service.objects.get(id=service_id, product=product) + except Service.DoesNotExist: + return None + + +def get_service_by_name(product: Product, name: str) -> Optional[Service]: + try: + return Service.objects.get(name=name, product=product) + except Service.DoesNotExist: + return None + + +def get_services() -> QuerySet[Service]: + user = get_current_user() + + if user is None: + return Service.objects.none() + + services = Service.objects.all() + + if not user.is_superuser: + product_members = Product_Member.objects.filter( + product=OuterRef("product_id"), user=user + ) + product_group_members = Product_Member.objects.filter( + product=OuterRef("product__product_group"), user=user + ) + + services = services.annotate( + product__member=Exists(product_members), + product__product_group__member=Exists(product_group_members), + ) + + services = services.filter( + Q(product__member=True) | Q(product__product_group__member=True) + ) + + return services + + +def get_services_by_product(product: Product) -> QuerySet[Service]: + return Service.objects.filter(product=product) diff --git a/backend/application/import_observations/services/import_observations.py b/backend/application/import_observations/services/import_observations.py index 0fdd1fd00..238b95480 100644 --- a/backend/application/import_observations/services/import_observations.py +++ b/backend/application/import_observations/services/import_observations.py @@ -13,6 +13,7 @@ Parser, Product, Reference, + Service, ) from application.core.queries.observation import ( get_observations_for_vulnerability_check, @@ -287,6 +288,10 @@ def prepare_imported_observation( imported_observation.import_last_seen = timezone.now() if import_parameters.service: imported_observation.origin_service_name = import_parameters.service + service = Service.objects.get_or_create( + product=import_parameters.product, name=import_parameters.service + )[0] + imported_observation.origin_service = service if import_parameters.docker_image_name_tag: imported_observation.origin_docker_image_name_tag = ( import_parameters.docker_image_name_tag diff --git a/backend/config/api_router.py b/backend/config/api_router.py index 33baf8543..122320e94 100644 --- a/backend/config/api_router.py +++ b/backend/config/api_router.py @@ -10,6 +10,7 @@ ProductGroupViewSet, ProductMemberViewSet, ProductViewSet, + ServiceViewSet, ) from application.import_observations.api.views import ( ApiConfigurationViewSet, @@ -27,6 +28,7 @@ router.register("product_groups", ProductGroupViewSet) router.register("product_members", ProductMemberViewSet) router.register("branches", BranchViewSet) +router.register("services", ServiceViewSet) router.register("parsers", ParserViewSet) router.register("observations", ObservationViewSet) router.register("general_rules", GeneralRuleViewSet) diff --git a/backend/unittests/access_control/api/test_authentication.py b/backend/unittests/access_control/api/test_authentication.py index 81d3df225..51ac6b949 100644 --- a/backend/unittests/access_control/api/test_authentication.py +++ b/backend/unittests/access_control/api/test_authentication.py @@ -256,6 +256,9 @@ def test_authentication(self, mock_user): ["delete", "get", "put", "patch"], "/api/branches/1/" ) + self._check_authentication(["get"], "/api/services/") + self._check_authentication(["delete", "get"], "/api/services/1/") + self._check_authentication(["get", "post"], "/api/product_members/") self._check_authentication( ["delete", "get", "put", "patch"], "/api/product_members/1/" diff --git a/backend/unittests/access_control/api/test_authorization_api_configurations.py b/backend/unittests/access_control/api/test_authorization_api_configurations.py index 81e57b3dd..4d6ba85cd 100644 --- a/backend/unittests/access_control/api/test_authorization_api_configurations.py +++ b/backend/unittests/access_control/api/test_authorization_api_configurations.py @@ -6,14 +6,14 @@ class TestAuthorizationApiConfigurations(TestAuthorizationBase): def test_authorization_api_configurations(self): - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_api_configuration_internal'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 1), ('parser', 2)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])), ('name', 'db_api_configuration_external'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 2), ('parser', 2)])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_api_configuration_internal'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 1), ('parser', 2)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])), ('name', 'db_api_configuration_external'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 2), ('parser', 2)])])])" self._test_api( APITest( "db_admin", "get", "/api/api_configurations/", None, 200, expected_data ) ) - expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_api_configuration_internal'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 1), ('parser', 2)])])])" + expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_api_configuration_internal'), ('base_url', 'http://localhost:8080'), ('project_key', 'secobserve'), ('api_key', '__secret__'), ('product', 1), ('parser', 2)])])])" self._test_api( APITest( "db_internal_write", @@ -25,7 +25,7 @@ def test_authorization_api_configurations(self): ) ) - expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'db_api_configuration_internal', 'base_url': 'http://localhost:8080', 'project_key': 'secobserve', 'api_key': '__secret__', 'product': 1, 'parser': 2}" + expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'db_api_configuration_internal', 'base_url': 'http://localhost:8080', 'project_key': 'secobserve', 'api_key': '__secret__', 'product': 1, 'parser': 2}" self._test_api( APITest( "db_internal_write", @@ -83,7 +83,7 @@ def test_authorization_api_configurations(self): ) ) - expected_data = "{'id': 3, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'string', 'base_url': 'string', 'project_key': 'string', 'api_key': 'string', 'product': 1, 'parser': 2}" + expected_data = "{'id': 3, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'string', 'base_url': 'string', 'project_key': 'string', 'api_key': 'string', 'product': 1, 'parser': 2}" self._test_api( APITest( "db_internal_write", @@ -109,7 +109,7 @@ def test_authorization_api_configurations(self): ) ) - expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'changed', 'base_url': 'http://localhost:8080', 'project_key': 'secobserve', 'api_key': '__secret__', 'product': 1, 'parser': 2}" + expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'changed', 'base_url': 'http://localhost:8080', 'project_key': 'secobserve', 'api_key': '__secret__', 'product': 1, 'parser': 2}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_branches.py b/backend/unittests/access_control/api/test_authorization_branches.py index 2d4d06a80..ff7928260 100644 --- a/backend/unittests/access_control/api/test_authorization_branches.py +++ b/backend/unittests/access_control/api/test_authorization_branches.py @@ -6,12 +6,12 @@ class TestAuthorizationBranches(TestAuthorizationBase): def test_authorization_branches(self): - expected_data = "OrderedDict([('count', 3), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_dev'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 2), ('is_default_branch', False), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_main'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 3), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_external'), ('last_import', None), ('housekeeping_protect', False), ('product', 2)])])])" + expected_data = "OrderedDict([('count', 3), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('name_with_product', 'db_branch_internal_dev (db_product_internal)'), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_dev'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 2), ('name_with_product', 'db_branch_internal_main (db_product_internal)'), ('is_default_branch', False), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_main'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 3), ('name_with_product', 'db_branch_external (db_product_external)'), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_external'), ('last_import', None), ('housekeeping_protect', False), ('product', 2)])])])" self._test_api( APITest("db_admin", "get", "/api/branches/", None, 200, expected_data) ) - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_dev'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 2), ('is_default_branch', False), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_main'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('name_with_product', 'db_branch_internal_dev (db_product_internal)'), ('is_default_branch', True), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_dev'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)]), OrderedDict([('id', 2), ('name_with_product', 'db_branch_internal_main (db_product_internal)'), ('is_default_branch', False), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_branch_internal_main'), ('last_import', None), ('housekeeping_protect', False), ('product', 1)])])])" self._test_api( APITest( "db_internal_write", @@ -23,7 +23,7 @@ def test_authorization_branches(self): ) ) - expected_data = "{'id': 1, 'is_default_branch': True, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'db_branch_internal_dev', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" + expected_data = "{'id': 1, 'name_with_product': 'db_branch_internal_dev (db_product_internal)', 'is_default_branch': True, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'db_branch_internal_dev', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" self._test_api( APITest( "db_internal_write", @@ -73,7 +73,7 @@ def test_authorization_branches(self): ) ) - expected_data = "{'id': 4, 'is_default_branch': False, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'string', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" + expected_data = "{'id': 4, 'name_with_product': 'string (db_product_internal)', 'is_default_branch': False, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'string', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" self._test_api( APITest( "db_internal_write", @@ -100,7 +100,7 @@ def test_authorization_branches(self): ) ) - expected_data = "{'id': 1, 'is_default_branch': True, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'changed', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" + expected_data = "{'id': 1, 'name_with_product': 'changed (db_product_internal)', 'is_default_branch': True, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'changed', 'last_import': None, 'housekeeping_protect': False, 'product': 1}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_observations.py b/backend/unittests/access_control/api/test_authorization_observations.py index c836953c9..8af66da65 100644 --- a/backend/unittests/access_control/api/test_authorization_observations.py +++ b/backend/unittests/access_control/api/test_authorization_observations.py @@ -6,12 +6,12 @@ class TestAuthorizationObservations(TestAuthorizationBase): def test_authorization_observations(self): - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('product_group_name', 'db_product_group'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1)])), ('branch_name', 'db_branch_internal_dev'), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'Duplicate'), ('parser_status', 'Open'), ('rule_status', 'Duplicate'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.870000+01:00'), ('created', '2022-12-15T17:10:35.513000+01:00'), ('modified', '2022-12-16T17:13:18.282000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.281000+01:00'), ('identity_hash', '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c'), ('issue_tracker_issue_id', ''), ('product', 1), ('branch', 1), ('parser', 1), ('general_rule', None), ('product_rule', 1)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('product_group_name', ''), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3)])), ('branch_name', ''), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'False positive'), ('parser_status', 'Open'), ('rule_status', 'False positive'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.876000+01:00'), ('created', '2022-12-15T17:10:35.521000+01:00'), ('modified', '2022-12-16T17:13:18.283000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.283000+01:00'), ('identity_hash', 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007'), ('issue_tracker_issue_id', ''), ('product', 2), ('branch', None), ('parser', 1), ('general_rule', None), ('product_rule', 2)])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('product_group_name', 'db_product_group'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1)])), ('branch_name', 'db_branch_internal_dev'), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'Duplicate'), ('parser_status', 'Open'), ('rule_status', 'Duplicate'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', 'db_service_internal_backend'), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.870000+01:00'), ('created', '2022-12-15T17:10:35.513000+01:00'), ('modified', '2022-12-16T17:13:18.282000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.281000+01:00'), ('identity_hash', '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c'), ('issue_tracker_issue_id', ''), ('product', 1), ('branch', 1), ('parser', 1), ('origin_service', 1), ('general_rule', None), ('product_rule', 1)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('product_group_name', ''), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3)])), ('branch_name', ''), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'False positive'), ('parser_status', 'Open'), ('rule_status', 'False positive'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.876000+01:00'), ('created', '2022-12-15T17:10:35.521000+01:00'), ('modified', '2022-12-16T17:13:18.283000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.283000+01:00'), ('identity_hash', 'bc8e59b7687fe3533616b3914c636389c131eac3bdbda1b67d8d26f890a74007'), ('issue_tracker_issue_id', ''), ('product', 2), ('branch', None), ('parser', 1), ('origin_service', None), ('general_rule', None), ('product_rule', 2)])])])" self._test_api( APITest("db_admin", "get", "/api/observations/", None, 200, expected_data) ) - expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('product_group_name', 'db_product_group'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1)])), ('branch_name', 'db_branch_internal_dev'), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'Duplicate'), ('parser_status', 'Open'), ('rule_status', 'Duplicate'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.870000+01:00'), ('created', '2022-12-15T17:10:35.513000+01:00'), ('modified', '2022-12-16T17:13:18.282000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.281000+01:00'), ('identity_hash', '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c'), ('issue_tracker_issue_id', ''), ('product', 1), ('branch', 1), ('parser', 1), ('general_rule', None), ('product_rule', 1)])])])" + expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('product_group_name', 'db_product_group'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1)])), ('branch_name', 'db_branch_internal_dev'), ('parser_data', OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')])), ('scanner_name', 'db_parser'), ('origin_component_name_version', ''), ('title', 'db_observation_internal'), ('description', ''), ('recommendation', ''), ('current_severity', 'Medium'), ('parser_severity', 'Medium'), ('rule_severity', ''), ('assessment_severity', ''), ('current_status', 'Duplicate'), ('parser_status', 'Open'), ('rule_status', 'Duplicate'), ('assessment_status', ''), ('scanner_observation_id', ''), ('vulnerability_id', ''), ('origin_component_name', ''), ('origin_component_version', ''), ('origin_component_purl', ''), ('origin_component_cpe', ''), ('origin_docker_image_name', ''), ('origin_docker_image_tag', ''), ('origin_docker_image_name_tag', ''), ('origin_docker_image_name_tag_short', ''), ('origin_endpoint_url', ''), ('origin_endpoint_scheme', ''), ('origin_endpoint_hostname', ''), ('origin_endpoint_port', None), ('origin_endpoint_path', ''), ('origin_endpoint_params', ''), ('origin_endpoint_query', ''), ('origin_endpoint_fragment', ''), ('origin_service_name', 'db_service_internal_backend'), ('origin_source_file', ''), ('origin_source_line_start', None), ('origin_source_line_end', None), ('cvss3_score', None), ('cvss3_vector', ''), ('cwe', None), ('epss_score', None), ('epss_percentile', None), ('found', None), ('scanner', 'db_parser'), ('upload_filename', 'parser.json'), ('api_configuration_name', ''), ('import_last_seen', '2022-12-15T17:14:20.870000+01:00'), ('created', '2022-12-15T17:10:35.513000+01:00'), ('modified', '2022-12-16T17:13:18.282000+01:00'), ('last_observation_log', '2022-12-16T17:13:18.281000+01:00'), ('identity_hash', '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c'), ('issue_tracker_issue_id', ''), ('product', 1), ('branch', 1), ('parser', 1), ('origin_service', 1), ('general_rule', None), ('product_rule', 1)])])])" self._test_api( APITest( "db_internal_write", @@ -22,7 +22,7 @@ def test_authorization_observations(self): expected_data, ) ) - expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'branch_name': 'db_branch_internal_dev', 'parser_data': OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')]), 'observation_logs': [OrderedDict([('id', 2), ('severity', ''), ('status', 'Duplicate'), ('comment', 'Set by product rule'), ('created', '2022-12-15T17:10:35.524000+01:00'), ('user', 2)]), OrderedDict([('id', 1), ('severity', 'Medium'), ('status', 'Open'), ('comment', 'Set by parser'), ('created', '2022-12-15T17:10:35.518000+01:00'), ('user', 2)])], 'references': [], 'evidences': [OrderedDict([('id', 1), ('name', 'db_evidence_internal')])], 'origin_source_file_url': None, 'issue_tracker_issue_url': None, 'title': 'db_observation_internal', 'description': '', 'recommendation': '', 'current_severity': 'Medium', 'parser_severity': 'Medium', 'rule_severity': '', 'assessment_severity': '', 'current_status': 'Duplicate', 'parser_status': 'Open', 'rule_status': 'Duplicate', 'assessment_status': '', 'scanner_observation_id': '', 'vulnerability_id': '', 'origin_component_name': '', 'origin_component_version': '', 'origin_component_name_version': '', 'origin_component_purl': '', 'origin_component_cpe': '', 'origin_docker_image_name': '', 'origin_docker_image_tag': '', 'origin_docker_image_name_tag': '', 'origin_docker_image_name_tag_short': '', 'origin_endpoint_url': '', 'origin_endpoint_scheme': '', 'origin_endpoint_hostname': '', 'origin_endpoint_port': None, 'origin_endpoint_path': '', 'origin_endpoint_params': '', 'origin_endpoint_query': '', 'origin_endpoint_fragment': '', 'origin_service_name': '', 'origin_source_file': '', 'origin_source_line_start': None, 'origin_source_line_end': None, 'cvss3_score': None, 'cvss3_vector': '', 'cwe': None, 'epss_score': None, 'epss_percentile': None, 'found': None, 'scanner': 'db_parser', 'upload_filename': 'parser.json', 'api_configuration_name': '', 'import_last_seen': '2022-12-15T17:14:20.870000+01:00', 'created': '2022-12-15T17:10:35.513000+01:00', 'modified': '2022-12-16T17:13:18.282000+01:00', 'last_observation_log': '2022-12-16T17:13:18.281000+01:00', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'issue_tracker_issue_id': '', 'product': 1, 'branch': 1, 'parser': 1, 'general_rule': None, 'product_rule': 1}" + expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'branch_name': 'db_branch_internal_dev', 'parser_data': OrderedDict([('id', 1), ('name', 'db_parser_file'), ('type', 'DAST'), ('source', 'File')]), 'observation_logs': [OrderedDict([('id', 2), ('severity', ''), ('status', 'Duplicate'), ('comment', 'Set by product rule'), ('created', '2022-12-15T17:10:35.524000+01:00'), ('user', 2)]), OrderedDict([('id', 1), ('severity', 'Medium'), ('status', 'Open'), ('comment', 'Set by parser'), ('created', '2022-12-15T17:10:35.518000+01:00'), ('user', 2)])], 'references': [], 'evidences': [OrderedDict([('id', 1), ('name', 'db_evidence_internal')])], 'origin_source_file_url': None, 'issue_tracker_issue_url': None, 'title': 'db_observation_internal', 'description': '', 'recommendation': '', 'current_severity': 'Medium', 'parser_severity': 'Medium', 'rule_severity': '', 'assessment_severity': '', 'current_status': 'Duplicate', 'parser_status': 'Open', 'rule_status': 'Duplicate', 'assessment_status': '', 'scanner_observation_id': '', 'vulnerability_id': '', 'origin_component_name': '', 'origin_component_version': '', 'origin_component_name_version': '', 'origin_component_purl': '', 'origin_component_cpe': '', 'origin_docker_image_name': '', 'origin_docker_image_tag': '', 'origin_docker_image_name_tag': '', 'origin_docker_image_name_tag_short': '', 'origin_endpoint_url': '', 'origin_endpoint_scheme': '', 'origin_endpoint_hostname': '', 'origin_endpoint_port': None, 'origin_endpoint_path': '', 'origin_endpoint_params': '', 'origin_endpoint_query': '', 'origin_endpoint_fragment': '', 'origin_service_name': 'db_service_internal_backend', 'origin_source_file': '', 'origin_source_line_start': None, 'origin_source_line_end': None, 'cvss3_score': None, 'cvss3_vector': '', 'cwe': None, 'epss_score': None, 'epss_percentile': None, 'found': None, 'scanner': 'db_parser', 'upload_filename': 'parser.json', 'api_configuration_name': '', 'import_last_seen': '2022-12-15T17:14:20.870000+01:00', 'created': '2022-12-15T17:10:35.513000+01:00', 'modified': '2022-12-16T17:13:18.282000+01:00', 'last_observation_log': '2022-12-16T17:13:18.281000+01:00', 'identity_hash': '6eef8088480aa2523aeeb64ad35f876a942cc3172cfb36752f3a052a4f88642c', 'issue_tracker_issue_id': '', 'product': 1, 'branch': 1, 'parser': 1, 'origin_service': 1, 'general_rule': None, 'product_rule': 1}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_product_groups.py b/backend/unittests/access_control/api/test_authorization_product_groups.py index d6794346e..eb1c42c30 100644 --- a/backend/unittests/access_control/api/test_authorization_product_groups.py +++ b/backend/unittests/access_control/api/test_authorization_product_groups.py @@ -6,12 +6,12 @@ class TestAuthorizationProductGroups(TestAuthorizationBase): def test_product_groups_authorization(self): - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 3), ('name', 'db_product_group'), ('description', ''), ('products_count', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)]), OrderedDict([('id', 4), ('name', 'db_product_group_admin_only'), ('description', ''), ('products_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 3), ('name', 'db_product_group'), ('description', ''), ('products_count', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)]), OrderedDict([('id', 4), ('name', 'db_product_group_admin_only'), ('description', ''), ('products_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)])])])" self._test_api( APITest("db_admin", "get", "/api/product_groups/", None, 200, expected_data) ) - expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 3), ('name', 'db_product_group'), ('description', ''), ('products_count', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)])])])" + expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 3), ('name', 'db_product_group'), ('description', ''), ('products_count', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None)])])])" self._test_api( APITest( "db_product_group_user", @@ -22,7 +22,7 @@ def test_product_groups_authorization(self): expected_data, ) ) - expected_data = "{'id': 3, 'name': 'db_product_group', 'description': '', 'products_count': 1, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" + expected_data = "{'id': 3, 'name': 'db_product_group', 'description': '', 'products_count': 1, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" self._test_api( APITest( "db_product_group_user", @@ -58,7 +58,7 @@ def test_product_groups_authorization(self): expected_data, ) ) - expected_data = "{'id': 5, 'name': 'string', 'description': '', 'products_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" + expected_data = "{'id': 5, 'name': 'string', 'description': '', 'products_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" self._test_api( APITest( "db_product_group_user", @@ -72,7 +72,7 @@ def test_product_groups_authorization(self): ) ) - expected_data = "{'id': 3, 'name': 'db_product_group', 'description': 'string', 'products_count': 1, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" + expected_data = "{'id': 3, 'name': 'db_product_group', 'description': 'string', 'products_count': 1, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None}" self._test_api( APITest( "db_product_group_user", diff --git a/backend/unittests/access_control/api/test_authorization_product_rules.py b/backend/unittests/access_control/api/test_authorization_product_rules.py index e9bbcd883..8c2878f55 100644 --- a/backend/unittests/access_control/api/test_authorization_product_rules.py +++ b/backend/unittests/access_control/api/test_authorization_product_rules.py @@ -6,12 +6,12 @@ class TestAuthorizationProductRules(TestAuthorizationBase): def test_authorization_product_rules(self): - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_product_rule_internal'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'Duplicate'), ('enabled', True), ('product', 1), ('parser', 1)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])), ('name', 'db_product_rule_external'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'False positive'), ('enabled', True), ('product', 2), ('parser', 1)])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_product_rule_internal'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'Duplicate'), ('enabled', True), ('product', 1), ('parser', 1)]), OrderedDict([('id', 2), ('product_data', OrderedDict([('id', 2), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])), ('name', 'db_product_rule_external'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'False positive'), ('enabled', True), ('product', 2), ('parser', 1)])])])" self._test_api( APITest("db_admin", "get", "/api/product_rules/", None, 200, expected_data) ) - expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_product_rule_internal'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'Duplicate'), ('enabled', True), ('product', 1), ('parser', 1)])])])" + expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('product_data', OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])), ('name', 'db_product_rule_internal'), ('description', ''), ('scanner_prefix', ''), ('title', ''), ('origin_component_name_version', ''), ('origin_docker_image_name_tag', ''), ('origin_endpoint_url', ''), ('origin_service_name', ''), ('origin_source_file', ''), ('new_severity', ''), ('new_status', 'Duplicate'), ('enabled', True), ('product', 1), ('parser', 1)])])])" self._test_api( APITest( "db_internal_write", @@ -23,7 +23,7 @@ def test_authorization_product_rules(self): ) ) - expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'db_product_rule_internal', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': 'Duplicate', 'enabled': True, 'product': 1, 'parser': 1}" + expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'db_product_rule_internal', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': 'Duplicate', 'enabled': True, 'product': 1, 'parser': 1}" self._test_api( APITest( "db_internal_write", @@ -73,7 +73,7 @@ def test_authorization_product_rules(self): ) ) - expected_data = "{'id': 4, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'string', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': '', 'enabled': True, 'product': 1, 'parser': 1}" + expected_data = "{'id': 4, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'string', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': '', 'enabled': True, 'product': 1, 'parser': 1}" self._test_api( APITest( "db_internal_write", @@ -100,7 +100,7 @@ def test_authorization_product_rules(self): ) ) - expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'changed', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': 'Duplicate', 'enabled': True, 'product': 1, 'parser': 1}" + expected_data = "{'id': 1, 'product_data': OrderedDict([('id', 1), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), 'name': 'changed', 'description': '', 'scanner_prefix': '', 'title': '', 'origin_component_name_version': '', 'origin_docker_image_name_tag': '', 'origin_endpoint_url': '', 'origin_service_name': '', 'origin_source_file': '', 'new_severity': '', 'new_status': 'Duplicate', 'enabled': True, 'product': 1, 'parser': 1}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_products.py b/backend/unittests/access_control/api/test_authorization_products.py index cb0fe1988..d811ed818 100644 --- a/backend/unittests/access_control/api/test_authorization_products.py +++ b/backend/unittests/access_control/api/test_authorization_products.py @@ -6,18 +6,18 @@ class TestAuthorizationProducts(TestAuthorizationBase): def test_authorization_products(self): - expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', 'db_product_group'), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_internal_dev'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), OrderedDict([('id', 2), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', ''), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_external'), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])])])" + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', 'db_product_group'), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_internal_dev'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])]), OrderedDict([('id', 2), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', ''), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_external'), ('name', 'db_product_external'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', None), ('security_gate_active', False), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', None), ('repository_default_branch', 3), ('members', [3, 4, 5])])])])" self._test_api( APITest("db_admin", "get", "/api/products/", None, 200, expected_data) ) - expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', 'db_product_group'), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_internal_dev'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])])])" + expected_data = "OrderedDict([('count', 1), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('permissions', {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }), ('product_group_name', 'db_product_group'), ('product_group_repository_branch_housekeeping_active', None), ('product_group_security_gate_active', None), ('repository_default_branch_name', 'db_branch_internal_dev'), ('name', 'db_product_internal'), ('description', ''), ('repository_prefix', ''), ('repository_branch_housekeeping_active', None), ('repository_branch_housekeeping_keep_inactive_days', None), ('repository_branch_housekeeping_exempt_branches', ''), ('security_gate_passed', True), ('security_gate_active', None), ('security_gate_threshold_critical', None), ('security_gate_threshold_high', None), ('security_gate_threshold_medium', None), ('security_gate_threshold_low', None), ('security_gate_threshold_none', None), ('security_gate_threshold_unkown', None), ('apply_general_rules', True), ('notification_ms_teams_webhook', ''), ('notification_email_to', ''), ('issue_tracker_active', False), ('issue_tracker_type', ''), ('issue_tracker_base_url', ''), ('issue_tracker_username', ''), ('issue_tracker_api_key', ''), ('issue_tracker_project_id', ''), ('issue_tracker_labels', ''), ('issue_tracker_issue_type', ''), ('issue_tracker_status_closed', ''), ('last_observation_change', '2022-12-16T17:13:18.283000+01:00'), ('product_group', 3), ('repository_default_branch', 1), ('members', [2, 3])])])])" self._test_api( APITest( "db_internal_write", "get", "/api/products/", None, 200, expected_data ) ) - expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': 'db_branch_internal_dev', 'name': 'db_product_internal', 'description': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': 3, 'repository_default_branch': 1, 'members': [2, 3]}" + expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': 'db_branch_internal_dev', 'name': 'db_product_internal', 'description': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': 3, 'repository_default_branch': 1, 'members': [2, 3]}" self._test_api( APITest( "db_internal_write", "get", "/api/products/1/", None, 200, expected_data @@ -53,7 +53,7 @@ def test_authorization_products(self): expected_data, ) ) - expected_data = "{'id': 5, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': '', 'name': 'string', 'description': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': None, 'repository_default_branch': None, 'members': [2]}" + expected_data = "{'id': 5, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': '', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': '', 'name': 'string', 'description': '', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': None, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': None, 'repository_default_branch': None, 'members': [2]}" self._test_api( APITest( "db_internal_write", @@ -81,7 +81,7 @@ def test_authorization_products(self): expected_data, ) ) - expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': 'db_branch_internal_dev', 'name': 'db_product_internal', 'description': 'string', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': 3, 'repository_default_branch': 1, 'members': [2, 3]}" + expected_data = "{'id': 1, 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'permissions': {, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , }, 'product_group_name': 'db_product_group', 'product_group_repository_branch_housekeeping_active': None, 'product_group_security_gate_active': None, 'repository_default_branch_name': 'db_branch_internal_dev', 'name': 'db_product_internal', 'description': 'string', 'repository_prefix': '', 'repository_branch_housekeeping_active': None, 'repository_branch_housekeeping_keep_inactive_days': None, 'repository_branch_housekeeping_exempt_branches': '', 'security_gate_passed': True, 'security_gate_active': None, 'security_gate_threshold_critical': None, 'security_gate_threshold_high': None, 'security_gate_threshold_medium': None, 'security_gate_threshold_low': None, 'security_gate_threshold_none': None, 'security_gate_threshold_unkown': None, 'apply_general_rules': True, 'notification_ms_teams_webhook': '', 'notification_email_to': '', 'issue_tracker_active': False, 'issue_tracker_type': '', 'issue_tracker_base_url': '', 'issue_tracker_username': '', 'issue_tracker_api_key': '', 'issue_tracker_project_id': '', 'issue_tracker_labels': '', 'issue_tracker_issue_type': '', 'issue_tracker_status_closed': '', 'last_observation_change': '2022-12-16T17:13:18.283000+01:00', 'product_group': 3, 'repository_default_branch': 1, 'members': [2, 3]}" self._test_api( APITest( "db_internal_write", diff --git a/backend/unittests/access_control/api/test_authorization_services.py b/backend/unittests/access_control/api/test_authorization_services.py new file mode 100644 index 000000000..020d3f20f --- /dev/null +++ b/backend/unittests/access_control/api/test_authorization_services.py @@ -0,0 +1,85 @@ +from unittests.access_control.api.test_authorization import ( + APITest, + TestAuthorizationBase, +) + + +class TestAuthorizationServices(TestAuthorizationBase): + def test_authorization_services(self): + expected_data = "OrderedDict([('count', 3), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('name_with_product', 'db_service_internal_backend (db_product_internal)'), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_service_internal_backend'), ('product', 1)]), OrderedDict([('id', 2), ('name_with_product', 'db_service_internal_frontend (db_product_internal)'), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_service_internal_frontend'), ('product', 1)]), OrderedDict([('id', 3), ('name_with_product', 'db_service_external (db_product_external)'), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_service_external'), ('product', 2)])])])" + self._test_api( + APITest("db_admin", "get", "/api/services/", None, 200, expected_data) + ) + + expected_data = "OrderedDict([('count', 2), ('next', None), ('previous', None), ('results', [OrderedDict([('id', 1), ('name_with_product', 'db_service_internal_backend (db_product_internal)'), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_service_internal_backend'), ('product', 1)]), OrderedDict([('id', 2), ('name_with_product', 'db_service_internal_frontend (db_product_internal)'), ('open_critical_observation_count', 0), ('open_high_observation_count', 0), ('open_medium_observation_count', 0), ('open_low_observation_count', 0), ('open_none_observation_count', 0), ('open_unkown_observation_count', 0), ('name', 'db_service_internal_frontend'), ('product', 1)])])])" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/services/", + None, + 200, + expected_data, + ) + ) + + expected_data = "{'id': 1, 'name_with_product': 'db_service_internal_backend (db_product_internal)', 'open_critical_observation_count': 0, 'open_high_observation_count': 0, 'open_medium_observation_count': 0, 'open_low_observation_count': 0, 'open_none_observation_count': 0, 'open_unkown_observation_count': 0, 'name': 'db_service_internal_backend', 'product': 1}" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/services/1/", + None, + 200, + expected_data, + ) + ) + + expected_data = "{'message': 'No Service matches the given query.'}" + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/services/3/", + None, + 404, + expected_data, + ) + ) + + self._test_api( + APITest( + "db_internal_write", + "get", + "/api/services/99999/", + None, + 404, + expected_data, + ) + ) + + expected_data = ( + "{'message': 'You do not have permission to perform this action.'}" + ) + self._test_api( + APITest( + "db_internal_read", + "delete", + "/api/services/1/", + None, + 403, + expected_data, + ) + ) + + expected_data = "{'message': \"Cannot delete some instances of model 'Service' because they are referenced through protected foreign keys\"}" + self._test_api( + APITest( + "db_internal_write", + "delete", + "/api/services/1/", + None, + 409, + expected_data, + ) + ) diff --git a/backend/unittests/access_control/services/test_roles_permissions.py b/backend/unittests/access_control/services/test_roles_permissions.py index 40274c22e..a8d9df22e 100644 --- a/backend/unittests/access_control/services/test_roles_permissions.py +++ b/backend/unittests/access_control/services/test_roles_permissions.py @@ -19,5 +19,6 @@ def test_get_permissions_for_role_successful(self): Permissions.Product_Rule_View, Permissions.Observation_View, Permissions.Api_Configuration_View, + Permissions.Service_View, } self.assertEqual(permissions, get_permissions_for_role(Roles.Reader)) diff --git a/backend/unittests/fixtures/unittests_fixtures.json b/backend/unittests/fixtures/unittests_fixtures.json index a9211dc7b..636fb4f67 100644 --- a/backend/unittests/fixtures/unittests_fixtures.json +++ b/backend/unittests/fixtures/unittests_fixtures.json @@ -237,6 +237,30 @@ "name": "db_branch_external" } }, + { + "model": "core.service", + "pk": 1, + "fields": { + "product": 1, + "name": "db_service_internal_backend" + } + }, + { + "model": "core.service", + "pk": 2, + "fields": { + "product": 1, + "name": "db_service_internal_frontend" + } + }, + { + "model": "core.service", + "pk": 3, + "fields": { + "product": 2, + "name": "db_service_external" + } + }, { "model": "core.product_member", "pk": 1, @@ -355,7 +379,8 @@ "origin_endpoint_params": "", "origin_endpoint_query": "", "origin_endpoint_fragment": "", - "origin_service_name": "", + "origin_service_name": "db_service_internal_backend", + "origin_service": 1, "origin_source_file": "", "origin_source_line_start": null, "origin_source_line_end": null, diff --git a/docs/getting_started/data_model.md b/docs/getting_started/data_model.md index 52c1ed7ac..1a258c1c1 100644 --- a/docs/getting_started/data_model.md +++ b/docs/getting_started/data_model.md @@ -5,6 +5,7 @@ erDiagram Product_Group |o--o{ Product : has Product ||--o{ Observation : has Product ||--o{ Branch : has + Product ||--o{ Service : has Product ||--o{ Vulnerability_Check : has Product ||--o{ Product_Rule : has Product ||--o{ API_Configuration : has @@ -35,6 +36,10 @@ Every `Observation` belongs to exactly one product. Software development often uses branches in the source code repository. Vulnerability scanners can run for multiple branches of a product and observations can be viewed and managed by branch. See more in [Working with branches](../usage/branches.md). +## Service + +A `Service` is a self-contained piece of functionality of a product. Can be something like a microservice or `backend` or `frontend`. + ## Vulnerability Check An import for one product, one branch and one file name resp. one API configuration is a so-called vulnerability check. See more in [Import algorithm](../../usage/import_observations/#import-algorithm). diff --git a/frontend/src/access_control/types.tsx b/frontend/src/access_control/types.tsx index fabcbea10..4b5b9df43 100644 --- a/frontend/src/access_control/types.tsx +++ b/frontend/src/access_control/types.tsx @@ -33,6 +33,9 @@ export const PERMISSION_BRANCH_EDIT = 1402; export const PERMISSION_BRANCH_DELETE = 1403; export const PERMISSION_BRANCH_CREATE = 1404; +export const PERMISSION_SERVICE_VIEW = 1501; +export const PERMISSION_SERVICE_DELETE = 1503; + export const PERMISSION_OBSERVATION_VIEW = 2001; export const PERMISSION_OBSERVATION_EDIT = 2002; export const PERMISSION_OBSERVATION_DELETE = 2003; diff --git a/frontend/src/core/observations/ObservationEmbeddedList.tsx b/frontend/src/core/observations/ObservationEmbeddedList.tsx index 6378964ac..4d20eaa57 100644 --- a/frontend/src/core/observations/ObservationEmbeddedList.tsx +++ b/frontend/src/core/observations/ObservationEmbeddedList.tsx @@ -51,7 +51,15 @@ function listFilters(product: Product) { alwaysOn />, , - , + + + , , , , diff --git a/frontend/src/core/observations/ObservationList.tsx b/frontend/src/core/observations/ObservationList.tsx index 69dbd616f..6b2e31e2b 100644 --- a/frontend/src/core/observations/ObservationList.tsx +++ b/frontend/src/core/observations/ObservationList.tsx @@ -17,7 +17,7 @@ import { import { CustomPagination } from "../../commons/custom_fields/CustomPagination"; import { SeverityField } from "../../commons/custom_fields/SeverityField"; import { humanReadableDate } from "../../commons/functions"; -import { AutocompleteInputMedium } from "../../commons/layout/themes"; +import { AutocompleteInputMedium, AutocompleteInputWide } from "../../commons/layout/themes"; import { AGE_CHOICES, OBSERVATION_SEVERITY_CHOICES, @@ -34,12 +34,14 @@ const listFilters = [ , - + , , , , - , + + + , , , , diff --git a/frontend/src/core/products/ProductShow.tsx b/frontend/src/core/products/ProductShow.tsx index bde95370c..970adc36a 100644 --- a/frontend/src/core/products/ProductShow.tsx +++ b/frontend/src/core/products/ProductShow.tsx @@ -1,6 +1,7 @@ import AccountTreeIcon from "@mui/icons-material/AccountTree"; import BarChartIcon from "@mui/icons-material/BarChart"; import UploadIcon from "@mui/icons-material/CloudUpload"; +import ConstructionIcon from "@mui/icons-material/Construction"; import GradingIcon from "@mui/icons-material/Grading"; import PeopleAltIcon from "@mui/icons-material/PeopleAlt"; import TokenIcon from "@mui/icons-material/Token"; @@ -52,6 +53,7 @@ import ObservationCreate from "../observations/ObservationCreate"; import ObservationsEmbeddedList from "../observations/ObservationEmbeddedList"; import ProductMemberCreate from "../product_members/ProductMemberCreate"; import ProductMemberEmbeddedList from "../product_members/ProductMemberEmbeddedList"; +import ServiceEmbeddedList from "../services/ServiceEmbeddedList"; import ExportMenu from "./ExportMenu"; import ProductHeader from "./ProductHeader"; import ProductShowProduct from "./ProductShowProduct"; @@ -145,6 +147,9 @@ const ProductShow = () => { )} + }> + + }> diff --git a/frontend/src/core/services/ServiceDelete.tsx b/frontend/src/core/services/ServiceDelete.tsx new file mode 100644 index 000000000..66decfa43 --- /dev/null +++ b/frontend/src/core/services/ServiceDelete.tsx @@ -0,0 +1,56 @@ +import DeleteIcon from "@mui/icons-material/Delete"; +import { useState } from "react"; +import { Button, Confirm, useDelete, useNotify, useRefresh } from "react-admin"; + +type ServiceDeleteProps = { + service: any; +}; + +const ServiceDelete = (props: ServiceDeleteProps) => { + const [open, setOpen] = useState(false); + const [deleted, setDeleted] = useState(false); + const [error_shown, setErrorShown] = useState(false); + const [deleteOne, { isLoading, error }] = useDelete(); // eslint-disable-line @typescript-eslint/no-unused-vars + // isLoading is not needed but easier to let it there + const refresh = useRefresh(); + const notify = useNotify(); + const handleClick = () => setOpen(true); + const handleDialogClose = () => setOpen(false); + + const handleConfirm = async () => { + deleteOne("services", { id: props.service.id }); + setDeleted(true); + refresh(); + setOpen(false); + }; + + if (error && !error_shown) { + setErrorShown(true); + setDeleted(false); + notify("Service could not be deleted: " + error, { + type: "warning", + }); + } else if (deleted) { + setDeleted(false); + notify("Service deleted"); + } + + return ( + <> +