[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) <noreply@anthropic.com>
This commit is contained in:
Manish Gupta
2026-07-24 15:13:13 +05:30
parent 73675d7e34
commit 110bd545c9
2 changed files with 5 additions and 1 deletions

View File

@@ -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:

View File

@@ -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."""