Fix /-/check 500 for query actions (#2756)

_check_permission_for_actor() constructed child resources with
resource_class(database=parent, table=child), but QueryResource takes a
"query" argument, not "table", so /-/check?action=delete-query (and
view-query / update-query) raised TypeError. Construct the resource
positionally so it works for any child resource class.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Simon Willison 2026-06-10 23:27:13 -07:00
commit d5141a5778
2 changed files with 28 additions and 3 deletions

View file

@ -497,11 +497,13 @@ async def _check_permission_for_actor(ds, action, parent, child, actor):
if action_obj.resource_class is None:
resource_obj = None
elif action_obj.takes_parent and action_obj.takes_child:
# Child-level resource (e.g., TableResource, QueryResource)
resource_obj = action_obj.resource_class(database=parent, table=child)
# Child-level resource (e.g., TableResource, QueryResource). The child
# argument is named differently per resource class (table, query, ...),
# so pass positionally - https://github.com/simonw/datasette/issues/2756
resource_obj = action_obj.resource_class(parent, child)
elif action_obj.takes_parent:
# Parent-level resource (e.g., DatabaseResource)
resource_obj = action_obj.resource_class(database=parent)
resource_obj = action_obj.resource_class(parent)
else:
# This shouldn't happen given validation in Action.__post_init__
return {"error": f"Invalid action configuration: {action}"}, 500

View file

@ -1733,6 +1733,29 @@ async def test_permission_check_view_requires_debug_permission():
assert data["allowed"] is True
@pytest.mark.asyncio
@pytest.mark.parametrize("action", ("view-query", "update-query", "delete-query"))
async def test_permission_check_view_query_actions(action):
# https://github.com/simonw/datasette/issues/2756
# QueryResource takes a "query" argument, not "table", so /-/check must
# not assume every child resource class accepts table=
ds = Datasette()
ds.root_enabled = True
root_token = await ds.create_token("root", handler="signed")
response = await ds.client.get(
f"/-/check.json?action={action}&parent=mydb&child=myquery",
headers={"Authorization": f"Bearer {root_token}"},
)
assert response.status_code == 200
data = response.json()
assert data["action"] == action
assert data["resource"] == {
"parent": "mydb",
"child": "myquery",
"path": "/mydb/myquery",
}
@pytest.mark.asyncio
async def test_root_allow_block_with_table_restricted_actor():
"""