diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 4efe7cab63..581e0d0e97 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -3382,6 +3382,26 @@ class TestRoleViewSet: errors = response.json()["errors"] assert errors[0]["source"]["pointer"] == "/data/attributes/name" + def test_admin_role_partial_update(self, authenticated_client, admin_role_fixture): + role = admin_role_fixture + data = { + "data": { + "id": str(role.id), + "type": "roles", + "attributes": { + "name": "Updated Role", + }, + } + } + response = authenticated_client.patch( + reverse("role-detail", kwargs={"pk": role.id}), + data=json.dumps(data), + content_type="application/vnd.api+json", + ) + assert response.status_code == status.HTTP_400_BAD_REQUEST + role.refresh_from_db() + assert role.name != "Updated Role" + def test_role_partial_update(self, authenticated_client, roles_fixture): role = roles_fixture[1] data = { @@ -3389,7 +3409,7 @@ class TestRoleViewSet: "id": str(role.id), "type": "roles", "attributes": { - "name": "Updated Provider Group Name", + "name": "Updated Role", }, } } @@ -3400,7 +3420,7 @@ class TestRoleViewSet: ) assert response.status_code == status.HTTP_200_OK role.refresh_from_db() - assert role.name == "Updated Provider Group Name" + assert role.name == "Updated Role" def test_role_partial_update_invalid(self, authenticated_client, roles_fixture): role = roles_fixture[2] @@ -3422,6 +3442,14 @@ class TestRoleViewSet: errors = response.json()["errors"] assert errors[0]["source"]["pointer"] == "/data/attributes/name" + def test_role_destroy_admin(self, authenticated_client, admin_role_fixture): + role = admin_role_fixture + response = authenticated_client.delete( + reverse("role-detail", kwargs={"pk": role.id}) + ) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert Role.objects.filter(id=role.id).exists() + def test_role_destroy(self, authenticated_client, roles_fixture): role = roles_fixture[2] response = authenticated_client.delete( diff --git a/api/src/backend/api/v1/views.py b/api/src/backend/api/v1/views.py index ce24a2f830..17419fa634 100644 --- a/api/src/backend/api/v1/views.py +++ b/api/src/backend/api/v1/views.py @@ -1636,6 +1636,15 @@ class RoleViewSet(BaseRLSViewSet): request.data["manage_account"] = str(user_role.manage_account).lower() return super().partial_update(request, *args, **kwargs) + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if ( + instance.name == "admin" + ): # TODO: Move to a constant/enum (in case other roles are created by default) + raise ValidationError(detail="The admin role cannot be deleted.") + + return super().destroy(request, *args, **kwargs) + @extend_schema_view( create=extend_schema( diff --git a/api/src/backend/conftest.py b/api/src/backend/conftest.py index 77b9bc41d3..014e660480 100644 --- a/api/src/backend/conftest.py +++ b/api/src/backend/conftest.py @@ -395,6 +395,23 @@ def provider_groups_fixture(tenants_fixture): return pgroup1, pgroup2, pgroup3 +@pytest.fixture +def admin_role_fixture(tenants_fixture): + tenant, *_ = tenants_fixture + + return Role.objects.get_or_create( + name="admin", + tenant_id=tenant.id, + manage_users=True, + manage_account=True, + manage_billing=True, + manage_providers=True, + manage_integrations=True, + manage_scans=True, + unlimited_visibility=True, + )[0] + + @pytest.fixture def roles_fixture(tenants_fixture): tenant, *_ = tenants_fixture