ds.allowed() is now keyword-argument only, closes #2519

This commit is contained in:
Simon Willison 2025-10-23 09:25:33 -07:00
commit 159b9f3fec
2 changed files with 31 additions and 12 deletions

View file

@ -1369,6 +1369,7 @@ class Datasette:
async def allowed( async def allowed(
self, self,
*,
action: str, action: str,
resource: "Resource", resource: "Resource",
actor: dict | None = None, actor: dict | None = None,
@ -1382,9 +1383,9 @@ class Datasette:
Example: Example:
from datasette.resources import TableResource from datasette.resources import TableResource
can_view = await datasette.allowed( can_view = await datasette.allowed(
"view-table", action="view-table",
TableResource(database="analytics", table="users"), resource=TableResource(database="analytics", table="users"),
actor actor=actor
) )
""" """
from datasette.utils.actions_sql import check_permission_for_resource from datasette.utils.actions_sql import check_permission_for_resource

View file

@ -113,13 +113,19 @@ async def test_allowed_specific_resource(test_ds):
# Check specific resources using allowed() # Check specific resources using allowed()
# This should use SQL WHERE clause, not fetch all resources # This should use SQL WHERE clause, not fetch all resources
assert await test_ds.allowed( assert await test_ds.allowed(
"view-table", TableResource("analytics", "users"), actor action="view-table",
resource=TableResource("analytics", "users"),
actor=actor,
) )
assert await test_ds.allowed( assert await test_ds.allowed(
"view-table", TableResource("analytics", "events"), actor action="view-table",
resource=TableResource("analytics", "events"),
actor=actor,
) )
assert not await test_ds.allowed( assert not await test_ds.allowed(
"view-table", TableResource("production", "orders"), actor action="view-table",
resource=TableResource("production", "orders"),
actor=actor,
) )
finally: finally:
@ -200,10 +206,14 @@ async def test_child_deny_overrides_parent_allow(test_ds):
# Verify with allowed() method # Verify with allowed() method
assert await test_ds.allowed( assert await test_ds.allowed(
"view-table", TableResource("analytics", "users"), actor action="view-table",
resource=TableResource("analytics", "users"),
actor=actor,
) )
assert not await test_ds.allowed( assert not await test_ds.allowed(
"view-table", TableResource("analytics", "sensitive"), actor action="view-table",
resource=TableResource("analytics", "sensitive"),
actor=actor,
) )
finally: finally:
@ -240,10 +250,14 @@ async def test_child_allow_overrides_parent_deny(test_ds):
# Verify with allowed() method # Verify with allowed() method
assert await test_ds.allowed( assert await test_ds.allowed(
"view-table", TableResource("production", "orders"), actor action="view-table",
resource=TableResource("production", "orders"),
actor=actor,
) )
assert not await test_ds.allowed( assert not await test_ds.allowed(
"view-table", TableResource("production", "customers"), actor action="view-table",
resource=TableResource("production", "customers"),
actor=actor,
) )
finally: finally:
@ -301,10 +315,14 @@ async def test_sql_does_filtering_not_python(test_ds):
# allowed() should execute a targeted SQL query # allowed() should execute a targeted SQL query
# NOT fetch all resources and filter in Python # NOT fetch all resources and filter in Python
assert await test_ds.allowed( assert await test_ds.allowed(
"view-table", TableResource("analytics", "users"), actor action="view-table",
resource=TableResource("analytics", "users"),
actor=actor,
) )
assert not await test_ds.allowed( assert not await test_ds.allowed(
"view-table", TableResource("analytics", "events"), actor action="view-table",
resource=TableResource("analytics", "events"),
actor=actor,
) )
# allowed_resources() should also use SQL filtering # allowed_resources() should also use SQL filtering