From 110bd545c963a5e000f374cbc5b8bdfe7f9dcf6d Mon Sep 17 00:00:00 2001 From: Manish Gupta Date: Fri, 24 Jul 2026 15:13:13 +0530 Subject: [PATCH] [WEB-8372] fix: invalidate states cache on partial_update + strengthen member test (CodeRabbit/Copilot #9473) - Copilot: partial_update mutates state data but (unlike create/destroy/ mark_as_default) did not invalidate the workspaces/:slug/states/ cache, so clients could see stale state after a PATCH. Add the same @invalidate_cache decorator as the sibling writes. - CodeRabbit: member test now also sends default=True and asserts it stays False, matching the guest regression coverage. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/api/plane/app/views/state/base.py | 1 + .../app/test_state_partial_update_admin_scope_app.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/api/plane/app/views/state/base.py b/apps/api/plane/app/views/state/base.py index 9067a6e2e9..af7acae5a3 100644 --- a/apps/api/plane/app/views/state/base.py +++ b/apps/api/plane/app/views/state/base.py @@ -62,6 +62,7 @@ class StateViewSet(BaseViewSet): # the sibling create/destroy/mark_as_default writes. Previously [ADMIN, MEMBER, GUEST] # let a Guest rewrite any state (incl. setting `default`, bypassing the admin-only # mark_as_default). See GHSA-4jpp-964m-27cr. + @invalidate_cache(path="workspaces/:slug/states/", url_params=True, user=False) @allow_permission([ROLE.ADMIN]) def partial_update(self, request, slug, project_id, pk): try: diff --git a/apps/api/plane/tests/contract/app/test_state_partial_update_admin_scope_app.py b/apps/api/plane/tests/contract/app/test_state_partial_update_admin_scope_app.py index f98184b395..2aacfe0ee2 100644 --- a/apps/api/plane/tests/contract/app/test_state_partial_update_admin_scope_app.py +++ b/apps/api/plane/tests/contract/app/test_state_partial_update_admin_scope_app.py @@ -75,13 +75,16 @@ class TestStatePartialUpdateAdminScope: def test_member_cannot_patch_state(self, workspace, project, state): member_client = _member_of(workspace, project, role=15) response = member_client.patch( - _state_url(workspace.slug, project.id, state.id), {"name": "Member Renamed"}, format="json" + _state_url(workspace.slug, project.id, state.id), + {"name": "Member Renamed", "default": True}, + format="json", ) assert response.status_code == status.HTTP_403_FORBIDDEN, ( f"Got {response.status_code}: {getattr(response, 'data', None)!r}" ) state.refresh_from_db() assert state.name == "Backlog" + assert state.default is False def test_admin_can_patch_state(self, session_client, workspace, project, state): """Positive control: a project admin may still edit a state."""