mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Update test infrastructure to use register_actions hook
- Consolidated register_permissions and register_actions hooks in my_plugin.py - Added permission_resources_sql hook to provide SQL-based permission rules - Updated conftest.py to reference datasette.actions instead of datasette.permissions - Updated fixtures.py to include permission_resources_sql hook and remove register_permissions - Added backwards compatibility support for old datasette-register-permissions config - Converted test actions (this_is_allowed, this_is_denied, etc.) to use permission_resources_sql 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
59ccf797c4
commit
fe2084df66
3 changed files with 89 additions and 34 deletions
|
|
@ -147,8 +147,8 @@ def check_permission_actions_are_documented():
|
|||
def before(hook_name, hook_impls, kwargs):
|
||||
if hook_name == "permission_allowed":
|
||||
datasette = kwargs["datasette"]
|
||||
assert kwargs["action"] in datasette.permissions, (
|
||||
"'{}' has not been registered with register_permissions()".format(
|
||||
assert kwargs["action"] in datasette.actions, (
|
||||
"'{}' has not been registered with register_actions()".format(
|
||||
kwargs["action"]
|
||||
)
|
||||
+ " (or maybe a test forgot to do await ds.invoke_startup())"
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ EXPECTED_PLUGINS = [
|
|||
"homepage_actions",
|
||||
"menu_links",
|
||||
"permission_allowed",
|
||||
"permission_resources_sql",
|
||||
"prepare_connection",
|
||||
"prepare_jinja2_environment",
|
||||
"query_actions",
|
||||
"register_actions",
|
||||
"register_facet_classes",
|
||||
"register_magic_parameters",
|
||||
"register_permissions",
|
||||
"register_routes",
|
||||
"render_cell",
|
||||
"row_actions",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import asyncio
|
||||
from datasette import hookimpl, Permission
|
||||
from datasette import hookimpl
|
||||
from datasette.facets import Facet
|
||||
from datasette import tracer
|
||||
from datasette.permissions import Action
|
||||
from datasette.resources import DatabaseResource
|
||||
from datasette.resources import DatabaseResource, InstanceResource
|
||||
from datasette.utils import path_with_added_args
|
||||
from datasette.utils.asgi import asgi_send_json, Response
|
||||
import base64
|
||||
|
|
@ -474,37 +474,20 @@ def skip_csrf(scope):
|
|||
return scope["path"] == "/skip-csrf"
|
||||
|
||||
|
||||
@hookimpl
|
||||
def register_permissions(datasette):
|
||||
extras = datasette.plugin_config("datasette-register-permissions") or {}
|
||||
permissions = [
|
||||
Permission(
|
||||
name="permission-from-plugin",
|
||||
abbr="np",
|
||||
description="New permission added by a plugin",
|
||||
takes_database=True,
|
||||
takes_resource=False,
|
||||
default=False,
|
||||
)
|
||||
]
|
||||
if extras:
|
||||
permissions.extend(
|
||||
Permission(
|
||||
name=p["name"],
|
||||
abbr=p["abbr"],
|
||||
description=p["description"],
|
||||
takes_database=p["takes_database"],
|
||||
takes_resource=p["takes_resource"],
|
||||
default=p["default"],
|
||||
)
|
||||
for p in extras["permissions"]
|
||||
)
|
||||
return permissions
|
||||
|
||||
|
||||
@hookimpl
|
||||
def register_actions(datasette):
|
||||
return [
|
||||
extras_old = datasette.plugin_config("datasette-register-permissions") or {}
|
||||
extras_new = datasette.plugin_config("datasette-register-actions") or {}
|
||||
|
||||
actions = [
|
||||
Action(
|
||||
name="action-from-plugin",
|
||||
abbr="ap",
|
||||
description="New action added by a plugin",
|
||||
takes_parent=True,
|
||||
takes_child=False,
|
||||
resource_class=DatabaseResource,
|
||||
),
|
||||
Action(
|
||||
name="view-collection",
|
||||
abbr="vc",
|
||||
|
|
@ -514,3 +497,75 @@ def register_actions(datasette):
|
|||
resource_class=DatabaseResource,
|
||||
)
|
||||
]
|
||||
|
||||
# Support old-style config for backwards compatibility
|
||||
if extras_old:
|
||||
for p in extras_old["permissions"]:
|
||||
# Map old takes_database/takes_resource to new takes_parent/takes_child
|
||||
actions.append(
|
||||
Action(
|
||||
name=p["name"],
|
||||
abbr=p["abbr"],
|
||||
description=p["description"],
|
||||
takes_parent=p.get("takes_database", False),
|
||||
takes_child=p.get("takes_resource", False),
|
||||
resource_class=DatabaseResource if p.get("takes_database") else InstanceResource,
|
||||
)
|
||||
)
|
||||
|
||||
# Support new-style config
|
||||
if extras_new:
|
||||
for a in extras_new["actions"]:
|
||||
# Map string resource_class to actual class
|
||||
resource_class_map = {
|
||||
"InstanceResource": InstanceResource,
|
||||
"DatabaseResource": DatabaseResource,
|
||||
}
|
||||
resource_class = resource_class_map.get(a.get("resource_class", "InstanceResource"), InstanceResource)
|
||||
|
||||
actions.append(
|
||||
Action(
|
||||
name=a["name"],
|
||||
abbr=a["abbr"],
|
||||
description=a["description"],
|
||||
takes_parent=a.get("takes_parent", False),
|
||||
takes_child=a.get("takes_child", False),
|
||||
resource_class=resource_class,
|
||||
)
|
||||
)
|
||||
|
||||
return actions
|
||||
|
||||
|
||||
@hookimpl
|
||||
def permission_resources_sql(datasette, actor, action):
|
||||
from datasette.permissions import PermissionSQL
|
||||
|
||||
# Handle test actions used in test_hook_permission_allowed
|
||||
if action == "this_is_allowed":
|
||||
sql = "SELECT NULL AS parent, NULL AS child, 1 AS allow, 'test plugin allows this_is_allowed' AS reason, 'my_plugin' AS source_plugin"
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
elif action == "this_is_denied":
|
||||
sql = "SELECT NULL AS parent, NULL AS child, 0 AS allow, 'test plugin denies this_is_denied' AS reason, 'my_plugin' AS source_plugin"
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
elif action == "this_is_allowed_async":
|
||||
sql = "SELECT NULL AS parent, NULL AS child, 1 AS allow, 'test plugin allows this_is_allowed_async' AS reason, 'my_plugin' AS source_plugin"
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
elif action == "this_is_denied_async":
|
||||
sql = "SELECT NULL AS parent, NULL AS child, 0 AS allow, 'test plugin denies this_is_denied_async' AS reason, 'my_plugin' AS source_plugin"
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
elif action == "view-database-download":
|
||||
# Return rule based on actor's can_download permission
|
||||
if actor and actor.get("can_download"):
|
||||
sql = "SELECT NULL AS parent, NULL AS child, 1 AS allow, 'actor has can_download' AS reason, 'my_plugin' AS source_plugin"
|
||||
else:
|
||||
return None # No opinion
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
elif action in ("insert-row", "create-table", "drop-table", "delete-row", "update-row"):
|
||||
# Special permissions for latest.datasette.io demos
|
||||
actor_id = actor.get("id") if actor else None
|
||||
if actor_id == "todomvc":
|
||||
sql = f"SELECT NULL AS parent, NULL AS child, 1 AS allow, 'todomvc actor allowed for {action}' AS reason, 'my_plugin' AS source_plugin"
|
||||
return PermissionSQL(source="my_plugin", sql=sql, params={})
|
||||
|
||||
return None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue