Permissions SQL API improvements (#2558)

* Neater design for PermissionSQL class, refs #2556
  - source is now automatically set to the source plugin
  - params is optional
* PermissionSQL.allow() and PermissionSQL.deny() shortcuts

Closes #2556

* Filter out temp database from attached_databases()

Refs https://github.com/simonw/datasette/issues/2557#issuecomment-3470510837
This commit is contained in:
Simon Willison 2025-10-30 15:48:46 -07:00 committed by GitHub
commit 6a71bde37f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 241 additions and 227 deletions

View file

@ -58,7 +58,7 @@ async def test_tables_endpoint_global_access(test_ds):
def rules_callback(datasette, actor, action):
if actor and actor.get("id") == "alice":
sql = "SELECT NULL AS parent, NULL AS child, 1 AS allow, 'global: alice has access' AS reason"
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)
@ -98,7 +98,7 @@ async def test_tables_endpoint_database_restriction(test_ds):
if actor and actor.get("role") == "analyst":
# Allow only analytics database
sql = "SELECT 'analytics' AS parent, NULL AS child, 1 AS allow, 'analyst access' AS reason"
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)
@ -145,7 +145,7 @@ async def test_tables_endpoint_table_exception(test_ds):
UNION ALL
SELECT 'analytics' AS parent, 'users' AS child, 1 AS allow, 'carol exception' AS reason
"""
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)
@ -187,7 +187,7 @@ async def test_tables_endpoint_deny_overrides_allow(test_ds):
UNION ALL
SELECT 'analytics' AS parent, 'sensitive' AS child, 0 AS allow, 'deny sensitive' AS reason
"""
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)
@ -253,7 +253,7 @@ async def test_tables_endpoint_specific_table_only(test_ds):
UNION ALL
SELECT 'production' AS parent, 'orders' AS child, 1 AS allow, 'specific table 2' AS reason
"""
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)
@ -291,7 +291,7 @@ async def test_tables_endpoint_empty_result(test_ds):
if actor and actor.get("id") == "blocked":
# Global deny
sql = "SELECT NULL AS parent, NULL AS child, 0 AS allow, 'global deny' AS reason"
return PermissionSQL(source="test", sql=sql, params={})
return PermissionSQL(sql=sql)
return None
plugin = PermissionRulesPlugin(rules_callback)