From ce666ff30e7c2d7204761afc59866b1ebc6fe142 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 20 Feb 2024 11:23:59 +0100 Subject: [PATCH 01/48] clear policies api tests and add a category choices test --- backend/app_tests/api/test_api_policies.py | 32 +++++++++---------- .../api/test_api_requirement_nodes.py | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/backend/app_tests/api/test_api_policies.py b/backend/app_tests/api/test_api_policies.py index 94d3fa026..da7cd271a 100644 --- a/backend/app_tests/api/test_api_policies.py +++ b/backend/app_tests/api/test_api_policies.py @@ -1,6 +1,6 @@ import pytest from rest_framework.test import APIClient -from core.models import SecurityFunction, Policy +from core.models import Policy from iam.models import Folder from test_api import EndpointTestsQueries @@ -22,7 +22,7 @@ class TestPolicysUnauthenticated: client = APIClient() - def test_get_security_measures(self): + def test_get_policies(self): """test to get policies from the API without authentication""" EndpointTestsQueries.get_object( @@ -36,7 +36,7 @@ def test_get_security_measures(self): }, ) - def test_create_security_measures(self): + def test_create_policies(self): """test to create policies with the API without authentication""" EndpointTestsQueries.create_object( @@ -50,7 +50,7 @@ def test_create_security_measures(self): }, ) - def test_update_security_measures(self): + def test_update_policies(self): """test to update policies with the API without authentication""" EndpointTestsQueries.update_object( @@ -69,7 +69,7 @@ def test_update_security_measures(self): }, ) - def test_delete_security_measures(self): + def test_delete_policies(self): """test to delete policies with the API without authentication""" EndpointTestsQueries.delete_object( @@ -87,7 +87,7 @@ def test_delete_security_measures(self): class TestPolicysAuthenticated: """Perform tests on policies API endpoint with authentication""" - def test_get_security_measures(self, authenticated_client): + def test_get_policies(self, authenticated_client): """test to get policies from the API with authentication""" EndpointTestsQueries.Auth.get_object( @@ -111,13 +111,9 @@ def test_get_security_measures(self, authenticated_client): }, ) - def test_create_security_measures(self, authenticated_client): + def test_create_policies(self, authenticated_client): """test to create policies with the API with authentication""" - security_function = SecurityFunction.objects.create( - name="test", typical_evidence={}, folder=Folder.objects.create(name="test") - ) - EndpointTestsQueries.Auth.create_object( authenticated_client, "policies", @@ -138,13 +134,10 @@ def test_create_security_measures(self, authenticated_client): }, ) - def test_update_security_measures(self, authenticated_client): + def test_update_policies(self, authenticated_client): """test to update policies with the API with authentication""" folder = Folder.objects.create(name="test") - security_function = SecurityFunction.objects.create( - name="test", typical_evidence={}, folder=folder - ) EndpointTestsQueries.Auth.update_object( authenticated_client, @@ -175,7 +168,7 @@ def test_update_security_measures(self, authenticated_client): }, ) - def test_delete_security_measures(self, authenticated_client): + def test_delete_policies(self, authenticated_client): """test to delete policies with the API with authentication""" EndpointTestsQueries.Auth.delete_object( @@ -187,6 +180,13 @@ def test_delete_security_measures(self, authenticated_client): "folder": Folder.objects.create(name="test"), }, ) + + def test_get_category_choices(self, authenticated_client): + """test to get policies category choices from the API with authentication""" + + EndpointTestsQueries.Auth.get_object_options( + authenticated_client, "policies", "category", Policy.CATEGORY + ) def test_get_effort_choices(self, authenticated_client): """test to get policies effort choices from the API with authentication""" diff --git a/backend/app_tests/api/test_api_requirement_nodes.py b/backend/app_tests/api/test_api_requirement_nodes.py index d4a34ab4f..52c9adfb6 100644 --- a/backend/app_tests/api/test_api_requirement_nodes.py +++ b/backend/app_tests/api/test_api_requirement_nodes.py @@ -6,7 +6,7 @@ from test_api import EndpointTestsQueries, EndpointTestsUtils # Generic requirement data for tests -REQUIREMENT_NODE_NAME = "Test Requiremen Node" +REQUIREMENT_NODE_NAME = "Test Requirement Node" REQUIREMENT_NODE_DESCRIPTION = "Test Description" REQUIREMENT_NODE_URN = "urn:test:req_node.t:1" REQUIREMENT_NODE_PARENT_URN = "urn:test:req_node.t" From 608a4c97229a05f6260d2d957224db23b007f2b6 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 20 Feb 2024 11:51:05 +0100 Subject: [PATCH 02/48] fix risk acceptances skipped tests --- backend/app_tests/api/test_api_risk_acceptance.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/backend/app_tests/api/test_api_risk_acceptance.py b/backend/app_tests/api/test_api_risk_acceptance.py index 128bd7f7d..6b3cc37bd 100644 --- a/backend/app_tests/api/test_api_risk_acceptance.py +++ b/backend/app_tests/api/test_api_risk_acceptance.py @@ -7,7 +7,6 @@ RiskScenario, RiskMatrix, RiskAssessment, - Threat, ) from iam.models import Folder, UserGroup @@ -124,10 +123,6 @@ def test_get_risk_acceptances(self, authenticated_client): }, ) - @pytest.mark.skip( - reason="Everything is working fine on the API but the approver field is problematic in tests" - ) - # NOTE: It is related to roles and approver permissions somewhere in the test context def test_create_risk_acceptances(self, authenticated_client): """test to create risk acceptances with the API with authentication""" @@ -143,7 +138,6 @@ def test_create_risk_acceptances(self, authenticated_client): project=Project.objects.create(name="test", folder=folder), risk_matrix=RiskMatrix.objects.create(name="test", folder=folder), ), - threat=Threat.objects.create(name="test", folder=folder), ) EndpointTestsQueries.Auth.create_object( @@ -172,10 +166,6 @@ def test_create_risk_acceptances(self, authenticated_client): }, ) - @pytest.mark.skip( - reason="Everything is working fine on the API but the approver field is problematic in tests" - ) - # NOTE: It is related to roles and approver permissions somewhere in the test context def test_update_risk_acceptances(self, authenticated_client): """test to update risk acceptances with the API with authentication""" @@ -194,7 +184,6 @@ def test_update_risk_acceptances(self, authenticated_client): project=Project.objects.create(name="test", folder=folder2), risk_matrix=RiskMatrix.objects.create(name="test", folder=folder2), ), - threat=Threat.objects.create(name="test", folder=folder2), ) EndpointTestsQueries.Auth.update_object( From 63086d122805edf9fc8adaab09e7ab6b7a5f85f3 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 20 Feb 2024 16:51:25 +0100 Subject: [PATCH 03/48] first test of auditor permissions --- backend/app_tests/api/test_api_user_groups.py | 46 +++++++++++++++++++ backend/app_tests/conftest.py | 12 ++++- backend/core/apps.py | 3 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 backend/app_tests/api/test_api_user_groups.py diff --git a/backend/app_tests/api/test_api_user_groups.py b/backend/app_tests/api/test_api_user_groups.py new file mode 100644 index 000000000..9b1462852 --- /dev/null +++ b/backend/app_tests/api/test_api_user_groups.py @@ -0,0 +1,46 @@ +import pytest +from core.models import User +from core.models import ( + Project, + RiskAcceptance, + RiskScenario, + RiskMatrix, + RiskAssessment, +) +from iam.models import Folder, UserGroup, RoleAssignment +from test_api import EndpointTestsQueries + +@pytest.mark.django_db +class TestUserGroupsAuthenticated: + """Perform tests on User Groups API endpoint with authentication""" + + @pytest.mark.django_db + @pytest.fixture(autouse=True) + def setup(self, authenticated_client): + EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) # TODO create the folder using the DB directly instead of the API + + @pytest.mark.parametrize("authenticated_client_with_role", [{"role": "BI-UG-AUD", "folder": "test"}], indirect=True) + def test_group_auditor(self, authenticated_client_with_role): + """test that a user with the role auditor has the correct permissions""" + + user_permissions = RoleAssignment.get_permissions(User.objects.get(email="user@tests.com")) + for perm in [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + "view_requirement", + "view_evidence", + "view_framework", + ]: + assert perm in user_permissions.keys(), f"Permission {perm} not found in auditor user permissions" diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 452a051d3..53f1525ee 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -1,6 +1,6 @@ import pytest from rest_framework.test import APIClient -from iam.models import User, UserGroup +from iam.models import Folder, User, UserGroup from core.apps import startup @@ -24,3 +24,13 @@ def authenticated_client(app_config): client = APIClient() client.force_login(admin) return client + + +@pytest.fixture +def authenticated_client_with_role(app_config, request): + """Get an authenticated client with a specific role""" + user = User.objects.create_user("user@tests.com") + UserGroup.objects.get(name=request.param['role'], folder=Folder.objects.get(name=request.param['folder']).id).user_set.add(user) + client = APIClient() + client.force_login(user) + return client diff --git a/backend/core/apps.py b/backend/core/apps.py index b1b82b6bf..2403132d8 100644 --- a/backend/core/apps.py +++ b/backend/core/apps.py @@ -27,7 +27,8 @@ def startup(**kwargs): "view_securityfunction", "view_folder", "view_usergroup", - "view_riskmatrix" "view_complianceassessment", + "view_riskmatrix", + "view_complianceassessment", "view_requirementassessment", "view_requirement", "view_evidence", From b02ea9c205be4ef77573c99fdaca371a2a4ec906 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 20 Feb 2024 17:30:34 +0100 Subject: [PATCH 04/48] parametrize test_group_permissions to test all 4 user groups --- backend/app_tests/api/test_api_user_groups.py | 166 +++++++++++++++--- backend/app_tests/conftest.py | 2 +- 2 files changed, 143 insertions(+), 25 deletions(-) diff --git a/backend/app_tests/api/test_api_user_groups.py b/backend/app_tests/api/test_api_user_groups.py index 9b1462852..c24704edd 100644 --- a/backend/app_tests/api/test_api_user_groups.py +++ b/backend/app_tests/api/test_api_user_groups.py @@ -10,6 +10,141 @@ from iam.models import Folder, UserGroup, RoleAssignment from test_api import EndpointTestsQueries +groups_permissions = { + "BI-UG-AUD": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + # "view_requirement", + "view_evidence", + "view_framework", + ], + "BI-UG-VAL": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "approve_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + # "view_requirement", + "view_evidence", + "view_framework", + ], + "BI-UG-ANA": [ + "add_project", + "view_project", + "change_project", + "delete_project", + "add_riskassessment", + "view_riskassessment", + "change_riskassessment", + "delete_riskassessment", + "add_securitymeasure", + "view_securitymeasure", + "change_securitymeasure", + "delete_securitymeasure", + "add_policy", + "view_policy", + "change_policy", + "delete_policy", + "add_riskscenario", + "view_riskscenario", + "change_riskscenario", + "delete_riskscenario", + "add_riskacceptance", + "view_riskacceptance", + "change_riskacceptance", + "delete_riskacceptance", + "add_complianceassessment", + "view_complianceassessment", + "change_complianceassessment", + "delete_complianceassessment", + "view_requirementassessment", + "change_requirementassessment", + "add_evidence", + "view_evidence", + "change_evidence", + "delete_evidence", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + # "view_requirement", + "view_framework", + ], + "BI-UG-DMA": [ + "change_usergroup", + "view_usergroup", + "add_project", + "change_project", + "delete_project", + "view_project", + "add_riskassessment", + "view_riskassessment", + "change_riskassessment", + "delete_riskassessment", + "add_securitymeasure", + "view_securitymeasure", + "change_securitymeasure", + "delete_securitymeasure", + "add_policy", + "view_policy", + "change_policy", + "delete_policy", + "add_riskscenario", + "view_riskscenario", + "change_riskscenario", + "delete_riskscenario", + "add_riskacceptance", + "view_riskacceptance", + "change_riskacceptance", + "delete_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "change_folder", + "add_riskmatrix", + "view_riskmatrix", + "change_riskmatrix", + "delete_riskmatrix", + "add_complianceassessment", + "view_complianceassessment", + "change_complianceassessment", + "delete_complianceassessment", + "view_requirementassessment", + "change_requirementassessment", + "add_evidence", + "view_evidence", + "change_evidence", + "delete_evidence", + # "view_requirement", + "view_framework", + ] +} + @pytest.mark.django_db class TestUserGroupsAuthenticated: """Perform tests on User Groups API endpoint with authentication""" @@ -19,28 +154,11 @@ class TestUserGroupsAuthenticated: def setup(self, authenticated_client): EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) # TODO create the folder using the DB directly instead of the API - @pytest.mark.parametrize("authenticated_client_with_role", [{"role": "BI-UG-AUD", "folder": "test"}], indirect=True) - def test_group_auditor(self, authenticated_client_with_role): - """test that a user with the role auditor has the correct permissions""" - + @pytest.mark.parametrize("authenticated_client_with_role", [{"role": "BI-UG-AUD", "folder": "test"}, {"role": "BI-UG-VAL", "folder": "test"}, {"role": "BI-UG-ANA", "folder": "test"}, {"role": "BI-UG-DMA", "folder": "test"}], indirect=True, ids=["BI-UG-AUD", "BI-UG-VAL", "BI-UG-ANA", "BI-UG-DMA"]) + def test_group_permissions(self, authenticated_client_with_role): + """test that a user with a specific role has the correct permissions""" + + authenticated_client, params = authenticated_client_with_role user_permissions = RoleAssignment.get_permissions(User.objects.get(email="user@tests.com")) - for perm in [ - "view_project", - "view_riskassessment", - "view_securitymeasure", - "view_policy", - "view_riskscenario", - "view_riskacceptance", - "view_asset", - "view_threat", - "view_securityfunction", - "view_folder", - "view_usergroup", - "view_riskmatrix", - "view_complianceassessment", - "view_requirementassessment", - "view_requirement", - "view_evidence", - "view_framework", - ]: - assert perm in user_permissions.keys(), f"Permission {perm} not found in auditor user permissions" + for perm in groups_permissions[params["role"]]: + assert perm in user_permissions.keys(), f"Permission {perm} not found in user permissions (group: {params['role']})" diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 53f1525ee..8e54220e5 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -33,4 +33,4 @@ def authenticated_client_with_role(app_config, request): UserGroup.objects.get(name=request.param['role'], folder=Folder.objects.get(name=request.param['folder']).id).user_set.add(user) client = APIClient() client.force_login(user) - return client + return client, request.param From f4f142e109ae68b7430b203eae5be89b553f76ac Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 21 Feb 2024 17:16:48 +0100 Subject: [PATCH 05/48] rename compliance assessment file --- ...test_api_assessments.py => test_api_compliance_assessments.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/app_tests/api/{test_api_assessments.py => test_api_compliance_assessments.py} (100%) diff --git a/backend/app_tests/api/test_api_assessments.py b/backend/app_tests/api/test_api_compliance_assessments.py similarity index 100% rename from backend/app_tests/api/test_api_assessments.py rename to backend/app_tests/api/test_api_compliance_assessments.py From 0e0813acafe1f394c1fc81783fba0913e99edd01 Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 21 Feb 2024 17:18:23 +0100 Subject: [PATCH 06/48] projects api tests for 5 different user groups instead of just admin --- backend/app_tests/api/test_api.py | 17 +- backend/app_tests/api/test_api_projects.py | 23 +- backend/app_tests/api/test_api_user_groups.py | 154 +----------- backend/app_tests/conftest.py | 18 +- backend/app_tests/test_vars.py | 228 ++++++++++++++++++ 5 files changed, 276 insertions(+), 164 deletions(-) diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_api.py index 1737b1671..fec46a33e 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_api.py @@ -1,8 +1,10 @@ +import pytest import json import re from django.db.models.fields.related_descriptors import ManyToManyDescriptor from django.urls import reverse from rest_framework import status +from rest_framework.test import APIClient from ciso_assistant.settings import EMAIL_HOST, EMAIL_HOST_RESCUE from test_vars import * @@ -10,7 +12,7 @@ class EndpointTestsUtils: """Provides utils functions for API endpoints testing""" - + def get_endpoint_url(verbose_name: str, resolved: bool = True): """Get the endpoint URL for the given object""" @@ -25,6 +27,19 @@ def get_object_urn(object_name: str, resolved: bool = True): urn = get_var(urn_varname) return f"{reverse(LIBRARIES_ENDPOINT)}{urn}/" if resolved else eval(urn) + @pytest.mark.django_db + def get_test_client_and_folder(authenticated_client, role: str): + """Get an authenticated client with a specific role and the folder associated to the role""" + from iam.models import Folder, User, UserGroup + + EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) + folder = Folder.objects.get(name="test") + + user = User.objects.create_user("user@tests.com") + UserGroup.objects.get(name=role, folder=Folder.objects.get(name=GROUPS_PERMISSIONS[role]["folder"])).user_set.add(user) + client = APIClient() + client.force_login(user) + return client, folder class EndpointTestsQueries: """Provides tests functions for API endpoints testing""" diff --git a/backend/app_tests/api/test_api_projects.py b/backend/app_tests/api/test_api_projects.py index 85a4bacad..c189fdf16 100644 --- a/backend/app_tests/api/test_api_projects.py +++ b/backend/app_tests/api/test_api_projects.py @@ -1,9 +1,10 @@ import pytest from rest_framework.test import APIClient from core.models import Project -from iam.models import Folder +from iam.models import Folder, User, UserGroup -from test_api import EndpointTestsQueries +from test_vars import GROUPS_PERMISSIONS +from test_api import EndpointTestsQueries, EndpointTestsUtils # Generic project data for tests PROJECT_NAME = "Test Project" @@ -76,30 +77,32 @@ def test_delete_projects(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestProjectsAuthenticated: """Perform tests on Projects API endpoint with authentication""" - def test_get_projects(self, authenticated_client): + def test_get_projects(self, test): """test to get projects from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Projects", Project, { "name": PROJECT_NAME, "description": PROJECT_DESCRIPTION, - "folder": Folder.get_root_folder(), + "folder": test.folder, "internal_reference": PROJECT_REFERENCE, "lc_status": PROJECT_STATUS[0], }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "lc_status": PROJECT_STATUS[1], }, ) + - def test_create_projects(self, authenticated_client): + def test_create_projects(self, authenticated_client, test): """test to create projects with the API with authentication""" EndpointTestsQueries.Auth.create_object( @@ -119,7 +122,7 @@ def test_create_projects(self, authenticated_client): }, ) - def test_update_projects(self, authenticated_client): + def test_update_projects(self, authenticated_client, test): """test to update projects with the API with authentication""" status = ("in_dev", "Development") @@ -149,7 +152,7 @@ def test_update_projects(self, authenticated_client): }, ) - def test_delete_projects(self, authenticated_client): + def test_delete_projects(self, authenticated_client, test): """test to delete projects with the API with authentication""" EndpointTestsQueries.Auth.delete_object( @@ -159,7 +162,7 @@ def test_delete_projects(self, authenticated_client): {"name": PROJECT_NAME, "folder": Folder.get_root_folder()}, ) - def test_get_status_choices(self, authenticated_client): + def test_get_status_choices(self, authenticated_client, test): """test to get projects status choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( diff --git a/backend/app_tests/api/test_api_user_groups.py b/backend/app_tests/api/test_api_user_groups.py index c24704edd..6d78fea96 100644 --- a/backend/app_tests/api/test_api_user_groups.py +++ b/backend/app_tests/api/test_api_user_groups.py @@ -1,158 +1,18 @@ import pytest from core.models import User -from core.models import ( - Project, - RiskAcceptance, - RiskScenario, - RiskMatrix, - RiskAssessment, -) + from iam.models import Folder, UserGroup, RoleAssignment +from test_vars import GROUPS_PERMISSIONS from test_api import EndpointTestsQueries -groups_permissions = { - "BI-UG-AUD": [ - "view_project", - "view_riskassessment", - "view_securitymeasure", - "view_policy", - "view_riskscenario", - "view_riskacceptance", - "view_asset", - "view_threat", - "view_securityfunction", - "view_folder", - "view_usergroup", - "view_riskmatrix", - "view_complianceassessment", - "view_requirementassessment", - # "view_requirement", - "view_evidence", - "view_framework", - ], - "BI-UG-VAL": [ - "view_project", - "view_riskassessment", - "view_securitymeasure", - "view_policy", - "view_riskscenario", - "view_riskacceptance", - "approve_riskacceptance", - "view_asset", - "view_threat", - "view_securityfunction", - "view_folder", - "view_usergroup", - "view_riskmatrix", - "view_complianceassessment", - "view_requirementassessment", - # "view_requirement", - "view_evidence", - "view_framework", - ], - "BI-UG-ANA": [ - "add_project", - "view_project", - "change_project", - "delete_project", - "add_riskassessment", - "view_riskassessment", - "change_riskassessment", - "delete_riskassessment", - "add_securitymeasure", - "view_securitymeasure", - "change_securitymeasure", - "delete_securitymeasure", - "add_policy", - "view_policy", - "change_policy", - "delete_policy", - "add_riskscenario", - "view_riskscenario", - "change_riskscenario", - "delete_riskscenario", - "add_riskacceptance", - "view_riskacceptance", - "change_riskacceptance", - "delete_riskacceptance", - "add_complianceassessment", - "view_complianceassessment", - "change_complianceassessment", - "delete_complianceassessment", - "view_requirementassessment", - "change_requirementassessment", - "add_evidence", - "view_evidence", - "change_evidence", - "delete_evidence", - "view_asset", - "view_threat", - "view_securityfunction", - "view_folder", - "view_usergroup", - "view_riskmatrix", - # "view_requirement", - "view_framework", - ], - "BI-UG-DMA": [ - "change_usergroup", - "view_usergroup", - "add_project", - "change_project", - "delete_project", - "view_project", - "add_riskassessment", - "view_riskassessment", - "change_riskassessment", - "delete_riskassessment", - "add_securitymeasure", - "view_securitymeasure", - "change_securitymeasure", - "delete_securitymeasure", - "add_policy", - "view_policy", - "change_policy", - "delete_policy", - "add_riskscenario", - "view_riskscenario", - "change_riskscenario", - "delete_riskscenario", - "add_riskacceptance", - "view_riskacceptance", - "change_riskacceptance", - "delete_riskacceptance", - "view_asset", - "view_threat", - "view_securityfunction", - "view_folder", - "change_folder", - "add_riskmatrix", - "view_riskmatrix", - "change_riskmatrix", - "delete_riskmatrix", - "add_complianceassessment", - "view_complianceassessment", - "change_complianceassessment", - "delete_complianceassessment", - "view_requirementassessment", - "change_requirementassessment", - "add_evidence", - "view_evidence", - "change_evidence", - "delete_evidence", - # "view_requirement", - "view_framework", - ] -} - @pytest.mark.django_db -class TestUserGroupsAuthenticated: +class TestUserGroups: """Perform tests on User Groups API endpoint with authentication""" @pytest.mark.django_db @pytest.fixture(autouse=True) def setup(self, authenticated_client): - EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) # TODO create the folder using the DB directly instead of the API + EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) @pytest.mark.parametrize("authenticated_client_with_role", [{"role": "BI-UG-AUD", "folder": "test"}, {"role": "BI-UG-VAL", "folder": "test"}, {"role": "BI-UG-ANA", "folder": "test"}, {"role": "BI-UG-DMA", "folder": "test"}], indirect=True, ids=["BI-UG-AUD", "BI-UG-VAL", "BI-UG-ANA", "BI-UG-DMA"]) def test_group_permissions(self, authenticated_client_with_role): @@ -160,5 +20,9 @@ def test_group_permissions(self, authenticated_client_with_role): authenticated_client, params = authenticated_client_with_role user_permissions = RoleAssignment.get_permissions(User.objects.get(email="user@tests.com")) - for perm in groups_permissions[params["role"]]: + for perm in GROUPS_PERMISSIONS[params["role"]]: assert perm in user_permissions.keys(), f"Permission {perm} not found in user permissions (group: {params['role']})" + +@pytest.mark.django_db +class TestUserPermissions: + pass \ No newline at end of file diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 8e54220e5..91f1f2ebd 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -1,8 +1,13 @@ import pytest from rest_framework.test import APIClient -from iam.models import Folder, User, UserGroup +from api.test_api import EndpointTestsUtils +from iam.models import User, UserGroup from core.apps import startup +class Test(dict): + def __init__(self, *args, **kwargs): + super(Test, self).__init__(*args, **kwargs) + self.__dict__ = self @pytest.fixture def app_config(): @@ -27,10 +32,7 @@ def authenticated_client(app_config): @pytest.fixture -def authenticated_client_with_role(app_config, request): - """Get an authenticated client with a specific role""" - user = User.objects.create_user("user@tests.com") - UserGroup.objects.get(name=request.param['role'], folder=Folder.objects.get(name=request.param['folder']).id).user_set.add(user) - client = APIClient() - client.force_login(user) - return client, request.param +def test(authenticated_client, request): + """Get the elements used by the tests such as client and associated folder""" + client, folder = EndpointTestsUtils.get_test_client_and_folder(authenticated_client, request.param) + return Test({"client": client, "authenticated_client": authenticated_client, "folder": folder, "user_group": request.param}) \ No newline at end of file diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index a2bd354ca..90c50c6a4 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -28,6 +28,234 @@ TEST_RISK_MATRIX2_URN = "urn:intuitem:risk:library:critical_risk_matrix_5x5" TEST_REQUIREMENT_NODE_URN = "urn:intuitem:risk:req_node:nist-csf-1.1:rs.an-1" +GROUPS_PERMISSIONS = { + "BI-UG-ADM": { + "folder": "Global", + "name": "Global administrator", + "perms": [ + "add_user", + "view_user", + "change_user", + "delete_user", + "add_usergroup", + "view_usergroup", + "change_usergroup", + "delete_usergroup", + "add_event", + "view_event", + "change_event", + "delete_event", + "add_asset", + "view_asset", + "change_asset", + "delete_asset", + "add_threat", + "view_threat", + "change_threat", + "delete_threat", + "add_securityfunction", + "view_securityfunction", + "change_securityfunction", + "delete_securityfunction", + "add_folder", + "change_folder", + "view_folder", + "delete_folder", + "add_project", + "change_project", + "delete_project", + "view_project", + "add_riskassessment", + "view_riskassessment", + "change_riskassessment", + "delete_riskassessment", + "add_securitymeasure", + "view_securitymeasure", + "change_securitymeasure", + "delete_securitymeasure", + "add_policy", + "view_policy", + "change_policy", + "delete_policy", + "add_riskscenario", + "view_riskscenario", + "change_riskscenario", + "delete_riskscenario", + "add_riskacceptance", + "view_riskacceptance", + "change_riskacceptance", + "delete_riskacceptance", + "approve_riskacceptance", + "add_riskmatrix", + "view_riskmatrix", + "change_riskmatrix", + "delete_riskmatrix", + "add_complianceassessment", + "view_complianceassessment", + "change_complianceassessment", + "delete_complianceassessment", + "view_requirementassessment", + "change_requirementassessment", + "add_evidence", + "view_evidence", + "change_evidence", + "delete_evidence", + "add_framework", + "view_framework", + "delete_framework", + "view_requirementnode", + "view_requirementlevel", # Permits to see the object on api by an admin + "delete_library", + "backup", + "restore", + ] + }, + "BI-UG-AUD": { + "folder": "test", + "name": "Auditor", + "perms": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + "view_evidence", + "view_framework", + ] + }, + "BI-UG-VAL": { + "folder": "test", + "name": "Validator", + "perms": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "approve_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + "view_evidence", + "view_framework", + ] + }, + "BI-UG-ANA": { + "folder": "test", + "name": "Analyst", + "perms": [ + "add_project", + "view_project", + "change_project", + "delete_project", + "add_riskassessment", + "view_riskassessment", + "change_riskassessment", + "delete_riskassessment", + "add_securitymeasure", + "view_securitymeasure", + "change_securitymeasure", + "delete_securitymeasure", + "add_policy", + "view_policy", + "change_policy", + "delete_policy", + "add_riskscenario", + "view_riskscenario", + "change_riskscenario", + "delete_riskscenario", + "add_riskacceptance", + "view_riskacceptance", + "change_riskacceptance", + "delete_riskacceptance", + "add_complianceassessment", + "view_complianceassessment", + "change_complianceassessment", + "delete_complianceassessment", + "view_requirementassessment", + "change_requirementassessment", + "add_evidence", + "view_evidence", + "change_evidence", + "delete_evidence", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_framework", + ] + }, + "BI-UG-DMA": { + "folder": "test", + "name": "Domain Manager", + "perms": [ + "change_usergroup", + "view_usergroup", + "add_project", + "change_project", + "delete_project", + "view_project", + "add_riskassessment", + "view_riskassessment", + "change_riskassessment", + "delete_riskassessment", + "add_securitymeasure", + "view_securitymeasure", + "change_securitymeasure", + "delete_securitymeasure", + "add_policy", + "view_policy", + "change_policy", + "delete_policy", + "add_riskscenario", + "view_riskscenario", + "change_riskscenario", + "delete_riskscenario", + "add_riskacceptance", + "view_riskacceptance", + "change_riskacceptance", + "delete_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "change_folder", + "add_riskmatrix", + "view_riskmatrix", + "change_riskmatrix", + "delete_riskmatrix", + "add_complianceassessment", + "view_complianceassessment", + "change_complianceassessment", + "delete_complianceassessment", + "view_requirementassessment", + "change_requirementassessment", + "add_evidence", + "view_evidence", + "change_evidence", + "delete_evidence", + "view_framework", + ] + }, +} + __globals__ = globals() From 4766d2448e173636d22a28444aff242e2cd70c84 Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 21 Feb 2024 18:25:08 +0100 Subject: [PATCH 07/48] rename risk acceptances --- .../{test_api_risk_acceptance.py => test_api_risk_acceptances.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/app_tests/api/{test_api_risk_acceptance.py => test_api_risk_acceptances.py} (100%) diff --git a/backend/app_tests/api/test_api_risk_acceptance.py b/backend/app_tests/api/test_api_risk_acceptances.py similarity index 100% rename from backend/app_tests/api/test_api_risk_acceptance.py rename to backend/app_tests/api/test_api_risk_acceptances.py From aa5f82c68c957a8cbe87030f32aaf191bf765c03 Mon Sep 17 00:00:00 2001 From: Alexis Date: Wed, 21 Feb 2024 18:25:51 +0100 Subject: [PATCH 08/48] add expected result for each test with different user groups --- backend/app_tests/api/test_api.py | 48 ++++++++++++++++++---- backend/app_tests/api/test_api_projects.py | 32 ++++++++------- backend/app_tests/conftest.py | 2 +- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_api.py index fec46a33e..f51c13d4a 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_api.py @@ -40,6 +40,19 @@ def get_test_client_and_folder(authenticated_client, role: str): client = APIClient() client.force_login(user) return client, folder + + def expected_request_response(action: str, object: str, user_group, expected_status: int = status.HTTP_200_OK): + """Get the expected request response""" + perm_name = f"{action}_{object.lower().replace(' ', '')[:-1]}" + + if perm_name in GROUPS_PERMISSIONS[user_group]['perms']: + fails = False + expected_status = expected_status + else: + fails = True + expected_status = status.HTTP_403_FORBIDDEN + print(object, user_group, perm_name, fails, expected_status) + return fails, expected_status class EndpointTestsQueries: """Provides tests functions for API endpoints testing""" @@ -277,6 +290,7 @@ def get_object( endpoint: str = None, fails: bool = False, expected_status: int = status.HTTP_200_OK, + user_group: str = None, ): """Test to get object from the API with authentication @@ -290,6 +304,9 @@ def get_object( :param endpoint: the endpoint URL of the object to test (optional) """ + if user_group and not fails: + fails, expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) + url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) # Uses the API endpoint to assert that objects are accessible @@ -377,6 +394,7 @@ def get_object_options( endpoint: str = None, fails: bool = False, expected_status: int = status.HTTP_200_OK, + user_group: str = None, ): """Test to get object options from the API with authentication @@ -386,6 +404,8 @@ def get_object_options( :param option: the option to test :param endpoint: the endpoint URL of the object to test (optional) """ + if user_group and not fails: + fails, expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) @@ -416,6 +436,7 @@ def create_object( query_format: str = "json", fails: bool = False, expected_status: int = status.HTTP_201_CREATED, + user_group: str = None, ): """Test to create object with the API with authentication @@ -428,6 +449,8 @@ def create_object( -1 means that the number of objects is unknown :param endpoint: the endpoint URL of the object to test (optional) """ + if user_group and not fails: + fails, expected_status = EndpointTestsUtils.expected_request_response("add", verbose_name, user_group, expected_status) url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) @@ -444,7 +467,7 @@ def create_object( # Asserts that the object was created successfully assert ( response.status_code == expected_status - ), f"{verbose_name} can not be created with authentication" + ), f"{verbose_name} can not be created with authentication" if expected_status == status.HTTP_201_CREATED else f"{verbose_name} should not be created (expected status: {expected_status})" for key, value in build_params.items(): if key == "attachment": @@ -500,6 +523,7 @@ def update_object( query_format: str = "json", fails: bool = False, expected_status: int = status.HTTP_200_OK, + user_group: str = None, ): """Test to update object with the API with authentication @@ -511,6 +535,9 @@ def update_object( the test_params can ovveride the build_params :param endpoint: the endpoint URL of the object to test (optional) """ + + if user_group and not fails: + fails, expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group) # Creates a test object from the model m2m_fields = {} @@ -558,7 +585,7 @@ def update_object( assert ( update_response.status_code == expected_status - ), f"{verbose_name} can not be updated with authentication" + ), f"{verbose_name} can not be updated with authentication" if expected_status == status.HTTP_201_CREATED else f"{verbose_name} should not be updated (expected status: {expected_status})" for key, value in {**build_params, **update_params, **test_params}.items(): if not fails: if key == "attachment" and update_response.json()[key] != value: @@ -580,6 +607,7 @@ def delete_object( endpoint: str = None, fails: bool = False, expected_status: int = status.HTTP_204_NO_CONTENT, + user_group: str = None, ): """Test to delete object with the API with authentication @@ -589,6 +617,9 @@ def delete_object( :param endpoint: the endpoint URL of the object to test (optional) """ + if user_group and not fails: + fails, expected_status = EndpointTestsUtils.expected_request_response("delete", verbose_name, user_group, expected_status) + if build_params: # Creates a test object from the model m2m_fields = {} @@ -624,13 +655,14 @@ def delete_object( delete_response = authenticated_client.delete(url) assert ( delete_response.status_code == expected_status - ), f"{verbose_name} can not be deleted with authentication" + ), f"{verbose_name} can not be deleted with authentication" if expected_status == status.HTTP_204_NO_CONTENT else f"{verbose_name} should not be deleted (expected status: {expected_status})" - # Asserts that the objects does not exists anymore - response = authenticated_client.get(url) - assert ( - response.status_code == status.HTTP_404_NOT_FOUND - ), f"{verbose_name} has not been properly deleted with authentication" + if not fails: + # Asserts that the objects does not exists anymore + response = authenticated_client.get(url) + assert ( + response.status_code == status.HTTP_404_NOT_FOUND + ), f"{verbose_name} has not been properly deleted with authentication" def import_object( authenticated_client, diff --git a/backend/app_tests/api/test_api_projects.py b/backend/app_tests/api/test_api_projects.py index c189fdf16..bea996d20 100644 --- a/backend/app_tests/api/test_api_projects.py +++ b/backend/app_tests/api/test_api_projects.py @@ -99,43 +99,45 @@ def test_get_projects(self, test): "folder": {"id": str(test.folder.id), "str": test.folder.name}, "lc_status": PROJECT_STATUS[1], }, + user_group=test.user_group, ) - def test_create_projects(self, authenticated_client, test): + def test_create_projects(self, test): """test to create projects with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Projects", Project, { "name": PROJECT_NAME, "description": PROJECT_DESCRIPTION, - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), "internal_reference": PROJECT_REFERENCE, "lc_status": PROJECT_STATUS[0], }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "lc_status": PROJECT_STATUS[1], }, + user_group=test.user_group, ) - def test_update_projects(self, authenticated_client, test): + def test_update_projects(self, test): """test to update projects with the API with authentication""" status = ("in_dev", "Development") - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Projects", Project, { "name": PROJECT_NAME, "description": PROJECT_DESCRIPTION, - "folder": Folder.get_root_folder(), + "folder": test.folder, "internal_reference": PROJECT_REFERENCE, "lc_status": PROJECT_STATUS[0], }, @@ -147,24 +149,26 @@ def test_update_projects(self, authenticated_client, test): "lc_status": status[0], }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "lc_status": PROJECT_STATUS[1], }, + user_group=test.user_group, ) - def test_delete_projects(self, authenticated_client, test): + def test_delete_projects(self, test): """test to delete projects with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Projects", Project, - {"name": PROJECT_NAME, "folder": Folder.get_root_folder()}, + {"name": PROJECT_NAME, "folder": test.folder}, + user_group=test.user_group, ) - def test_get_status_choices(self, authenticated_client, test): + def test_get_status_choices(self, test): """test to get projects status choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, "Projects", "lc_status", Project.PRJ_LC_STATUS + test.client, "Projects", "lc_status", Project.PRJ_LC_STATUS ) diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 91f1f2ebd..17c15c9d6 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -32,7 +32,7 @@ def authenticated_client(app_config): @pytest.fixture -def test(authenticated_client, request): +def test(authenticated_client, request) -> Test: """Get the elements used by the tests such as client and associated folder""" client, folder = EndpointTestsUtils.get_test_client_and_folder(authenticated_client, request.param) return Test({"client": client, "authenticated_client": authenticated_client, "folder": folder, "user_group": request.param}) \ No newline at end of file From ad538025e51c8e9570af0ef229a2e93a7bab0baa Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 10:49:38 +0100 Subject: [PATCH 09/48] fix api user groups --- backend/app_tests/api/test_api.py | 3 +-- backend/app_tests/api/test_api_user_groups.py | 22 +++++-------------- backend/app_tests/test_vars.py | 1 + 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_api.py index f51c13d4a..127353d11 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_api.py @@ -35,7 +35,7 @@ def get_test_client_and_folder(authenticated_client, role: str): EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) folder = Folder.objects.get(name="test") - user = User.objects.create_user("user@tests.com") + user = User.objects.create_user(TEST_USER_EMAIL) UserGroup.objects.get(name=role, folder=Folder.objects.get(name=GROUPS_PERMISSIONS[role]["folder"])).user_set.add(user) client = APIClient() client.force_login(user) @@ -51,7 +51,6 @@ def expected_request_response(action: str, object: str, user_group, expected_sta else: fails = True expected_status = status.HTTP_403_FORBIDDEN - print(object, user_group, perm_name, fails, expected_status) return fails, expected_status class EndpointTestsQueries: diff --git a/backend/app_tests/api/test_api_user_groups.py b/backend/app_tests/api/test_api_user_groups.py index 6d78fea96..9b988dde6 100644 --- a/backend/app_tests/api/test_api_user_groups.py +++ b/backend/app_tests/api/test_api_user_groups.py @@ -2,27 +2,17 @@ from core.models import User from iam.models import Folder, UserGroup, RoleAssignment -from test_vars import GROUPS_PERMISSIONS +from test_vars import GROUPS_PERMISSIONS, TEST_USER_EMAIL from test_api import EndpointTestsQueries @pytest.mark.django_db class TestUserGroups: """Perform tests on User Groups API endpoint with authentication""" - @pytest.mark.django_db - @pytest.fixture(autouse=True) - def setup(self, authenticated_client): - EndpointTestsQueries.Auth.create_object(authenticated_client, "Folders", Folder, {"name": "test"}) - - @pytest.mark.parametrize("authenticated_client_with_role", [{"role": "BI-UG-AUD", "folder": "test"}, {"role": "BI-UG-VAL", "folder": "test"}, {"role": "BI-UG-ANA", "folder": "test"}, {"role": "BI-UG-DMA", "folder": "test"}], indirect=True, ids=["BI-UG-AUD", "BI-UG-VAL", "BI-UG-ANA", "BI-UG-DMA"]) - def test_group_permissions(self, authenticated_client_with_role): + @pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) + def test_group_permissions(self, test): """test that a user with a specific role has the correct permissions""" - authenticated_client, params = authenticated_client_with_role - user_permissions = RoleAssignment.get_permissions(User.objects.get(email="user@tests.com")) - for perm in GROUPS_PERMISSIONS[params["role"]]: - assert perm in user_permissions.keys(), f"Permission {perm} not found in user permissions (group: {params['role']})" - -@pytest.mark.django_db -class TestUserPermissions: - pass \ No newline at end of file + user_permissions = RoleAssignment.get_permissions(User.objects.get(email=TEST_USER_EMAIL)) + for perm in GROUPS_PERMISSIONS[test.user_group]['perms']: + assert perm in user_permissions.keys(), f"Permission {perm} not found in user permissions (group: {test.user_group})" diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index 90c50c6a4..b04597090 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -28,6 +28,7 @@ TEST_RISK_MATRIX2_URN = "urn:intuitem:risk:library:critical_risk_matrix_5x5" TEST_REQUIREMENT_NODE_URN = "urn:intuitem:risk:req_node:nist-csf-1.1:rs.an-1" +TEST_USER_EMAIL = "user@tests.com" GROUPS_PERMISSIONS = { "BI-UG-ADM": { "folder": "Global", From ab859f3c7a88e58fc7bad67eb7aa103c3f313db3 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 10:58:19 +0100 Subject: [PATCH 10/48] add test user groups global auditors and global validators --- backend/app_tests/test_vars.py | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index b04597090..a05176c99 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -111,6 +111,51 @@ "restore", ] }, + "BI-UG-GAD": { + "folder": "Global", + "name": "Global auditor", + "perms": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + "view_evidence", + "view_framework", + ] + }, + "BI-UG-GVA": { + "folder": "Global", + "name": "Global validator", + "perms": [ + "view_project", + "view_riskassessment", + "view_securitymeasure", + "view_policy", + "view_riskscenario", + "view_riskacceptance", + "approve_riskacceptance", + "view_asset", + "view_threat", + "view_securityfunction", + "view_folder", + "view_usergroup", + "view_riskmatrix", + "view_complianceassessment", + "view_requirementassessment", + "view_evidence", + "view_framework", + ] + }, "BI-UG-AUD": { "folder": "test", "name": "Auditor", From 3e02afcdd6e429b74ebdd39577f8db41093331f2 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 11:12:09 +0100 Subject: [PATCH 11/48] add assets api tests for the other user groups --- backend/app_tests/api/test_api_assets.py | 57 ++++++++++++---------- backend/app_tests/api/test_api_projects.py | 4 +- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/backend/app_tests/api/test_api_assets.py b/backend/app_tests/api/test_api_assets.py index 48e12bf1c..15eb26149 100644 --- a/backend/app_tests/api/test_api_assets.py +++ b/backend/app_tests/api/test_api_assets.py @@ -3,6 +3,7 @@ from core.models import Asset from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_api import EndpointTestsQueries # Generic asset data for tests @@ -78,14 +79,15 @@ def test_delete_assets(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestAssetsAuthenticated: """Perform tests on Assets API endpoint with authentication""" - def test_get_assets(self, authenticated_client): + def test_get_assets(self, test): """test to get assets from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Assets", Asset, { @@ -93,16 +95,17 @@ def test_get_assets(self, authenticated_client): "description": ASSET_DESCRIPTION, "business_value": ASSET_BUSINESS_VALUE, "type": ASSET_TYPE[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, - {"folder": {"str": Folder.get_root_folder().name}, "type": ASSET_TYPE[1]}, + {"folder": {"id": str(test.folder.id), "str": test.folder.name}, "type": ASSET_TYPE[1]}, + user_group=test.user_group, ) - def test_create_assets(self, authenticated_client): - """test to create assets with the API with authentication""" + def test_create_assets(self, test): + """test to create assets without a parent asset the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Assets", Asset, { @@ -111,23 +114,24 @@ def test_create_assets(self, authenticated_client): "business_value": ASSET_BUSINESS_VALUE, "type": ASSET_TYPE[0], "parent_assets": [], - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, - {"folder": {"str": Folder.get_root_folder().name}, "type": ASSET_TYPE[1]}, + {"folder": {"id": str(test.folder.id), "str": test.folder.name}, "type": ASSET_TYPE[1]}, + user_group=test.user_group, ) - def test_create_assets2(self, authenticated_client): - """test to create assets with the API with authentication""" + def test_create_assets_with_parent(self, test): + """test to create assets with a parent asset with the API with authentication""" root_asset = Asset.objects.create( name="root", description=ASSET_DESCRIPTION, type=ASSET_TYPE[0], - folder=Folder.get_root_folder(), + folder=test.folder, ) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Assets", Asset, { @@ -136,23 +140,24 @@ def test_create_assets2(self, authenticated_client): "business_value": ASSET_BUSINESS_VALUE, "type": ASSET_TYPE2[0], "parent_assets": [str(root_asset.id)], - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "type": ASSET_TYPE2[1], "parent_assets": [{"id": str(root_asset.id), "str": root_asset.name}], }, base_count=1, + user_group=test.user_group, ) - def test_update_assets(self, authenticated_client): + def test_update_assets(self, test): """test to update assets with the API with authentication""" - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Assets", Asset, { @@ -160,7 +165,7 @@ def test_update_assets(self, authenticated_client): "description": ASSET_DESCRIPTION, "business_value": ASSET_BUSINESS_VALUE, "type": ASSET_TYPE[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, { "name": "new " + ASSET_NAME, @@ -169,22 +174,24 @@ def test_update_assets(self, authenticated_client): "type": ASSET_TYPE2[0], "folder": str(folder.id), }, - {"folder": {"str": Folder.get_root_folder().name}, "type": ASSET_TYPE[1]}, + {"folder": {"id": str(test.folder.id), "str": test.folder.name}, "type": ASSET_TYPE[1]}, + user_group=test.user_group, ) - def test_delete_assets(self, authenticated_client): + def test_delete_assets(self, test): """test to delete assets with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Assets", Asset, - {"name": ASSET_NAME, "folder": Folder.get_root_folder()}, + {"name": ASSET_NAME, "folder": test.folder}, + user_group=test.user_group, ) - def test_get_type_choices(self, authenticated_client): + def test_get_type_choices(self, test): """test to get type choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, "Assets", "type", Asset.Type.choices + test.client, "Assets", "type", Asset.Type.choices ) diff --git a/backend/app_tests/api/test_api_projects.py b/backend/app_tests/api/test_api_projects.py index bea996d20..57ae05e45 100644 --- a/backend/app_tests/api/test_api_projects.py +++ b/backend/app_tests/api/test_api_projects.py @@ -1,10 +1,10 @@ import pytest from rest_framework.test import APIClient from core.models import Project -from iam.models import Folder, User, UserGroup +from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries, EndpointTestsUtils +from test_api import EndpointTestsQueries # Generic project data for tests PROJECT_NAME = "Test Project" From 6a99a47e71ce0cca5427cab118631f511f0e706b Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 12:58:30 +0100 Subject: [PATCH 12/48] add threats api tests for the other user groups --- backend/app_tests/api/test_api.py | 86 ++++++++++++++--------- backend/app_tests/api/test_api_threats.py | 43 +++++++----- 2 files changed, 81 insertions(+), 48 deletions(-) diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_api.py index 127353d11..472302930 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_api.py @@ -448,8 +448,9 @@ def create_object( -1 means that the number of objects is unknown :param endpoint: the endpoint URL of the object to test (optional) """ - if user_group and not fails: - fails, expected_status = EndpointTestsUtils.expected_request_response("add", verbose_name, user_group, expected_status) + user_perm_fails, user_perm_expected_status = None, 0 + if user_group: + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("add", verbose_name, user_group, expected_status) url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) @@ -464,10 +465,17 @@ def create_object( return # Asserts that the object was created successfully - assert ( - response.status_code == expected_status - ), f"{verbose_name} can not be created with authentication" if expected_status == status.HTTP_201_CREATED else f"{verbose_name} should not be created (expected status: {expected_status})" - + if not user_group or user_perm_expected_status == status.HTTP_201_CREATED: + # User has permission to create the object + assert ( + response.status_code == expected_status + ), f"{verbose_name} can not be created with authentication" if expected_status == status.HTTP_201_CREATED else f"{verbose_name} should not be created (expected status: {expected_status})" + else: + # User does not have permission to create the object + assert ( + response.status_code == user_perm_expected_status + ), f"{verbose_name} can be created without permission" if expected_status == status.HTTP_201_CREATED else f"Creating {verbose_name.lower()} should give a status {user_perm_expected_status}" + for key, value in build_params.items(): if key == "attachment": # Asserts that the value file name is present in the JSON response @@ -492,23 +500,24 @@ def create_object( ), f"{verbose_name} are not accessible with authentication" for key, value in {**build_params, **test_params}.items(): - if ( - key == "attachment" - and response.json()["results"][base_count][key] != value - ): - # Asserts that the value file name is present in the JSON response - assert ( - re.sub( - r"_([a-z]|[A-Z]|[0-9]){7}(?:\.)", - ".", - response.json()["results"][base_count][key], - ) - == value - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" - else: - assert ( - response.json()["results"][base_count][key] == value - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + if not (fails or user_perm_fails): + if ( + key == "attachment" + and response.json()["results"][base_count][key] != value + ): + # Asserts that the value file name is present in the JSON response + assert ( + re.sub( + r"_([a-z]|[A-Z]|[0-9]){7}(?:\.)", + ".", + response.json()["results"][base_count][key], + ) + == value + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + else: + assert ( + response.json()["results"][base_count][key] == value + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" def update_object( authenticated_client, @@ -535,8 +544,8 @@ def update_object( :param endpoint: the endpoint URL of the object to test (optional) """ - if user_group and not fails: - fails, expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group) + if user_group: + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group) # Creates a test object from the model m2m_fields = {} @@ -564,9 +573,15 @@ def update_object( response = authenticated_client.get(url) - assert ( - response.status_code == status.HTTP_200_OK - ), f"{verbose_name} can not be updated with authentication" + if not user_group or EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) == (False, status.HTTP_200_OK): + assert ( + response.status_code == status.HTTP_200_OK + ), f"{verbose_name} object detail can not be accessed with permission" + else: + assert ( + response.status_code == status.HTTP_403_FORBIDDEN + ), f"{verbose_name} object detail can be accessed without permission" + for key, value in {**build_params, **test_build_params}.items(): if key == "attachment": # Asserts that the value file name is present in the JSON response @@ -582,11 +597,18 @@ def update_object( url, update_params, format=query_format ) - assert ( - update_response.status_code == expected_status - ), f"{verbose_name} can not be updated with authentication" if expected_status == status.HTTP_201_CREATED else f"{verbose_name} should not be updated (expected status: {expected_status})" + if not user_group or user_perm_expected_status == status.HTTP_200_OK: + # User has permission to update the object + assert ( + update_response.status_code == expected_status + ), f"{verbose_name} can not be updated with authentication" if expected_status == status.HTTP_200_OK else f"{verbose_name} should not be updated (expected status: {expected_status})" + else: + # User does not have permission to update the object + assert ( + update_response.status_code == user_perm_expected_status + ), f"{verbose_name} can be updated without permission" if expected_status == status.HTTP_200_OK else f"Updating {verbose_name.lower()} should give a status {user_perm_expected_status}" for key, value in {**build_params, **update_params, **test_params}.items(): - if not fails: + if not (fails or user_perm_fails): if key == "attachment" and update_response.json()[key] != value: # Asserts that the value file name is present in the JSON response assert ( diff --git a/backend/app_tests/api/test_api_threats.py b/backend/app_tests/api/test_api_threats.py index 75558941e..374384d81 100644 --- a/backend/app_tests/api/test_api_threats.py +++ b/backend/app_tests/api/test_api_threats.py @@ -4,6 +4,7 @@ from core.models import Threat from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_api import EndpointTestsQueries # Generic threat data for tests @@ -88,14 +89,15 @@ def test_delete_threats(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestThreatsAuthenticated: """Perform tests on Threats API endpoint with authentication""" - def test_get_threats(self, authenticated_client): + def test_get_threats(self, test): """test to get threats from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Threats", Threat, { @@ -108,13 +110,14 @@ def test_get_threats(self, authenticated_client): { "folder": {"str": Folder.get_root_folder().name}, }, + user_group=test.user_group, ) - def test_create_threats(self, authenticated_client): + def test_create_threats(self, test): """test to create threats with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Threats", Threat, { @@ -122,20 +125,21 @@ def test_create_threats(self, authenticated_client): "name": THREAT_NAME, "description": THREAT_DESCRIPTION, "provider": THREAT_PROVIDER, - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "urn": None, }, + user_group=test.user_group, ) - def test_update_threats_with_url(self, authenticated_client): + def test_update_threats_with_url(self, test): """test to update imported threat (with URN) with the API with authentication""" - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Threats", Threat, { @@ -154,16 +158,17 @@ def test_update_threats_with_url(self, authenticated_client): "folder": str(folder.id), }, fails=True, - expected_status=HTTP_400_BAD_REQUEST, + expected_status=HTTP_400_BAD_REQUEST, # Imported objects cannot be modified + user_group=test.user_group, ) - def test_update_threats(self, authenticated_client): + def test_update_threats(self, test): """test to update threats with the API with authentication""" - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Threats", Threat, { @@ -171,6 +176,7 @@ def test_update_threats(self, authenticated_client): "name": THREAT_NAME, "description": THREAT_DESCRIPTION, "provider": THREAT_PROVIDER, + "folder": test.folder }, { "ref_id": "new " + THREAT_REF_ID, @@ -179,14 +185,19 @@ def test_update_threats(self, authenticated_client): "provider": "new " + THREAT_PROVIDER, "folder": str(folder.id), }, + { + "folder": {"id": str(test.folder.id), "str": test.folder.name}, + }, + user_group=test.user_group, ) - def test_delete_threats(self, authenticated_client): + def test_delete_threats(self, test): """test to delete threats with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Threats", Threat, - {"name": THREAT_NAME, "folder": Folder.objects.create(name="test")}, + {"name": THREAT_NAME, "folder": test.folder}, + user_group=test.user_group, ) From cb7e1d928d7cc0724749e5981497b1f1a2577e64 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 14:59:40 +0100 Subject: [PATCH 13/48] add compliance assessments api tests for the other user groups --- backend/app_tests/api/test_api.py | 5 ++- .../api/test_api_compliance_assessments.py | 42 +++++++++++-------- backend/app_tests/conftest.py | 2 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_api.py index 472302930..ec164f4bf 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_api.py @@ -543,7 +543,8 @@ def update_object( the test_params can ovveride the build_params :param endpoint: the endpoint URL of the object to test (optional) """ - + user_perm_fails, user_perm_expected_status = None, 0 + if user_group: user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group) @@ -581,7 +582,7 @@ def update_object( assert ( response.status_code == status.HTTP_403_FORBIDDEN ), f"{verbose_name} object detail can be accessed without permission" - + for key, value in {**build_params, **test_build_params}.items(): if key == "attachment": # Asserts that the value file name is present in the JSON response diff --git a/backend/app_tests/api/test_api_compliance_assessments.py b/backend/app_tests/api/test_api_compliance_assessments.py index 6fa9ed4d8..0cc59bac7 100644 --- a/backend/app_tests/api/test_api_compliance_assessments.py +++ b/backend/app_tests/api/test_api_compliance_assessments.py @@ -4,6 +4,7 @@ from core.models import Project from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_api import EndpointTestsQueries # Generic compliance assessment data for tests @@ -96,19 +97,20 @@ def test_delete_compliance_assessments(self, authenticated_client): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestComplianceAssessmentsAuthenticated: """Perform tests on ComplianceAssessments API endpoint with authentication""" - def test_get_compliance_assessments(self, authenticated_client): + def test_get_compliance_assessments(self, test): """test to get compliance assessments from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Compliance Assessments", ComplianceAssessment, { @@ -125,18 +127,19 @@ def test_get_compliance_assessments(self, authenticated_client): "str": str(Framework.objects.all()[0]), }, }, + user_group=test.user_group, ) - def test_create_compliance_assessments(self, authenticated_client): + def test_create_compliance_assessments(self, test): """test to create compliance assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Compliance Assessments", ComplianceAssessment, { @@ -153,23 +156,24 @@ def test_create_compliance_assessments(self, authenticated_client): "str": str(Framework.objects.all()[0]), }, }, + user_group=test.user_group, ) - def test_update_compliance_assessments(self, authenticated_client): + def test_update_compliance_assessments(self, test): """test to update compliance assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Documents") - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework2") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Documents") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework2") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) project2 = Project.objects.create( name="test2", folder=Folder.objects.create(name="test2") ) EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Compliance Assessments", ComplianceAssessment, { @@ -193,18 +197,19 @@ def test_update_compliance_assessments(self, authenticated_client): "str": str(Framework.objects.all()[0]), }, }, + user_group=test.user_group, ) - def test_delete_compliance_assessments(self, authenticated_client): + def test_delete_compliance_assessments(self, test): """test to delete compliance assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Compliance Assessments", ComplianceAssessment, { @@ -212,4 +217,5 @@ def test_delete_compliance_assessments(self, authenticated_client): "project": project, "framework": Framework.objects.all()[0], }, + user_group=test.user_group, ) diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 17c15c9d6..081569387 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -35,4 +35,4 @@ def authenticated_client(app_config): def test(authenticated_client, request) -> Test: """Get the elements used by the tests such as client and associated folder""" client, folder = EndpointTestsUtils.get_test_client_and_folder(authenticated_client, request.param) - return Test({"client": client, "authenticated_client": authenticated_client, "folder": folder, "user_group": request.param}) \ No newline at end of file + return Test({"client": client, "admin_client": authenticated_client, "folder": folder, "user_group": request.param}) \ No newline at end of file From dc9f5ae29f6f01e531c85b3d42a7dd3d25d71fc2 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 15:07:04 +0100 Subject: [PATCH 14/48] add evidences api tests for the other user groups --- backend/app_tests/api/test_api_evidences.py | 85 +++++++++++---------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/backend/app_tests/api/test_api_evidences.py b/backend/app_tests/api/test_api_evidences.py index 0fd73c3d6..b68b2d045 100644 --- a/backend/app_tests/api/test_api_evidences.py +++ b/backend/app_tests/api/test_api_evidences.py @@ -5,6 +5,7 @@ from core.models import Evidence from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_api import EndpointTestsQueries # Generic evidence data for tests @@ -91,28 +92,28 @@ def test_delete_evidences(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestEvidencesAuthenticated: """Perform tests on Evidences API endpoint with authentication""" - def test_get_evidences(self, authenticated_client): + def test_get_evidences(self, test): """test to get evidences from the API with authentication""" - folder = Folder.objects.create(name="test") - security_measure = SecurityMeasure.objects.create(name="test", folder=folder) + security_measure = SecurityMeasure.objects.create(name="test", folder=test.folder) EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Evidences", Evidence, { "name": EVIDENCE_NAME, "description": EVIDENCE_DESCRIPTION, "link": EVIDENCE_LINK, - "folder": folder, + "folder": test.folder, "security_measures": [security_measure], }, { - "folder": {"id": str(folder.id), "str": folder.name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "security_measures": [ { "id": str(security_measure.id), @@ -120,101 +121,101 @@ def test_get_evidences(self, authenticated_client): } ], }, + user_group=test.user_group, ) - def test_create_evidences(self, authenticated_client): + def test_create_evidences(self, test): """test to create evidences with the API with authentication""" - folder = Folder.objects.create(name="test") - security_measure = SecurityMeasure.objects.create(name="test", folder=folder) + security_measure = SecurityMeasure.objects.create(name="test", folder=test.folder) with open( path.join(path.dirname(path.dirname(__file__)), EVIDENCE_ATTACHMENT), "rb" ) as file: EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Evidences", Evidence, { "name": EVIDENCE_NAME, "description": EVIDENCE_DESCRIPTION, "link": EVIDENCE_LINK, - "folder": str(folder.id), - # "security_measures": [str(security_measure.id)], + "folder": str(test.folder.id), + "security_measures": [str(security_measure.id)], "attachment": file, }, { - "folder": {"id": str(folder.id), "str": folder.name}, - # "security_measures": [ - # { - # "id": str(security_measure.id), - # "str": security_measure.name, - # } - # ], + "folder": {"id": str(test.folder.id), "str": test.folder.name}, + "security_measures": [ + { + "id": str(security_measure.id), + "str": security_measure.name, + } + ], "attachment": EVIDENCE_ATTACHMENT, }, query_format="multipart", + user_group=test.user_group, ) - def test_update_evidences(self, authenticated_client): + def test_update_evidences(self, test): """test to update evidences with the API with authentication""" - folder = Folder.objects.create(name="test") - folder2 = Folder.objects.create(name="test2") - # security_measure = SecurityMeasure.objects.create(name="test", folder=folder) - # security_measure2 = SecurityMeasure.objects.create(name="test2", folder=folder2) + folder = Folder.objects.create(name="test2") + security_measure = SecurityMeasure.objects.create(name="test", folder=test.folder) + security_measure2 = SecurityMeasure.objects.create(name="test2", folder=folder) with open( path.join(path.dirname(path.dirname(__file__)), EVIDENCE_ATTACHMENT), "rb" ) as file: EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Evidences", Evidence, { "name": EVIDENCE_NAME, "description": EVIDENCE_DESCRIPTION, "link": EVIDENCE_LINK, - "folder": folder, - # "security_measures": [security_measure], + "folder": test.folder, + "security_measures": [security_measure], }, { "name": "new " + EVIDENCE_NAME, "description": "new " + EVIDENCE_DESCRIPTION, "link": EVIDENCE_LINK + "/new", - "folder": str(folder2.id), - # "security_measures": [str(security_measure2.id)], + "folder": str(folder.id), + "security_measures": [str(security_measure2.id)], "attachment": file, }, { - "folder": {"id": str(folder.id), "str": folder.name}, - # "security_measures": [ - # { - # "id": str(security_measure.id), - # "str": security_measure.name, - # } - # ], + "folder": {"id": str(test.folder.id), "str": test.folder.name}, + "security_measures": [ + { + "id": str(security_measure.id), + "str": security_measure.name, + } + ], }, { "attachment": EVIDENCE_ATTACHMENT, }, query_format="multipart", + user_group=test.user_group, ) - def test_delete_evidences(self, authenticated_client): + def test_delete_evidences(self, test): """test to delete evidences with the API with authentication""" - folder = Folder.objects.create(name="test") - EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Evidences", Evidence, { "name": EVIDENCE_NAME, - "folder": folder, + "folder": test.folder, "security_measures": [ - SecurityMeasure.objects.create(name="test", folder=folder) + SecurityMeasure.objects.create(name="test", folder=test.folder) ], }, + user_group=test.user_group, ) From 0b723aadd0be38aae57aca2ffce66e9bfd4b2fe2 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 16:06:34 +0100 Subject: [PATCH 15/48] rename test_api.py to test_utils.py --- backend/app_tests/api/test_api_assets.py | 2 +- .../api/test_api_compliance_assessments.py | 2 +- backend/app_tests/api/test_api_evidences.py | 2 +- backend/app_tests/api/test_api_folders.py | 2 +- backend/app_tests/api/test_api_libraries.py | 2 +- backend/app_tests/api/test_api_policies.py | 2 +- backend/app_tests/api/test_api_projects.py | 2 +- .../api/test_api_requirement_assessments.py | 2 +- .../api/test_api_requirement_nodes.py | 2 +- .../api/test_api_risk_acceptances.py | 2 +- .../api/test_api_risk_assessments.py | 2 +- .../app_tests/api/test_api_risk_scenarios.py | 2 +- .../api/test_api_security_functions.py | 2 +- .../api/test_api_security_measures.py | 2 +- backend/app_tests/api/test_api_threats.py | 2 +- backend/app_tests/api/test_api_user_groups.py | 2 +- backend/app_tests/api/test_api_users.py | 2 +- .../api/{test_api.py => test_utils.py} | 21 +++++++++++++++---- backend/app_tests/conftest.py | 2 +- 19 files changed, 35 insertions(+), 22 deletions(-) rename backend/app_tests/api/{test_api.py => test_utils.py} (96%) diff --git a/backend/app_tests/api/test_api_assets.py b/backend/app_tests/api/test_api_assets.py index 15eb26149..9c2857cf7 100644 --- a/backend/app_tests/api/test_api_assets.py +++ b/backend/app_tests/api/test_api_assets.py @@ -4,7 +4,7 @@ from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic asset data for tests ASSET_NAME = "Test Asset" diff --git a/backend/app_tests/api/test_api_compliance_assessments.py b/backend/app_tests/api/test_api_compliance_assessments.py index 0cc59bac7..6cb901b14 100644 --- a/backend/app_tests/api/test_api_compliance_assessments.py +++ b/backend/app_tests/api/test_api_compliance_assessments.py @@ -5,7 +5,7 @@ from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic compliance assessment data for tests COMPLIANCE_ASSESSMENT_NAME = "Test Compliance Assessment" diff --git a/backend/app_tests/api/test_api_evidences.py b/backend/app_tests/api/test_api_evidences.py index b68b2d045..fa0cc0430 100644 --- a/backend/app_tests/api/test_api_evidences.py +++ b/backend/app_tests/api/test_api_evidences.py @@ -6,7 +6,7 @@ from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic evidence data for tests EVIDENCE_NAME = "Test Evidence" diff --git a/backend/app_tests/api/test_api_folders.py b/backend/app_tests/api/test_api_folders.py index 8147defdc..d10220044 100644 --- a/backend/app_tests/api/test_api_folders.py +++ b/backend/app_tests/api/test_api_folders.py @@ -2,7 +2,7 @@ from rest_framework.test import APIClient from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic folder data for tests FOLDER_NAME = "Test Folder" diff --git a/backend/app_tests/api/test_api_libraries.py b/backend/app_tests/api/test_api_libraries.py index b5df402ed..5ebbc78aa 100644 --- a/backend/app_tests/api/test_api_libraries.py +++ b/backend/app_tests/api/test_api_libraries.py @@ -4,7 +4,7 @@ from core.models import RiskMatrix from iam.models import Folder -from test_api import EndpointTestsQueries, EndpointTestsUtils +from test_utils import EndpointTestsQueries, EndpointTestsUtils @pytest.mark.django_db diff --git a/backend/app_tests/api/test_api_policies.py b/backend/app_tests/api/test_api_policies.py index da7cd271a..5157aca1f 100644 --- a/backend/app_tests/api/test_api_policies.py +++ b/backend/app_tests/api/test_api_policies.py @@ -3,7 +3,7 @@ from core.models import Policy from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic policy data for tests POLICY_NAME = "Test Policy" diff --git a/backend/app_tests/api/test_api_projects.py b/backend/app_tests/api/test_api_projects.py index 57ae05e45..507dd414e 100644 --- a/backend/app_tests/api/test_api_projects.py +++ b/backend/app_tests/api/test_api_projects.py @@ -4,7 +4,7 @@ from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic project data for tests PROJECT_NAME = "Test Project" diff --git a/backend/app_tests/api/test_api_requirement_assessments.py b/backend/app_tests/api/test_api_requirement_assessments.py index 6f29fa154..95fe58f86 100644 --- a/backend/app_tests/api/test_api_requirement_assessments.py +++ b/backend/app_tests/api/test_api_requirement_assessments.py @@ -10,7 +10,7 @@ from core.models import Project, SecurityMeasure from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic requirement assessment data for tests REQUIREMENT_ASSESSMENT_STATUS = "partially_compliant" diff --git a/backend/app_tests/api/test_api_requirement_nodes.py b/backend/app_tests/api/test_api_requirement_nodes.py index 52c9adfb6..4986b81fc 100644 --- a/backend/app_tests/api/test_api_requirement_nodes.py +++ b/backend/app_tests/api/test_api_requirement_nodes.py @@ -3,7 +3,7 @@ from core.models import RequirementNode, Framework from iam.models import Folder -from test_api import EndpointTestsQueries, EndpointTestsUtils +from test_utils import EndpointTestsQueries, EndpointTestsUtils # Generic requirement data for tests REQUIREMENT_NODE_NAME = "Test Requirement Node" diff --git a/backend/app_tests/api/test_api_risk_acceptances.py b/backend/app_tests/api/test_api_risk_acceptances.py index 6b3cc37bd..23bbf8d6f 100644 --- a/backend/app_tests/api/test_api_risk_acceptances.py +++ b/backend/app_tests/api/test_api_risk_acceptances.py @@ -10,7 +10,7 @@ ) from iam.models import Folder, UserGroup -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic risk acceptance data for tests RISK_ACCEPTANCE_NAME = "Test Risk Acceptance" diff --git a/backend/app_tests/api/test_api_risk_assessments.py b/backend/app_tests/api/test_api_risk_assessments.py index 5b8e85bd4..c8c2d8623 100644 --- a/backend/app_tests/api/test_api_risk_assessments.py +++ b/backend/app_tests/api/test_api_risk_assessments.py @@ -3,7 +3,7 @@ from core.models import Project, RiskAssessment, RiskMatrix from iam.models import Folder, User -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic project data for tests RISK_ASSESSMENT_NAME = "Test risk_assessment" diff --git a/backend/app_tests/api/test_api_risk_scenarios.py b/backend/app_tests/api/test_api_risk_scenarios.py index f5b612d9f..edc6ba20e 100644 --- a/backend/app_tests/api/test_api_risk_scenarios.py +++ b/backend/app_tests/api/test_api_risk_scenarios.py @@ -11,7 +11,7 @@ ) from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic project data for tests RISK_SCENARIO_NAME = "Test scenario" diff --git a/backend/app_tests/api/test_api_security_functions.py b/backend/app_tests/api/test_api_security_functions.py index a7a49c68e..32d7d16e3 100644 --- a/backend/app_tests/api/test_api_security_functions.py +++ b/backend/app_tests/api/test_api_security_functions.py @@ -4,7 +4,7 @@ from core.models import SecurityFunction from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic security function data for tests SECURITY_FUNCTION_REF_ID = "Test-Security-Function" diff --git a/backend/app_tests/api/test_api_security_measures.py b/backend/app_tests/api/test_api_security_measures.py index 83d846bc5..c283ad2ae 100644 --- a/backend/app_tests/api/test_api_security_measures.py +++ b/backend/app_tests/api/test_api_security_measures.py @@ -3,7 +3,7 @@ from core.models import SecurityFunction, SecurityMeasure from iam.models import Folder -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic security measure data for tests SECURITY_MEASURE_NAME = "Test Security Measure" diff --git a/backend/app_tests/api/test_api_threats.py b/backend/app_tests/api/test_api_threats.py index 374384d81..8155813ec 100644 --- a/backend/app_tests/api/test_api_threats.py +++ b/backend/app_tests/api/test_api_threats.py @@ -5,7 +5,7 @@ from iam.models import Folder from test_vars import GROUPS_PERMISSIONS -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic threat data for tests THREAT_REF_ID = "Test-Threat-ID" diff --git a/backend/app_tests/api/test_api_user_groups.py b/backend/app_tests/api/test_api_user_groups.py index 9b988dde6..74703aa74 100644 --- a/backend/app_tests/api/test_api_user_groups.py +++ b/backend/app_tests/api/test_api_user_groups.py @@ -3,7 +3,7 @@ from iam.models import Folder, UserGroup, RoleAssignment from test_vars import GROUPS_PERMISSIONS, TEST_USER_EMAIL -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries @pytest.mark.django_db class TestUserGroups: diff --git a/backend/app_tests/api/test_api_users.py b/backend/app_tests/api/test_api_users.py index 160027f20..1985a08b4 100644 --- a/backend/app_tests/api/test_api_users.py +++ b/backend/app_tests/api/test_api_users.py @@ -5,7 +5,7 @@ from iam.models import User from test_vars import USERS_ENDPOINT as API_ENDPOINT -from test_api import EndpointTestsQueries +from test_utils import EndpointTestsQueries # Generic user data for tests USER_FIRSTNAME = "John" diff --git a/backend/app_tests/api/test_api.py b/backend/app_tests/api/test_utils.py similarity index 96% rename from backend/app_tests/api/test_api.py rename to backend/app_tests/api/test_utils.py index ec164f4bf..4f89d93ab 100644 --- a/backend/app_tests/api/test_api.py +++ b/backend/app_tests/api/test_utils.py @@ -692,6 +692,7 @@ def import_object( urn: str | None = None, fails: bool = False, expected_status: int = status.HTTP_200_OK, + user_group: str = None, ): """Imports object with the API with authentication @@ -699,6 +700,10 @@ def import_object( :param verbose_name: the verbose name of the object to test :param urn: the endpoint URL of the object to test (optional) """ + user_perm_fails, user_perm_expected_status = None, 0 + + if user_group: + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("add", "library_", user_group) url = urn or EndpointTestsUtils.get_object_urn(verbose_name) @@ -706,10 +711,18 @@ def import_object( response = authenticated_client.get(url + "import/") # Asserts that the object was imported successfully - assert ( - response.status_code == expected_status - ), f"{verbose_name} can not be imported with authentication" - if not fails: + if not user_group or user_perm_expected_status == status.HTTP_200_OK: + # User has permission to import the library + assert ( + response.status_code == expected_status + ), f"{verbose_name} can not be imported with authentication" if expected_status == status.HTTP_200_OK else f"{verbose_name} should not be imported (expected status: {expected_status})" + else: + # User does not have permission to import the library + assert ( + response.status_code == user_perm_expected_status + ), f"{verbose_name} can be imported without permission" if expected_status == status.HTTP_200_OK else f"Importing {verbose_name.lower()} should give a status {user_perm_expected_status}" + + if not (fails or user_perm_fails): assert response.json() == { "status": "success" }, f"{verbose_name} can not be imported with authentication" diff --git a/backend/app_tests/conftest.py b/backend/app_tests/conftest.py index 081569387..ec31873a8 100644 --- a/backend/app_tests/conftest.py +++ b/backend/app_tests/conftest.py @@ -1,6 +1,6 @@ import pytest from rest_framework.test import APIClient -from api.test_api import EndpointTestsUtils +from api.test_utils import EndpointTestsUtils from iam.models import User, UserGroup from core.apps import startup From 79d61d6f3b9cadcc9d0ebcae4d61d6a7940369b6 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 17:31:48 +0100 Subject: [PATCH 16/48] add libraries api tests for the other user groups --- backend/app_tests/api/test_api_libraries.py | 45 +++++---- backend/app_tests/api/test_utils.py | 101 ++++++++++++++------ backend/app_tests/test_vars.py | 11 +++ 3 files changed, 107 insertions(+), 50 deletions(-) diff --git a/backend/app_tests/api/test_api_libraries.py b/backend/app_tests/api/test_api_libraries.py index 5ebbc78aa..f420ace81 100644 --- a/backend/app_tests/api/test_api_libraries.py +++ b/backend/app_tests/api/test_api_libraries.py @@ -4,6 +4,7 @@ from core.models import RiskMatrix from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries, EndpointTestsUtils @@ -42,21 +43,22 @@ def test_delete_risk_matrix(self, authenticated_client): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestLibrariesAuthenticated: """Perform tests on Libraries API endpoint with authentication""" - def test_get_libraries(self, authenticated_client): + def test_get_libraries(self, test): """test to get libraries from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, "Libraries", base_count=-1 + test.client, "Libraries", base_count=-1, user_group=test.user_group ) - def test_import_frameworks(self, authenticated_client): + def test_import_frameworks(self, test): """test to import frameworks with the API with authentication""" - # Uses the API endpoint to get library details with the authenticated client - lib_detail_response = authenticated_client.get( + # Uses the API endpoint to get library details with the admin client + lib_detail_response = test.admin_client.get( EndpointTestsUtils.get_object_urn("Framework") ).json()["objects"]["framework"] @@ -64,16 +66,16 @@ def test_import_frameworks(self, authenticated_client): assert ( Framework.objects.all().count() == 0 ), "libraries are already imported in the database" - EndpointTestsQueries.Auth.get_object(authenticated_client, "Frameworks") + EndpointTestsQueries.Auth.get_object(test.client, "Frameworks", user_group=test.user_group) - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.client, "Framework", user_group=test.user_group) # Uses the API endpoint to assert that the library was properly imported assert ( Framework.objects.all().count() == 1 ), "frameworks are not correctly imported in the database" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Frameworks", test_params={ "name": lib_detail_response["name"], @@ -82,21 +84,22 @@ def test_import_frameworks(self, authenticated_client): "folder": {"str": Folder.get_root_folder().name}, }, base_count=1, + user_group=test.user_group, ) - def test_delete_frameworks(self, authenticated_client): + def test_delete_frameworks(self, test): """test to delete frameworks with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.client, "Framework", user_group=test.user_group) EndpointTestsQueries.Auth.delete_object( - authenticated_client, "Frameworks", Framework + test.client, "Frameworks", Framework, user_group=test.user_group ) - def test_import_risk_matrix(self, authenticated_client): + def test_import_risk_matrix(self, test): """test to import risk matrix with the API with authentication""" - # Uses the API endpoint to get library details with the authenticated client - lib_detail_response = authenticated_client.get( + # Uses the API endpoint to get library details with the admin client + lib_detail_response = test.admin_client.get( EndpointTestsUtils.get_object_urn("Risk matrix") ).json()["objects"]["risk_matrix"][0] @@ -104,15 +107,16 @@ def test_import_risk_matrix(self, authenticated_client): assert ( RiskMatrix.objects.all().count() == 0 ), "libraries are already imported in the database" - EndpointTestsQueries.Auth.get_object(authenticated_client, "Risk matrices") - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") + EndpointTestsQueries.Auth.get_object(test.client, "Risk matrices", user_group=test.user_group) + + EndpointTestsQueries.Auth.import_object(test.client, "Risk matrix", user_group=test.user_group) # Uses the API endpoint to assert that the library was properly imported assert ( RiskMatrix.objects.all().count() == 1 ), "Risk matrices are not correctly imported in the database" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Risk matrices", test_params={ "name": lib_detail_response["name"], @@ -122,12 +126,13 @@ def test_import_risk_matrix(self, authenticated_client): # 'json_definition': lib_detail_response # TODO: restore this test }, base_count=1, + user_group=test.user_group, ) - def test_delete_matrix(self, authenticated_client): + def test_delete_matrix(self, test): """test to delete risk matrix with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.client, "Risk matrix", user_group=test.user_group) EndpointTestsQueries.Auth.delete_object( - authenticated_client, "Risk matrices", RiskMatrix + test.client, "Risk matrices", RiskMatrix, user_group=test.user_group ) diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index 4f89d93ab..2cf2a2b9a 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -43,7 +43,7 @@ def get_test_client_and_folder(authenticated_client, role: str): def expected_request_response(action: str, object: str, user_group, expected_status: int = status.HTTP_200_OK): """Get the expected request response""" - perm_name = f"{action}_{object.lower().replace(' ', '')[:-1]}" + perm_name = f"{action}_{get_singular_name(object).lower().replace(' ', '')}" if perm_name in GROUPS_PERMISSIONS[user_group]['perms']: fails = False @@ -302,29 +302,38 @@ def get_object( -1 means that the number of objects is unknown :param endpoint: the endpoint URL of the object to test (optional) """ - - if user_group and not fails: - fails, expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) + user_perm_fails, user_perm_expected_status = None, 0 + + if user_group: + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group, expected_status) url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) # Uses the API endpoint to assert that objects are accessible response = authenticated_client.get(url) - assert ( - response.status_code == expected_status - ), f"{verbose_name} are not accessible with authentication" + if not user_group or user_perm_expected_status == status.HTTP_200_OK: + # User has permission to view the object + assert ( + response.status_code == expected_status + ), f"{verbose_name} are not accessible with permission" if expected_status == status.HTTP_200_OK else f"{verbose_name} should not be accessible (expected status: {expected_status})" + else: + # User does not have permission to view the object + assert ( + response.status_code == user_perm_expected_status + ), f"{verbose_name} are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" + if ( base_count == 0 and not (object and build_params) and test_params - and not fails + and not (fails or user_perm_fails) ): # perfom a test with an externally created object assert ( response.json()["count"] == base_count + 1 ), f"{verbose_name} are not accessible with authentication" - elif base_count > 0 and not fails: + elif base_count > 0 and not (fails or user_perm_fails): assert ( response.json()["count"] == base_count ), f"{verbose_name} are not accessible with authentication" @@ -357,11 +366,18 @@ def get_object( # Uses the API endpoint to assert that the test object is accessible response = authenticated_client.get(url) - assert ( - response.status_code == status.HTTP_200_OK - ), f"{verbose_name} are not accessible with authentication" + if not user_group or user_perm_expected_status == status.HTTP_200_OK: + # User has permission to view the object + assert ( + response.status_code == expected_status + ), f"{verbose_name} are not accessible with permission" if expected_status == status.HTTP_200_OK else f"{verbose_name} should not be accessible (expected status: {expected_status})" + else: + # User does not have permission to view the object + assert ( + response.status_code == user_perm_expected_status + ), f"{verbose_name} are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" - if not fails: + if not (fails or user_perm_fails): if base_count < 0: assert ( len(response.json()["results"]) != 0 @@ -371,7 +387,7 @@ def get_object( response.json()["count"] == base_count + 1 ), f"{verbose_name} are not accessible with authentication" - if not fails: + if not (fails or user_perm_fails): for key, value in {**build_params, **test_params}.items(): if ( type(value) == dict @@ -403,19 +419,28 @@ def get_object_options( :param option: the option to test :param endpoint: the endpoint URL of the object to test (optional) """ + user_perm_fails, user_perm_expected_status = None, 0 + if user_group and not fails: - fails, expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("view", verbose_name, user_group, expected_status) url = endpoint or EndpointTestsUtils.get_endpoint_url(verbose_name) # Uses the API endpoint to assert that the object options are accessible response = authenticated_client.get(url + option + "/") - assert ( - response.status_code == expected_status - ), f"{verbose_name} {option} choices are not accessible with authentication" + if not user_group or user_perm_expected_status == status.HTTP_200_OK: + # User has permission to view the object + assert ( + response.status_code == expected_status + ), f"{verbose_name} {option} choices are not accessible with permission" if expected_status == status.HTTP_200_OK else f"{verbose_name} {option} should not be accessible (expected status: {expected_status})" + else: + # User does not have permission to view the object + assert ( + response.status_code == user_perm_expected_status + ), f"{verbose_name} {option} choices are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} {option} should give a status {user_perm_expected_status}" - if not fails: + if not (fails or user_perm_fails): for choice in choices: assert ( choice[0] in response.json() @@ -449,6 +474,7 @@ def create_object( :param endpoint: the endpoint URL of the object to test (optional) """ user_perm_fails, user_perm_expected_status = None, 0 + if user_group: user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("add", verbose_name, user_group, expected_status) @@ -546,7 +572,7 @@ def update_object( user_perm_fails, user_perm_expected_status = None, 0 if user_group: - user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group) + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("change", verbose_name, user_group, expected_status) # Creates a test object from the model m2m_fields = {} @@ -638,9 +664,10 @@ def delete_object( :param build_params: the parameters to build the object :param endpoint: the endpoint URL of the object to test (optional) """ + user_perm_fails, user_perm_expected_status = None, 0 - if user_group and not fails: - fails, expected_status = EndpointTestsUtils.expected_request_response("delete", verbose_name, user_group, expected_status) + if user_group: + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("delete", verbose_name, user_group, expected_status) if build_params: # Creates a test object from the model @@ -669,17 +696,31 @@ def delete_object( # Asserts that the objects exists response = authenticated_client.get(url) - assert ( - response.status_code == status.HTTP_200_OK - ), f"{verbose_name} can not be deleted with authentication" + + if not user_group or EndpointTestsUtils.expected_request_response("view", verbose_name, user_group) == (False, status.HTTP_200_OK): + assert ( + response.status_code == status.HTTP_200_OK + ), f"{verbose_name} object detail can not be accessed with permission" + else: + assert ( + response.status_code == status.HTTP_403_FORBIDDEN + ), f"{verbose_name} object detail can be accessed without permission" # Asserts that the object was deleted successfully delete_response = authenticated_client.delete(url) - assert ( - delete_response.status_code == expected_status - ), f"{verbose_name} can not be deleted with authentication" if expected_status == status.HTTP_204_NO_CONTENT else f"{verbose_name} should not be deleted (expected status: {expected_status})" - if not fails: + if not user_group or user_perm_expected_status == status.HTTP_204_NO_CONTENT: + # User has permission to delete the object + assert ( + delete_response.status_code == expected_status + ), f"{verbose_name} can not be deleted with authentication" if expected_status == status.HTTP_204_NO_CONTENT else f"{verbose_name} should not be deleted (expected status: {expected_status})" + else: + # User does not have permission to delete the object + assert ( + delete_response.status_code == user_perm_expected_status + ), f"{verbose_name} can be deleted without permission" if expected_status == status.HTTP_204_NO_CONTENT else f"Deleting {verbose_name.lower()} should give a status {user_perm_expected_status}" + + if not (fails or user_perm_fails): # Asserts that the objects does not exists anymore response = authenticated_client.get(url) assert ( @@ -703,7 +744,7 @@ def import_object( user_perm_fails, user_perm_expected_status = None, 0 if user_group: - user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("add", "library_", user_group) + user_perm_fails, user_perm_expected_status = EndpointTestsUtils.expected_request_response("add", "library", user_group, expected_status) url = urn or EndpointTestsUtils.get_object_urn(verbose_name) diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index a05176c99..5589e20c9 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -106,6 +106,8 @@ "delete_framework", "view_requirementnode", "view_requirementlevel", # Permits to see the object on api by an admin + "add_library", + "view_library", "delete_library", "backup", "restore", @@ -319,3 +321,12 @@ def get_var(varname: str) -> Any: f"The test_vars module doesn't contain any variable named '{varname}' !" ) return value + + +def get_singular_name(plural_name: str) -> str: + exceptions = { + "Libraries": "Library", + "Risk matrices": "Risk matrix", + "Policies": "Policy", + } + return exceptions.get(plural_name, plural_name[:-1] if plural_name.endswith("s") else plural_name) From 38d6b61176fdaaf96e81537a64781d95557b1f1d Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 17:48:21 +0100 Subject: [PATCH 17/48] add policies api tests for the other user groups --- backend/app_tests/api/test_api_policies.py | 77 +++++++++++++--------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/backend/app_tests/api/test_api_policies.py b/backend/app_tests/api/test_api_policies.py index 5157aca1f..0074093e6 100644 --- a/backend/app_tests/api/test_api_policies.py +++ b/backend/app_tests/api/test_api_policies.py @@ -3,6 +3,7 @@ from core.models import Policy from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic policy data for tests @@ -27,7 +28,7 @@ def test_get_policies(self): EndpointTestsQueries.get_object( self.client, - "policies", + "Policies", Policy, { "name": POLICY_NAME, @@ -41,7 +42,7 @@ def test_create_policies(self): EndpointTestsQueries.create_object( self.client, - "policies", + "Policies", Policy, { "name": POLICY_NAME, @@ -55,7 +56,7 @@ def test_update_policies(self): EndpointTestsQueries.update_object( self.client, - "policies", + "Policies", Policy, { "name": POLICY_NAME, @@ -74,7 +75,7 @@ def test_delete_policies(self): EndpointTestsQueries.delete_object( self.client, - "policies", + "Policies", Policy, { "name": POLICY_NAME, @@ -84,15 +85,16 @@ def test_delete_policies(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestPolicysAuthenticated: """Perform tests on policies API endpoint with authentication""" - def test_get_policies(self, authenticated_client): + def test_get_policies(self, test): """test to get policies from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, - "policies", + test.client, + "Policies", Policy, { "name": POLICY_NAME, @@ -101,22 +103,23 @@ def test_get_policies(self, authenticated_client): "link": POLICY_LINK, "eta": POLICY_ETA, "effort": POLICY_EFFORT[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "security_function": None, "status": POLICY_STATUS[1], "effort": POLICY_EFFORT[1], }, + user_group=test.user_group, ) - def test_create_policies(self, authenticated_client): + def test_create_policies(self, test): """test to create policies with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, - "policies", + test.client, + "Policies", Policy, { "name": POLICY_NAME, @@ -125,23 +128,24 @@ def test_create_policies(self, authenticated_client): "link": POLICY_LINK, "eta": POLICY_ETA, "effort": POLICY_EFFORT[0], - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "status": POLICY_STATUS[1], "effort": POLICY_EFFORT[1], }, + user_group=test.user_group, ) - def test_update_policies(self, authenticated_client): + def test_update_policies(self, test): """test to update policies with the API with authentication""" - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") EndpointTestsQueries.Auth.update_object( - authenticated_client, - "policies", + test.client, + "Policies", Policy, { "name": POLICY_NAME, @@ -150,7 +154,7 @@ def test_update_policies(self, authenticated_client): "link": POLICY_LINK, "eta": POLICY_ETA, "effort": POLICY_EFFORT[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, { "name": "new " + POLICY_NAME, @@ -162,45 +166,56 @@ def test_update_policies(self, authenticated_client): "folder": str(folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "status": POLICY_STATUS[1], "effort": POLICY_EFFORT[1], }, + user_group=test.user_group, ) - def test_delete_policies(self, authenticated_client): + def test_delete_policies(self, test): """test to delete policies with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, - "policies", + test.client, + "Policies", Policy, { "name": POLICY_NAME, - "folder": Folder.objects.create(name="test"), + "folder": test.folder, }, + user_group=test.user_group, ) - def test_get_category_choices(self, authenticated_client): + def test_get_category_choices(self, test): """test to get policies category choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, "policies", "category", Policy.CATEGORY + test.client, + "Policies", + "category", + Policy.CATEGORY, + user_group=test.user_group ) - def test_get_effort_choices(self, authenticated_client): + def test_get_effort_choices(self, test): """test to get policies effort choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, "policies", "effort", Policy.EFFORT + test.client, + "Policies", + "effort", + Policy.EFFORT, + user_group=test.user_group ) - def test_get_status_choices(self, authenticated_client): + def test_get_status_choices(self, test): """test to get policies status choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, - "policies", + test.client, + "Policies", "status", Policy.Status.choices, + user_group=test.user_group, ) From e2dc99d1c0747646d7ca0bc0c1ea460f9a25e49e Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 18:35:45 +0100 Subject: [PATCH 18/48] add requirement assessments api tests for the other user groups --- .../api/test_api_requirement_assessments.py | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/backend/app_tests/api/test_api_requirement_assessments.py b/backend/app_tests/api/test_api_requirement_assessments.py index 95fe58f86..d895ecda7 100644 --- a/backend/app_tests/api/test_api_requirement_assessments.py +++ b/backend/app_tests/api/test_api_requirement_assessments.py @@ -10,6 +10,7 @@ from core.models import Project, SecurityMeasure from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic requirement assessment data for tests @@ -91,28 +92,28 @@ def test_update_requirement_assessments(self, authenticated_client): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestRequirementAssessmentsAuthenticated: """Perform tests on Requirement Assessments API endpoint with authentication""" - def test_get_requirement_assessments(self, authenticated_client): + def test_get_requirement_assessments(self, test): """test to get requirement assessments from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") compliance_assessment = ComplianceAssessment.objects.create( name="test", - project=Project.objects.create(name="test", folder=folder), + project=Project.objects.create(name="test", folder=test.folder), framework=Framework.objects.all()[0], ) EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Requirement Assessments", RequirementAssessment, { "status": REQUIREMENT_ASSESSMENT_STATUS, "observation": REQUIREMENT_ASSESSMENT_OBSERVATION, - "folder": folder, + "folder": test.folder, "compliance_assessment": compliance_assessment, "requirement": RequirementNode.objects.all()[0], }, @@ -124,30 +125,30 @@ def test_get_requirement_assessments(self, authenticated_client): }, "requirement": str(RequirementNode.objects.all()[0].id), }, - -1, + base_count=-1, + user_group=test.user_group, ) - def test_create_requirement_assessments(self, authenticated_client): + def test_create_requirement_assessments(self, test): """test to create requirement assessments with the API with authentication""" """nobody has permission to do that, so it will fail""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") compliance_assessment = ComplianceAssessment.objects.create( name="test", - project=Project.objects.create(name="test", folder=folder), + project=Project.objects.create(name="test", folder=test.folder), framework=Framework.objects.all()[0], ) - security_measure = SecurityMeasure.objects.create(name="test", folder=folder) + security_measure = SecurityMeasure.objects.create(name="test", folder=test.folder) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Requirement Assessments", RequirementAssessment, { "status": REQUIREMENT_ASSESSMENT_STATUS, "observation": REQUIREMENT_ASSESSMENT_OBSERVATION, - "folder": str(folder.id), + "folder": str(test.folder.id), "compliance_assessment": str(compliance_assessment.id), "requirement": str(RequirementNode.objects.all()[0].id), "security_measures": [str(security_measure.id)], @@ -163,15 +164,15 @@ def test_create_requirement_assessments(self, authenticated_client): expected_status=HTTP_400_BAD_REQUEST ) - def test_update_requirement_assessments(self, authenticated_client): + def test_update_requirement_assessments(self, test): """test to update requirement assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") + folder = Folder.objects.create(name="test2") compliance_assessment = ComplianceAssessment.objects.create( name="test", project=Project.objects.create( - name="test", folder=Folder.get_root_folder() + name="test", folder=test.folder ), framework=Framework.objects.all()[0], ) @@ -183,13 +184,13 @@ def test_update_requirement_assessments(self, authenticated_client): security_measure = SecurityMeasure.objects.create(name="test", folder=folder) EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Requirement Assessments", RequirementAssessment, { "status": REQUIREMENT_ASSESSMENT_STATUS, "observation": REQUIREMENT_ASSESSMENT_OBSERVATION, - "folder": Folder.get_root_folder(), + "folder": test.folder, "compliance_assessment": compliance_assessment, "requirement": RequirementNode.objects.all()[0], }, @@ -209,14 +210,16 @@ def test_update_requirement_assessments(self, authenticated_client): }, "requirement": str(RequirementNode.objects.all()[0].id), }, + user_group=test.user_group, ) - def test_get_status_choices(self, authenticated_client): + def test_get_status_choices(self, test): """test to get requirement assessments status choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, + test.client, "Requirement Assessments", "status", RequirementAssessment.Status.choices, + user_group=test.user_group, ) From 4c3804c3925f86092323ffdca6bf88431e0717f1 Mon Sep 17 00:00:00 2001 From: Alexis Date: Thu, 22 Feb 2024 18:45:28 +0100 Subject: [PATCH 19/48] rename test user groups to allow single tests execution --- backend/app_tests/test_vars.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index 5589e20c9..74c75dd15 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -32,7 +32,7 @@ GROUPS_PERMISSIONS = { "BI-UG-ADM": { "folder": "Global", - "name": "Global administrator", + "name": "Global_administrator", "perms": [ "add_user", "view_user", @@ -115,7 +115,7 @@ }, "BI-UG-GAD": { "folder": "Global", - "name": "Global auditor", + "name": "Global_auditor", "perms": [ "view_project", "view_riskassessment", @@ -137,7 +137,7 @@ }, "BI-UG-GVA": { "folder": "Global", - "name": "Global validator", + "name": "Global_validator", "perms": [ "view_project", "view_riskassessment", @@ -252,7 +252,7 @@ }, "BI-UG-DMA": { "folder": "test", - "name": "Domain Manager", + "name": "Domain_Manager", "perms": [ "change_usergroup", "view_usergroup", From c2cce57680eccd425725e99801f6acd5d2abd8f9 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 11:43:29 +0100 Subject: [PATCH 20/48] add requirement nodes api tests for the other user groups --- .../api/test_api_requirement_nodes.py | 19 +++++++++++-------- backend/app_tests/api/test_utils.py | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/backend/app_tests/api/test_api_requirement_nodes.py b/backend/app_tests/api/test_api_requirement_nodes.py index 4986b81fc..421183bab 100644 --- a/backend/app_tests/api/test_api_requirement_nodes.py +++ b/backend/app_tests/api/test_api_requirement_nodes.py @@ -3,6 +3,7 @@ from core.models import RequirementNode, Framework from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries, EndpointTestsUtils # Generic requirement data for tests @@ -39,15 +40,16 @@ def test_get_requirement_nodes(self, authenticated_client): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestRequirementNodesAuthenticated: """Perform tests on RequirementNodes API endpoint with authentication""" - def test_get_requirement_nodes(self, authenticated_client): + def test_get_requirement_nodes(self, test): """test to get requirement nodes from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Requirement nodes", RequirementNode, { @@ -58,21 +60,22 @@ def test_get_requirement_nodes(self, authenticated_client): "order_id": REQUIREMENT_NODE_ORDER_ID, "level": REQUIREMENT_NODE_LEVEL, "assessable": True, - "folder": Folder.get_root_folder(), + "folder": test.folder, "framework": Framework.objects.all()[0], }, { - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), "framework": str(Framework.objects.all()[0].id), }, base_count=-1, + user_group=test.user_group, ) - def test_import_requirement_nodes(self, authenticated_client): + def test_import_requirement_nodes(self, test): """test that the requirements values imported from a library are correct""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") + EndpointTestsQueries.Auth.import_object(test.client, "Framework", user_group=test.user_group) EndpointTestsQueries.Auth.compare_results( - authenticated_client, + test.client, "Requirement nodes", EndpointTestsUtils.get_endpoint_url("Requirement nodes"), EndpointTestsUtils.get_object_urn("Framework"), diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index 2cf2a2b9a..3ab2f9da9 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -793,13 +793,13 @@ def compare_results( reference = authenticated_client.get(reference_url) assert ( reference.status_code == status.HTTP_200_OK - ), f"reference endpoint is not accessible with authentication" + ), f"reference endpoint is not accessible" for object in reference.json()["objects"]["framework"][ object_name.lower().replace(" ", "_") ][:count]: comparelist = authenticated_client.get(compare_url) - compare = None + compare = dict() assert ( comparelist.status_code == expected_status ), f"{object['name']} is not in {compare_url} results" From 8c59df2dd09d02c7b779354eb2f585a9baf54788 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 11:49:57 +0100 Subject: [PATCH 21/48] add risk acceptances api tests for the other user groups --- .../api/test_api_risk_acceptances.py | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/backend/app_tests/api/test_api_risk_acceptances.py b/backend/app_tests/api/test_api_risk_acceptances.py index 23bbf8d6f..6dbbc1d53 100644 --- a/backend/app_tests/api/test_api_risk_acceptances.py +++ b/backend/app_tests/api/test_api_risk_acceptances.py @@ -10,6 +10,7 @@ ) from iam.models import Folder, UserGroup +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic risk acceptance data for tests @@ -91,18 +92,18 @@ def test_delete_risk_acceptances(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestRiskAcceptanceAuthenticated: """Perform tests on Risk Acceptance API endpoint with authentication""" - def test_get_risk_acceptances(self, authenticated_client): + def test_get_risk_acceptances(self, test): """test to get risk acceptances from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") approver = User.objects.create_user(email="approver@test.com") EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Risk Acceptances", RiskAcceptance, { @@ -113,35 +114,35 @@ def test_get_risk_acceptances(self, authenticated_client): # 'rejected_date': RISK_ACCEPTANCE_REJECTED_DATE, # 'revoked_date': RISK_ACCEPTANCE_REVOKED_DATE, "state": RISK_ACCEPTANCE_STATE[0], - "folder": folder, + "folder": test.folder, "approver": approver, }, { - "folder": {"id": str(folder.id), "str": folder.name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "approver": {"id": str(approver.id), "str": approver.email}, "state": RISK_ACCEPTANCE_STATE[1], }, + user_group=test.user_group, ) - def test_create_risk_acceptances(self, authenticated_client): + def test_create_risk_acceptances(self, test): """test to create risk acceptances with the API with authentication""" approver = User.objects.create_user(email="approver@test.com") UserGroup.objects.get(name="BI-UG-GVA").user_set.add(approver) - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") risk_scenario = RiskScenario.objects.create( name="test scenario", description="test description", risk_assessment=RiskAssessment.objects.create( name="test", - project=Project.objects.create(name="test", folder=folder), - risk_matrix=RiskMatrix.objects.create(name="test", folder=folder), + project=Project.objects.create(name="test", folder=test.folder), + risk_matrix=RiskMatrix.objects.create(name="test", folder=test.folder), ), ) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Risk Acceptances", RiskAcceptance, { @@ -152,26 +153,26 @@ def test_create_risk_acceptances(self, authenticated_client): # 'rejected_date': RISK_ACCEPTANCE_REJECTED_DATE, # 'revoked_date': RISK_ACCEPTANCE_REVOKED_DATE, # 'state': RISK_ACCEPTANCE_STATE[0], - "folder": str(folder.id), + "folder": str(test.folder.id), "approver": str(approver.id), "risk_scenarios": [str(risk_scenario.id)], }, { - "folder": {"id": str(folder.id), "str": folder.name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "approver": {"id": str(approver.id), "str": approver.email}, "risk_scenarios": [ {"id": str(risk_scenario.id), "str": str(risk_scenario)} ], # 'state': RISK_ACCEPTANCE_STATE[1], }, + user_group=test.user_group, ) - def test_update_risk_acceptances(self, authenticated_client): + def test_update_risk_acceptances(self, test): """test to update risk acceptances with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Framework") - folder = Folder.objects.create(name="test") - folder2 = Folder.objects.create(name="test2") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Framework") + folder = Folder.objects.create(name="test2") approver = User.objects.create_user(email="approver@test.com") UserGroup.objects.get(name="BI-UG-GVA").user_set.add(approver) approver2 = User.objects.create_user(email="approver2@test.com") @@ -181,13 +182,13 @@ def test_update_risk_acceptances(self, authenticated_client): description="test description", risk_assessment=RiskAssessment.objects.create( name="test", - project=Project.objects.create(name="test", folder=folder2), - risk_matrix=RiskMatrix.objects.create(name="test", folder=folder2), + project=Project.objects.create(name="test", folder=folder), + risk_matrix=RiskMatrix.objects.create(name="test", folder=folder), ), ) EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Risk Acceptances", RiskAcceptance, { @@ -195,33 +196,35 @@ def test_update_risk_acceptances(self, authenticated_client): "description": RISK_ACCEPTANCE_DESCRIPTION, "expiry_date": RISK_ACCEPTANCE_EXPIRY_DATE, # 'state': RISK_ACCEPTANCE_STATE[0], - "folder": folder, + "folder": test.folder, "approver": approver, }, { "name": "new " + RISK_ACCEPTANCE_NAME, "description": "new " + RISK_ACCEPTANCE_DESCRIPTION, "expiry_date": "2024-05-05", - "folder": str(folder2.id), + "folder": str(folder.id), "approver": str(approver2.id), "risk_scenarios": [str(risk_scenario.id)], }, { - "folder": {"id": str(folder.id), "str": folder.name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "approver": {"id": str(approver.id), "str": approver.email}, # 'state': RISK_ACCEPTANCE_STATE[1], }, + user_group=test.user_group, ) - def test_delete_risk_acceptances(self, authenticated_client): + def test_delete_risk_acceptances(self, test): """test to delete risk acceptances with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Risk Acceptances", RiskAcceptance, { "name": RISK_ACCEPTANCE_NAME, - "folder": Folder.objects.create(name="test"), + "folder": test.folder, }, + user_group=test.user_group, ) From 55103172f69cb8915a909e197146c3c5d0bd8445 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 11:54:43 +0100 Subject: [PATCH 22/48] add risk assessments api tests for the other user groups --- .../api/test_api_risk_assessments.py | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/backend/app_tests/api/test_api_risk_assessments.py b/backend/app_tests/api/test_api_risk_assessments.py index c8c2d8623..cd08703e8 100644 --- a/backend/app_tests/api/test_api_risk_assessments.py +++ b/backend/app_tests/api/test_api_risk_assessments.py @@ -3,6 +3,7 @@ from core.models import Project, RiskAssessment, RiskMatrix from iam.models import Folder, User +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic project data for tests @@ -98,20 +99,21 @@ def test_delete_risk_assessments(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestRiskAssessmentAuthenticated: """Perform tests on Risk Assessment API endpoint with authentication""" - def test_get_risk_assessments(self, authenticated_client): + def test_get_risk_assessments(self, test): """test to get risk assessments from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) risk_matrix = RiskMatrix.objects.all()[0] EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Risk Assessment", RiskAssessment, { @@ -125,19 +127,20 @@ def test_get_risk_assessments(self, authenticated_client): "project": {"id": str(project.id), "str": project.name}, "risk_matrix": {"id": str(risk_matrix.id), "str": str(risk_matrix)}, }, + user_group=test.user_group, ) - def test_create_risk_assessments(self, authenticated_client): + def test_create_risk_assessments(self, test): """test to create risk assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) risk_matrix = RiskMatrix.objects.all()[0] EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Risk Assessment", RiskAssessment, { @@ -151,15 +154,16 @@ def test_create_risk_assessments(self, authenticated_client): "project": {"id": str(project.id), "str": project.name}, "risk_matrix": {"id": str(risk_matrix.id), "str": str(risk_matrix)}, }, + user_group=test.user_group, ) - def test_update_risk_assessments(self, authenticated_client): + def test_update_risk_assessments(self, test): """test to update risk assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix2") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix2") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) project2 = Project.objects.create( name="test2", folder=Folder.objects.create(name="test2") @@ -168,7 +172,7 @@ def test_update_risk_assessments(self, authenticated_client): risk_matrix2 = RiskMatrix.objects.all()[1] EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Risk Assessment", RiskAssessment, { @@ -183,25 +187,26 @@ def test_update_risk_assessments(self, authenticated_client): "description": "new " + RISK_ASSESSMENT_DESCRIPTION, "version": RISK_ASSESSMENT_VERSION + ".1", "project": str(project2.id), - "risk_matrix": str(risk_matrix.id), + "risk_matrix": str(risk_matrix2.id), }, { "project": {"id": str(project.id), "str": project.name}, "risk_matrix": {"id": str(risk_matrix.id), "str": str(risk_matrix)}, }, + user_group=test.user_group, ) - def test_delete_risk_assessments(self, authenticated_client): + def test_delete_risk_assessments(self, test): """test to delete risk assessments with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") project = Project.objects.create( - name="test", folder=Folder.objects.create(name="test") + name="test", folder=test.folder ) risk_matrix = RiskMatrix.objects.all()[0] EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Risk Assessment", RiskAssessment, { @@ -209,10 +214,11 @@ def test_delete_risk_assessments(self, authenticated_client): "project": project, "risk_matrix": risk_matrix, }, + user_group=test.user_group, ) # TODO add option quality_check (endpoint /api/risk-assessments/quality_check/ not working) - # def test_get_status_choice(self, authenticated_client): + # def test_get_status_choice(self, test): # """test to get risk assessments status choices from the API with authentication""" - # EndpointTestsQueries.get_object_options_auth(authenticated_client, "Risk Assessment", "lc_status", Project.PRJ_LC_STATUS) + # EndpointTestsQueries.get_object_options_auth(test.client, "Risk Assessment", "lc_status", Project.PRJ_LC_STATUS) From 94e73e1e2be6ed4bb1c41cef308453e2313d68c9 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 12:00:42 +0100 Subject: [PATCH 23/48] add risk scenarios api tests for the other user groups --- .../app_tests/api/test_api_risk_scenarios.py | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/backend/app_tests/api/test_api_risk_scenarios.py b/backend/app_tests/api/test_api_risk_scenarios.py index edc6ba20e..297b9ad66 100644 --- a/backend/app_tests/api/test_api_risk_scenarios.py +++ b/backend/app_tests/api/test_api_risk_scenarios.py @@ -11,6 +11,7 @@ ) from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic project data for tests @@ -147,23 +148,23 @@ def test_delete_risk_scenarios(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestRiskScenariosAuthenticated: """Perform tests on Risk Scenarios API endpoint with authentication""" - def test_get_risk_scenarios(self, authenticated_client): + def test_get_risk_scenarios(self, test): """test to get risk scenarios from the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") - folder = Folder.objects.create(name="testFolder") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") risk_assessment = RiskAssessment.objects.create( name="test", - project=Project.objects.create(name="testProject", folder=folder), + project=Project.objects.create(name="testProject", folder=test.folder), risk_matrix=RiskMatrix.objects.all()[0], ) - threat = Threat.objects.create(name="test", folder=folder) + threat = Threat.objects.create(name="test", folder=test.folder) EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Risk Scenarios", RiskScenario, { @@ -199,24 +200,24 @@ def test_get_risk_scenarios(self, authenticated_client): "str": risk_assessment.risk_matrix.name, }, }, + user_group=test.user_group, ) - def test_create_risk_scenarios(self, authenticated_client): + def test_create_risk_scenarios(self, test): """test to create risk scenarios with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") risk_assessment = RiskAssessment.objects.create( name="test", - project=Project.objects.create(name="test", folder=folder), + project=Project.objects.create(name="test", folder=test.folder), risk_matrix=RiskMatrix.objects.all()[0], ) - threat = Threat.objects.create(name="test", folder=folder) - asset = Asset.objects.create(name="test", folder=folder) - security_measures = SecurityMeasure.objects.create(name="test", folder=folder) + threat = Threat.objects.create(name="test", folder=test.folder) + asset = Asset.objects.create(name="test", folder=test.folder) + security_measures = SecurityMeasure.objects.create(name="test", folder=test.folder) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Risk Scenarios", RiskScenario, { @@ -258,18 +259,19 @@ def test_create_risk_scenarios(self, authenticated_client): {"id": str(security_measures.id), "str": security_measures.name} ], }, + user_group=test.user_group, ) - def test_update_risk_scenarios(self, authenticated_client): + def test_update_risk_scenarios(self, test): """test to update risk scenarios with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix2") - folder = Folder.objects.create(name="test") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix2") + folder = Folder.objects.create(name="test2") risk_assessment = RiskAssessment.objects.create( name="test", project=Project.objects.create( - name="test", folder=Folder.get_root_folder() + name="test", folder=test.folder ), risk_matrix=RiskMatrix.objects.all()[0], ) @@ -278,13 +280,13 @@ def test_update_risk_scenarios(self, authenticated_client): project=Project.objects.create(name="test2", folder=folder), risk_matrix=RiskMatrix.objects.all()[1], ) - threat = Threat.objects.create(name="test", folder=Folder.get_root_folder()) + threat = Threat.objects.create(name="test", folder=test.folder) threat2 = Threat.objects.create(name="test2", folder=folder) asset = Asset.objects.create(name="test", folder=folder) security_measures = SecurityMeasure.objects.create(name="test", folder=folder) EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Risk Scenarios", RiskScenario, { @@ -337,13 +339,14 @@ def test_update_risk_scenarios(self, authenticated_client): "str": risk_assessment.risk_matrix.name, }, }, + user_group=test.user_group, ) - def test_delete_risk_scenarios(self, authenticated_client): + def test_delete_risk_scenarios(self, test): """test to delete risk scenarios with the API with authentication""" - EndpointTestsQueries.Auth.import_object(authenticated_client, "Risk matrix") - folder = Folder.objects.create(name="testFolder") + EndpointTestsQueries.Auth.import_object(test.admin_client, "Risk matrix") + folder = test.folder risk_assessment = RiskAssessment.objects.create( name="test", project=Project.objects.create(name="testProject", folder=folder), @@ -352,7 +355,7 @@ def test_delete_risk_scenarios(self, authenticated_client): threat = Threat.objects.create(name="test", folder=folder) EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Risk Scenarios", RiskScenario, { @@ -360,14 +363,16 @@ def test_delete_risk_scenarios(self, authenticated_client): "risk_assessment": risk_assessment, "threats": [threat], }, + user_group=test.user_group, ) - def test_get_treatment_choices(self, authenticated_client): + def test_get_treatment_choices(self, test): """test to get risk scenarios treatment choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, + test.client, "Risk Scenarios", "treatment", RiskScenario.TREATMENT_OPTIONS, + user_group=test.user_group, ) From 980480e79dfdf0e259d2acb35fea4807cbb00960 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 12:12:22 +0100 Subject: [PATCH 24/48] add security functions api tests for the other user groups --- .../api/test_api_security_functions.py | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/backend/app_tests/api/test_api_security_functions.py b/backend/app_tests/api/test_api_security_functions.py index 32d7d16e3..c88dbfa4c 100644 --- a/backend/app_tests/api/test_api_security_functions.py +++ b/backend/app_tests/api/test_api_security_functions.py @@ -4,6 +4,7 @@ from core.models import SecurityFunction from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic security function data for tests @@ -85,14 +86,15 @@ def test_delete_security_functions(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestSecurityFunctionsAuthenticated: """Perform tests on Security Functions API endpoint with authentication""" - def test_get_security_functions(self, authenticated_client): + def test_get_security_functions(self, test): """test to get security functions from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Security functions", SecurityFunction, { @@ -105,13 +107,14 @@ def test_get_security_functions(self, authenticated_client): { "folder": {"str": Folder.get_root_folder().name}, }, + user_group=test.user_group, ) - def test_create_security_functions(self, authenticated_client): + def test_create_security_functions(self, test): """test to create security functions with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Security functions", SecurityFunction, { @@ -120,17 +123,18 @@ def test_create_security_functions(self, authenticated_client): "description": SECURITY_FUNCTION_DESCRIPTION, "urn": SECURITY_FUNCTION_URN, "provider": SECURITY_FUNCTION_PROVIDER, - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, }, + user_group=test.user_group, ) - def test_update_security_function_with_url(self, authenticated_client): + def test_update_security_function_with_url(self, test): """test to update an imported security function (with a URN) with the API with authentication""" EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Security functions", SecurityFunction, { @@ -146,18 +150,19 @@ def test_update_security_function_with_url(self, authenticated_client): "description": "new " + SECURITY_FUNCTION_DESCRIPTION, "urn": SECURITY_FUNCTION_URN, "provider": "new " + SECURITY_FUNCTION_PROVIDER, - "folder": str(Folder.objects.create(name="test").id), + "folder": str(test.folder.id), }, { "folder": {"str": Folder.get_root_folder().name}, }, fails=True, - expected_status=status.HTTP_400_BAD_REQUEST, + expected_status=status.HTTP_400_BAD_REQUEST, # Imported objects cannot be updated + user_group=test.user_group, ) - def test_update_security_function(self, authenticated_client): + def test_update_security_function(self, test): EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Security functions", SecurityFunction, { @@ -171,23 +176,25 @@ def test_update_security_function(self, authenticated_client): "name": SECURITY_FUNCTION_NAME, "description": "new " + SECURITY_FUNCTION_DESCRIPTION, "provider": "new " + SECURITY_FUNCTION_PROVIDER, - "folder": str(Folder.objects.create(name="test").id), + "folder": str(test.folder.id), }, { "folder": {"str": Folder.get_root_folder().name}, }, + user_group=test.user_group, ) - def test_delete_security_functions(self, authenticated_client): + def test_delete_security_functions(self, test): """test to delete security functions with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Security functions", SecurityFunction, { "ref_id": SECURITY_FUNCTION_REF_ID, "name": SECURITY_FUNCTION_NAME, - "folder": Folder.objects.create(name="test"), + "folder": test.folder, }, + user_group=test.user_group, ) From 4a6a8ec75a5f817443b5f696d079ee3f98c84a03 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 12:17:57 +0100 Subject: [PATCH 25/48] add security measures api tests for the other user groups --- .../api/test_api_security_measures.py | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/backend/app_tests/api/test_api_security_measures.py b/backend/app_tests/api/test_api_security_measures.py index c283ad2ae..779be5e19 100644 --- a/backend/app_tests/api/test_api_security_measures.py +++ b/backend/app_tests/api/test_api_security_measures.py @@ -3,6 +3,7 @@ from core.models import SecurityFunction, SecurityMeasure from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic security measure data for tests @@ -86,14 +87,15 @@ def test_delete_security_measures(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestSecurityMeasuresAuthenticated: """Perform tests on Security Measures API endpoint with authentication""" - def test_get_security_measures(self, authenticated_client): + def test_get_security_measures(self, test): """test to get security measures from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Security measures", SecurityMeasure, { @@ -104,26 +106,27 @@ def test_get_security_measures(self, authenticated_client): "link": SECURITY_MEASURE_LINK, "eta": SECURITY_MEASURE_ETA, "effort": SECURITY_MEASURE_EFFORT[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "security_function": None, "category": SECURITY_MEASURE_CATEGORY[1], "status": SECURITY_MEASURE_STATUS[1], "effort": SECURITY_MEASURE_EFFORT[1], }, + user_group=test.user_group, ) - def test_create_security_measures(self, authenticated_client): + def test_create_security_measures(self, test): """test to create security measures with the API with authentication""" security_function = SecurityFunction.objects.create( - name="test", typical_evidence={}, folder=Folder.objects.create(name="test") + name="test", typical_evidence={}, folder=Folder.objects.create(name="test2") ) EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Security measures", SecurityMeasure, { @@ -134,26 +137,27 @@ def test_create_security_measures(self, authenticated_client): "link": SECURITY_MEASURE_LINK, "eta": SECURITY_MEASURE_ETA, "effort": SECURITY_MEASURE_EFFORT[0], - "folder": str(Folder.get_root_folder().id), + "folder": str(test.folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "category": SECURITY_MEASURE_CATEGORY[1], "status": SECURITY_MEASURE_STATUS[1], "effort": SECURITY_MEASURE_EFFORT[1], }, + user_group=test.user_group, ) - def test_update_security_measures(self, authenticated_client): + def test_update_security_measures(self, test): """test to update security measures with the API with authentication""" - folder = Folder.objects.create(name="test") + folder = Folder.objects.create(name="test2") security_function = SecurityFunction.objects.create( name="test", typical_evidence={}, folder=folder ) EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Security measures", SecurityMeasure, { @@ -164,7 +168,7 @@ def test_update_security_measures(self, authenticated_client): "link": SECURITY_MEASURE_LINK, "eta": SECURITY_MEASURE_ETA, "effort": SECURITY_MEASURE_EFFORT[0], - "folder": Folder.get_root_folder(), + "folder": test.folder, }, { "name": "new " + SECURITY_MEASURE_NAME, @@ -177,49 +181,57 @@ def test_update_security_measures(self, authenticated_client): "folder": str(folder.id), }, { - "folder": {"str": Folder.get_root_folder().name}, + "folder": {"id": str(test.folder.id), "str": test.folder.name}, "category": SECURITY_MEASURE_CATEGORY[1], "status": SECURITY_MEASURE_STATUS[1], "effort": SECURITY_MEASURE_EFFORT[1], }, + user_group=test.user_group, ) - def test_delete_security_measures(self, authenticated_client): + def test_delete_security_measures(self, test): """test to delete security measures with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Security measures", SecurityMeasure, { "name": SECURITY_MEASURE_NAME, - "folder": Folder.objects.create(name="test"), + "folder": test.folder, }, + user_group=test.user_group, ) - def test_get_effort_choices(self, authenticated_client): + def test_get_effort_choices(self, test): """test to get security measures effort choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, "Security measures", "effort", SecurityMeasure.EFFORT + test.client, + "Security measures", + "effort", + SecurityMeasure.EFFORT, + user_group=test.user_group ) - def test_get_status_choices(self, authenticated_client): + def test_get_status_choices(self, test): """test to get security measures status choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, + test.client, "Security measures", "status", SecurityMeasure.Status.choices, + user_group=test.user_group, ) - def test_get_type_choices(self, authenticated_client): + def test_get_type_choices(self, test): """test to get security measures type choices from the API with authentication""" EndpointTestsQueries.Auth.get_object_options( - authenticated_client, + test.client, "Security measures", "category", SecurityMeasure.CATEGORY, + user_group=test.user_group, ) From de2b177bcea1a407d2ac05ad12e56170684a7917 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 13:13:21 +0100 Subject: [PATCH 26/48] add users api tests for the other user groups --- backend/app_tests/api/test_api_users.py | 45 +++++++++------ backend/app_tests/api/test_utils.py | 77 +++++++++++++++---------- 2 files changed, 74 insertions(+), 48 deletions(-) diff --git a/backend/app_tests/api/test_api_users.py b/backend/app_tests/api/test_api_users.py index 1985a08b4..8646f523d 100644 --- a/backend/app_tests/api/test_api_users.py +++ b/backend/app_tests/api/test_api_users.py @@ -4,7 +4,7 @@ from rest_framework.test import APIClient from iam.models import User -from test_vars import USERS_ENDPOINT as API_ENDPOINT +from test_vars import GROUPS_PERMISSIONS, USERS_ENDPOINT as API_ENDPOINT from test_utils import EndpointTestsQueries # Generic user data for tests @@ -72,57 +72,68 @@ def test_delete_users(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestUsersAuthenticated: """Perform tests on Users API endpoint with authentication""" - def test_get_users(self, authenticated_client): + def test_get_users(self, test): """test to get users from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Users", User, {"email": USER_EMAIL, "first_name": USER_FIRSTNAME, "last_name": USER_NAME}, - base_count=1, + base_count=2, + item_search_field="email", + user_group=test.user_group, ) - def test_create_users(self, authenticated_client): + def test_create_users(self, test): """test to create users with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Users", User, {"email": USER_EMAIL, "first_name": USER_FIRSTNAME, "last_name": USER_NAME}, - base_count=1, + base_count=2, + item_search_field="email", + user_group=test.user_group, ) - def test_update_users(self, authenticated_client): + def test_update_users(self, test): """test to update users with the API with authentication""" EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Users", User, - {"email": USER_EMAIL, "first_name": USER_FIRSTNAME, "last_name": USER_NAME}, + { + "email": USER_EMAIL, + "first_name": USER_FIRSTNAME, + "last_name": USER_NAME + }, { "email": "new" + USER_EMAIL, "first_name": "new" + USER_FIRSTNAME, "last_name": "new" + USER_NAME, }, + user_group=test.user_group, ) - def test_delete_users(self, authenticated_client): + def test_delete_users(self, test): """test to delete users with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Users", User, {"email": USER_EMAIL, "first_name": USER_FIRSTNAME, "last_name": USER_NAME}, + user_group=test.user_group, ) - def test_uniqueness_emails(self, authenticated_client): + def test_uniqueness_emails(self, test): """test to create users with the API with authentication and already existing email""" url = reverse(API_ENDPOINT) @@ -133,11 +144,11 @@ def test_uniqueness_emails(self, authenticated_client): } # Uses the API endpoint to create a user - response = authenticated_client.post(url, data, format="json") + response = test.admin_client.post(url, data, format="json") assert response.status_code == status.HTTP_201_CREATED # Uses the API endpoint to create another user with the same email - response = authenticated_client.post(url, data, format="json") + response = test.admin_client.post(url, data, format="json") # Asserts that the user was not created assert ( @@ -147,7 +158,7 @@ def test_uniqueness_emails(self, authenticated_client): "email": ["user with this email already exists."] }, "users can be created with an already used email" - def test_invalid_emails(self, authenticated_client): + def test_invalid_emails(self, test): """test to create users with the API with authentication and invalid emails""" url = reverse(API_ENDPOINT) @@ -169,7 +180,7 @@ def test_invalid_emails(self, authenticated_client): } # Uses the API endpoint to create a user - response = authenticated_client.post(url, data, format="json") + response = test.admin_client.post(url, data, format="json") # Asserts that the user was not created assert ( diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index 3ab2f9da9..67d18ba55 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -286,6 +286,7 @@ def get_object( build_params: dict = {}, test_params: dict = {}, base_count: int = 0, + item_search_field: str = None, endpoint: str = None, fails: bool = False, expected_status: int = status.HTTP_200_OK, @@ -388,17 +389,22 @@ def get_object( ), f"{verbose_name} are not accessible with authentication" if not (fails or user_perm_fails): - for key, value in {**build_params, **test_params}.items(): + params = {**build_params, **test_params} + if response.json()["count"] > 0 and item_search_field: + response_item = [res for res in response.json()["results"] if res[item_search_field] == params[item_search_field]][0] + else: + response_item = response.json()["results"][-1] + for key, value in params.items(): if ( type(value) == dict - and type(response.json()["results"][-1][key]) == str + and type(response_item[key]) == str ): assert ( - json.loads(response.json()["results"][-1][key]) == value + json.loads(response_item[key]) == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" else: assert ( - response.json()["results"][-1][key] == value + response_item[key] == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" def get_object_options( @@ -456,6 +462,7 @@ def create_object( build_params: dict, test_params: dict = {}, base_count: int = 0, + item_search_field: str = None, endpoint: str | None = None, query_format: str = "json", fails: bool = False, @@ -525,24 +532,29 @@ def create_object( response.status_code == status.HTTP_200_OK ), f"{verbose_name} are not accessible with authentication" - for key, value in {**build_params, **test_params}.items(): - if not (fails or user_perm_fails): + if not (fails or user_perm_fails): + params = {**build_params, **test_params} + if response.json()["count"] > 0 and item_search_field: + response_item = [res for res in response.json()["results"] if res[item_search_field] == params[item_search_field]][0] + else: + response_item = response.json()["results"][base_count] + for key, value in params.items(): if ( key == "attachment" - and response.json()["results"][base_count][key] != value + and response_item[key] != value ): # Asserts that the value file name is present in the JSON response assert ( re.sub( r"_([a-z]|[A-Z]|[0-9]){7}(?:\.)", ".", - response.json()["results"][base_count][key], + response_item[key], ) == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" else: assert ( - response.json()["results"][base_count][key] == value + response_item[key] == value ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" def update_object( @@ -609,16 +621,17 @@ def update_object( response.status_code == status.HTTP_403_FORBIDDEN ), f"{verbose_name} object detail can be accessed without permission" - for key, value in {**build_params, **test_build_params}.items(): - if key == "attachment": - # Asserts that the value file name is present in the JSON response - assert ( - value.name.split("/")[-1].split(".")[0] in response.json()[key] - ), f"{verbose_name} {key.replace('_', ' ')} returned by the API after object creation don't match the provided {key.replace('_', ' ')}" - else: - assert ( - response.json()[key] == value - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + if not (fails or user_perm_fails): + for key, value in {**build_params, **test_build_params}.items(): + if key == "attachment": + # Asserts that the value file name is present in the JSON response + assert ( + value.name.split("/")[-1].split(".")[0] in response.json()[key] + ), f"{verbose_name} {key.replace('_', ' ')} returned by the API after object creation don't match the provided {key.replace('_', ' ')}" + else: + assert ( + response.json()[key] == value + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" update_response = authenticated_client.patch( url, update_params, format=query_format @@ -634,18 +647,20 @@ def update_object( assert ( update_response.status_code == user_perm_expected_status ), f"{verbose_name} can be updated without permission" if expected_status == status.HTTP_200_OK else f"Updating {verbose_name.lower()} should give a status {user_perm_expected_status}" - for key, value in {**build_params, **update_params, **test_params}.items(): - if not (fails or user_perm_fails): - if key == "attachment" and update_response.json()[key] != value: - # Asserts that the value file name is present in the JSON response - assert ( - value.split("/")[-1].split(".")[0] - in update_response.json()[key] - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" - else: - assert ( - update_response.json()[key] == value - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + + if not (fails or user_perm_fails): + for key, value in {**build_params, **update_params, **test_params}.items(): + if not (fails or user_perm_fails): + if key == "attachment" and update_response.json()[key] != value: + # Asserts that the value file name is present in the JSON response + assert ( + value.split("/")[-1].split(".")[0] + in update_response.json()[key] + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + else: + assert ( + update_response.json()[key] == value + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" def delete_object( authenticated_client, From d7d10e5ec7abdb541b86d6d2ce934ac21bef2749 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 14:52:03 +0100 Subject: [PATCH 27/48] fix tests error due to missing key --- backend/app_tests/api/test_utils.py | 27 +++++++++++++-------------- backend/app_tests/test_vars.py | 1 - 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index 67d18ba55..e32a5bcfa 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -388,9 +388,9 @@ def get_object( response.json()["count"] == base_count + 1 ), f"{verbose_name} are not accessible with authentication" - if not (fails or user_perm_fails): + if not (fails or user_perm_fails) and len(response.json()["results"]) != 0: params = {**build_params, **test_params} - if response.json()["count"] > 0 and item_search_field: + if len(response.json()["results"]) > 0 and item_search_field: response_item = [res for res in response.json()["results"] if res[item_search_field] == params[item_search_field]][0] else: response_item = response.json()["results"][-1] @@ -532,7 +532,7 @@ def create_object( response.status_code == status.HTTP_200_OK ), f"{verbose_name} are not accessible with authentication" - if not (fails or user_perm_fails): + if not (fails or user_perm_fails) and len(response.json()["results"]) != 0: params = {**build_params, **test_params} if response.json()["count"] > 0 and item_search_field: response_item = [res for res in response.json()["results"] if res[item_search_field] == params[item_search_field]][0] @@ -650,17 +650,16 @@ def update_object( if not (fails or user_perm_fails): for key, value in {**build_params, **update_params, **test_params}.items(): - if not (fails or user_perm_fails): - if key == "attachment" and update_response.json()[key] != value: - # Asserts that the value file name is present in the JSON response - assert ( - value.split("/")[-1].split(".")[0] - in update_response.json()[key] - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" - else: - assert ( - update_response.json()[key] == value - ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + if key == "attachment" and update_response.json()[key] != value: + # Asserts that the value file name is present in the JSON response + assert ( + value.split("/")[-1].split(".")[0] + in update_response.json()[key] + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" + else: + assert ( + update_response.json()[key] == value + ), f"{verbose_name} {key.replace('_', ' ')} queried from the API don't match {verbose_name.lower()} {key.replace('_', ' ')} in the database" def delete_object( authenticated_client, diff --git a/backend/app_tests/test_vars.py b/backend/app_tests/test_vars.py index 74c75dd15..1b2c749a7 100644 --- a/backend/app_tests/test_vars.py +++ b/backend/app_tests/test_vars.py @@ -106,7 +106,6 @@ "delete_framework", "view_requirementnode", "view_requirementlevel", # Permits to see the object on api by an admin - "add_library", "view_library", "delete_library", "backup", From 386f768e783cf5682b9103fc5b980a7a910190e0 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 15:14:23 +0100 Subject: [PATCH 28/48] add folders api tests for the other user groups --- backend/app_tests/api/test_api_folders.py | 43 ++++++++++++++++------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/backend/app_tests/api/test_api_folders.py b/backend/app_tests/api/test_api_folders.py index d10220044..47012a3f3 100644 --- a/backend/app_tests/api/test_api_folders.py +++ b/backend/app_tests/api/test_api_folders.py @@ -2,6 +2,7 @@ from rest_framework.test import APIClient from iam.models import Folder +from test_vars import GROUPS_PERMISSIONS from test_utils import EndpointTestsQueries # Generic folder data for tests @@ -61,67 +62,83 @@ def test_delete_folders(self): @pytest.mark.django_db +@pytest.mark.parametrize("test", GROUPS_PERMISSIONS.keys(), ids=[GROUPS_PERMISSIONS[key]["name"] for key in GROUPS_PERMISSIONS.keys()], indirect=True) class TestFoldersAuthenticated: """Perform tests on Folders API endpoint with authentication""" - def test_get_folders(self, authenticated_client): + def test_get_folders(self, test): """test to get folders from the API with authentication""" EndpointTestsQueries.Auth.get_object( - authenticated_client, + test.client, "Folders", Folder, - {"name": FOLDER_NAME, "description": FOLDER_DESCRIPTION}, { - "parent_folder": {"str": Folder.get_root_folder().name}, + "name": FOLDER_NAME, + "description": FOLDER_DESCRIPTION, + "parent_folder": test.folder, + }, + { + "parent_folder": {"id": str(test.folder.id), "str": test.folder.name}, "content_type": FOLDER_CONTENT_TYPE, }, + base_count=-1, + user_group=test.user_group, ) - def test_create_folders(self, authenticated_client): + def test_create_folders(self, test): """test to create folders with the API with authentication""" EndpointTestsQueries.Auth.create_object( - authenticated_client, + test.client, "Folders", Folder, { "name": FOLDER_NAME, "description": FOLDER_DESCRIPTION, - "parent_folder": str(Folder.get_root_folder().id), + "parent_folder": str(test.folder.id), }, { - "parent_folder": {"str": Folder.get_root_folder().name}, + "parent_folder": {"id": str(test.folder.id), "str": test.folder.name}, "content_type": FOLDER_CONTENT_TYPE, }, + base_count=-1, + user_group=test.user_group, ) - def test_update_folders(self, authenticated_client): + def test_update_folders(self, test): """test to update folders with the API with authentication""" EndpointTestsQueries.Auth.update_object( - authenticated_client, + test.client, "Folders", Folder, { "name": FOLDER_NAME, "description": FOLDER_DESCRIPTION, + "parent_folder": test.folder, }, { "name": "new " + FOLDER_NAME, "description": "new " + FOLDER_DESCRIPTION, - "parent_folder": str(Folder.objects.create(name="test").id), + "parent_folder": str(Folder.objects.create(name="test2").id), + }, + { + "parent_folder": {"id": str(test.folder.id), "str": test.folder.name}, }, + user_group=test.user_group, ) - def test_delete_folders(self, authenticated_client): + def test_delete_folders(self, test): """test to delete folders with the API with authentication""" EndpointTestsQueries.Auth.delete_object( - authenticated_client, + test.client, "Folders", Folder, { "name": FOLDER_NAME, + "parent_folder": test.folder, }, + user_group=test.user_group, ) From 9c7d94f418d7b5cdfa030bcb077125314b3b4039 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 16:38:25 +0100 Subject: [PATCH 29/48] fix some api tests error messages --- backend/app_tests/api/test_utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/app_tests/api/test_utils.py b/backend/app_tests/api/test_utils.py index e32a5bcfa..e81471256 100644 --- a/backend/app_tests/api/test_utils.py +++ b/backend/app_tests/api/test_utils.py @@ -322,7 +322,7 @@ def get_object( # User does not have permission to view the object assert ( response.status_code == user_perm_expected_status - ), f"{verbose_name} are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} are accessible without permission" if response.status_code == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" if ( base_count == 0 @@ -376,7 +376,7 @@ def get_object( # User does not have permission to view the object assert ( response.status_code == user_perm_expected_status - ), f"{verbose_name} are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} are accessible without permission" if response.status_code == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} should give a status {user_perm_expected_status}" if not (fails or user_perm_fails): if base_count < 0: @@ -444,7 +444,7 @@ def get_object_options( # User does not have permission to view the object assert ( response.status_code == user_perm_expected_status - ), f"{verbose_name} {option} choices are accessible without permission" if expected_status == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} {option} should give a status {user_perm_expected_status}" + ), f"{verbose_name} {option} choices are accessible without permission" if response.status_code == status.HTTP_200_OK else f"Accessing {verbose_name.lower()} {option} should give a status {user_perm_expected_status}" if not (fails or user_perm_fails): for choice in choices: @@ -507,7 +507,7 @@ def create_object( # User does not have permission to create the object assert ( response.status_code == user_perm_expected_status - ), f"{verbose_name} can be created without permission" if expected_status == status.HTTP_201_CREATED else f"Creating {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} can be created without permission" if response.status_code == status.HTTP_201_CREATED else f"Creating {verbose_name.lower()} should give a status {user_perm_expected_status}" for key, value in build_params.items(): if key == "attachment": @@ -646,7 +646,7 @@ def update_object( # User does not have permission to update the object assert ( update_response.status_code == user_perm_expected_status - ), f"{verbose_name} can be updated without permission" if expected_status == status.HTTP_200_OK else f"Updating {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} can be updated without permission" if update_response.status_code == status.HTTP_200_OK else f"Updating {verbose_name.lower()} should give a status {user_perm_expected_status}" if not (fails or user_perm_fails): for key, value in {**build_params, **update_params, **test_params}.items(): @@ -732,7 +732,7 @@ def delete_object( # User does not have permission to delete the object assert ( delete_response.status_code == user_perm_expected_status - ), f"{verbose_name} can be deleted without permission" if expected_status == status.HTTP_204_NO_CONTENT else f"Deleting {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} can be deleted without permission" if delete_response.status_code == status.HTTP_204_NO_CONTENT else f"Deleting {verbose_name.lower()} should give a status {user_perm_expected_status}" if not (fails or user_perm_fails): # Asserts that the objects does not exists anymore @@ -775,7 +775,7 @@ def import_object( # User does not have permission to import the library assert ( response.status_code == user_perm_expected_status - ), f"{verbose_name} can be imported without permission" if expected_status == status.HTTP_200_OK else f"Importing {verbose_name.lower()} should give a status {user_perm_expected_status}" + ), f"{verbose_name} can be imported without permission" if response.status_code == status.HTTP_200_OK else f"Importing {verbose_name.lower()} should give a status {user_perm_expected_status}" if not (fails or user_perm_fails): assert response.json() == { From 57ca39d6748b2c43ec31719f0f4d1e918124227b Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 17:24:47 +0100 Subject: [PATCH 30/48] add and api tests reports to allow easier debuging --- .github/workflows/backend-api-tests.yml | 8 +++++++- backend/.gitignore | 1 + backend/pytest.ini | 1 + backend/requirements.txt | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backend-api-tests.yml b/.github/workflows/backend-api-tests.yml index 1153bfcaf..13fac804d 100644 --- a/.github/workflows/backend-api-tests.yml +++ b/.github/workflows/backend-api-tests.yml @@ -57,4 +57,10 @@ jobs: working-directory: ${{env.working-directory}} run: | export $(grep -v '^#' .env | xargs) - pytest app_tests/api \ No newline at end of file + pytest app_tests/api --html=pytest-report.html --self-contained-html + - uses: actions/upload-artifact@v4 + if: always() + with: + name: api-tests-report + path: pytest-report.html + retention-days: 5 \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore index 66db79d2a..2ba5b3ed8 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -17,3 +17,4 @@ db/django_secret_key db/pg_password.txt ./db/ .coverage +pytest-report.html \ No newline at end of file diff --git a/backend/pytest.ini b/backend/pytest.ini index 0c8d5e8d8..cd7dc895f 100644 --- a/backend/pytest.ini +++ b/backend/pytest.ini @@ -1,6 +1,7 @@ # pytest.ini [pytest] DJANGO_SETTINGS_MODULE = ciso_assistant.settings +generate_report_on_test=True # -- recommended but optional: python_files = *_test.py test_*.py addopts = -p no:warnings diff --git a/backend/requirements.txt b/backend/requirements.txt index 40dbc4fd1..ec48892e6 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -3,6 +3,7 @@ weasyprint==60.2 psycopg2-binary==2.9.9 gunicorn==21.2.0 pytest-django==4.8.0 +pytest-html==1.1.1 django-filter==23.5 whitenoise==6.6.0 argon2-cffi==23.1.0 From 267257dd28083a024f2de31008aa23b320bc7aa3 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 23 Feb 2024 17:30:46 +0100 Subject: [PATCH 31/48] Fix requirements.txt --- backend/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index ec48892e6..0e716e4a0 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -3,7 +3,7 @@ weasyprint==60.2 psycopg2-binary==2.9.9 gunicorn==21.2.0 pytest-django==4.8.0 -pytest-html==1.1.1 +pytest-html==4.1.1 django-filter==23.5 whitenoise==6.6.0 argon2-cffi==23.1.0 From db0a216782ede5627c38e3bb4c0223aaa756b90a Mon Sep 17 00:00:00 2001 From: monsieurswag Date: Wed, 21 Feb 2024 10:04:01 +0100 Subject: [PATCH 32/48] Make The website work offline by using font-awesome locally --- frontend/package-lock.json | 10 ++++++++++ frontend/package.json | 1 + frontend/src/app.html | 8 +------- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9010e8e22..ce7eaeff6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "dependencies": { "@floating-ui/dom": "^1.5.1", + "@fortawesome/fontawesome-free": "^6.5.1", "@inlang/paraglide-js-adapter-vite": "^1.2.14", "dotenv": "^16.4.1", "echarts": "^5.4.3", @@ -2765,6 +2766,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.1.tgz", + "integrity": "sha512-CNy5vSwN3fsUStPRLX7fUYojyuzoEMSXPl7zSLJ8TgtRfjv24LOnOWKT2zYwaHZCJGkdyRnTmstR0P+Ah503Gw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", diff --git a/frontend/package.json b/frontend/package.json index 101c2e6df..8ff4722ad 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -74,6 +74,7 @@ "type": "module", "dependencies": { "@floating-ui/dom": "^1.5.1", + "@fortawesome/fontawesome-free": "^6.5.1", "@inlang/paraglide-js-adapter-vite": "^1.2.14", "dotenv": "^16.4.1", "echarts": "^5.4.3", diff --git a/frontend/src/app.html b/frontend/src/app.html index ff6d832aa..06cf9318e 100644 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -3,13 +3,7 @@ - + %sveltekit.head%