diff --git a/apps/api/plane/app/views/project/member.py b/apps/api/plane/app/views/project/member.py index e747f573e74..db280046495 100644 --- a/apps/api/plane/app/views/project/member.py +++ b/apps/api/plane/app/views/project/member.py @@ -202,7 +202,7 @@ def retrieve(self, request, slug, project_id, pk): return Response(serializer.data, status=status.HTTP_200_OK) - @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) + @allow_permission([ROLE.ADMIN]) def partial_update(self, request, slug, project_id, pk): project_member = ProjectMember.objects.get(pk=pk, workspace__slug=slug, project_id=project_id, is_active=True) diff --git a/apps/api/plane/tests/contract/app/test_project_app.py b/apps/api/plane/tests/contract/app/test_project_app.py index 979c5e805c4..b5284fbda5f 100644 --- a/apps/api/plane/tests/contract/app/test_project_app.py +++ b/apps/api/plane/tests/contract/app/test_project_app.py @@ -522,3 +522,33 @@ def test_delete_project_unauthenticated(self, client, workspace): assert response.status_code == status.HTTP_401_UNAUTHORIZED assert Project.objects.filter(id=project.id).exists() + + +@pytest.mark.contract +class TestProjectMemberAPI(TestProjectBase): + @pytest.mark.django_db + def test_guest_cannot_deactivate_another_project_member(self, session_client, workspace): + project = Project.objects.create(name="Member Protected", identifier="MP", workspace=workspace) + + guest_user = User.objects.create_user(email="project-guest@example.com", username="project-guest") + victim_user = User.objects.create_user(email="project-member@example.com", username="project-member") + + WorkspaceMember.objects.create(workspace=workspace, member=guest_user, role=5, is_active=True) + WorkspaceMember.objects.create(workspace=workspace, member=victim_user, role=15, is_active=True) + + ProjectMember.objects.create(project=project, member=guest_user, role=5, is_active=True) + victim_project_member = ProjectMember.objects.create( + project=project, + member=victim_user, + role=15, + is_active=True, + ) + + session_client.force_authenticate(user=guest_user) + + url = f"/api/workspaces/{workspace.slug}/projects/{project.id}/members/{victim_project_member.id}/" + response = session_client.patch(url, {"is_active": False}, format="json") + + assert response.status_code == status.HTTP_403_FORBIDDEN + victim_project_member.refresh_from_db() + assert victim_project_member.is_active is True