Migrate views from ds.permissions to ds.actions, refs #2528

Updates all permission debugging views to use the new ds.actions dict
instead of the old ds.permissions dict. Changes include:

- Replace all ds.permissions references with ds.actions
- Update field references: takes_database/takes_resource → takes_parent/takes_child
- Remove default field from permission display
- Rename sorted_permissions to sorted_actions in templates
- Remove source_plugin from SQL queries and responses
- Update test expectations to not check for source_plugin field

This aligns the views with the new Action dataclass structure.
This commit is contained in:
Simon Willison 2025-10-25 08:53:03 -07:00
commit 5c6b76f2f0
5 changed files with 15 additions and 30 deletions

View file

@ -110,7 +110,7 @@
<label for="action">Action (permission name):</label>
<select id="action" name="action" required>
<option value="">Select an action...</option>
{% for permission_name in sorted_permissions %}
{% for permission_name in sorted_actions %}
<option value="{{ permission_name }}">{{ permission_name }}</option>
{% endfor %}
</select>

View file

@ -26,7 +26,7 @@
<label for="action">Action (permission name):</label>
<select id="action" name="action" required>
<option value="">Select an action...</option>
{% for permission_name in sorted_permissions %}
{% for permission_name in sorted_actions %}
<option value="{{ permission_name }}">{{ permission_name }}</option>
{% endfor %}
</select>

View file

@ -57,7 +57,7 @@ textarea {
<p><label for="permission" style="display:block">Permission</label>
<select name="permission" id="permission">
{% for permission in permissions %}
<option value="{{ permission.name }}">{{ permission.name }} (default {{ permission.default }})</option>
<option value="{{ permission.name }}">{{ permission.name }}</option>
{% endfor %}
</select>
<p><label for="resource_1">Database name</label><input type="text" id="resource_1" name="resource_1"></p>
@ -131,9 +131,6 @@ debugPost.addEventListener('submit', function(ev) {
{% else %}
<span class="check-result check-result-false"></span>
{% endif %}
{% if check.used_default %}
<span class="check-used-default">(used default)</span>
{% endif %}
</h2>
<p><strong>Actor:</strong> {{ check.actor|tojson }}</p>
{% if check.resource %}

View file

@ -144,11 +144,10 @@ class PermissionsDebugView(BaseView):
"name": p.name,
"abbr": p.abbr,
"description": p.description,
"takes_database": p.takes_database,
"takes_resource": p.takes_resource,
"default": p.default,
"takes_parent": p.takes_parent,
"takes_child": p.takes_child,
}
for p in self.ds.permissions.values()
for p in self.ds.actions.values()
],
},
)
@ -182,7 +181,6 @@ class PermissionsDebugView(BaseView):
"permission": permission,
"resource": resource_for_response,
"result": result,
"default": self.ds.permissions[permission].default,
}
)
@ -232,7 +230,7 @@ class AllowedResourcesView(BaseView):
action = request.args.get("action")
if not action:
return Response.json({"error": "action parameter is required"}, status=400)
if action not in self.ds.permissions:
if action not in self.ds.actions:
return Response.json({"error": f"Unknown action: {action}"}, status=404)
if action not in self.CANDIDATE_SQL:
return Response.json(
@ -313,8 +311,6 @@ class AllowedResourcesView(BaseView):
# Add debug fields if available
if has_debug_permission and hasattr(resource, "_reason"):
row["reason"] = resource._reason
if has_debug_permission and hasattr(resource, "_source_plugin"):
row["source_plugin"] = resource._source_plugin
allowed_rows.append(row)
@ -380,7 +376,7 @@ class PermissionRulesView(BaseView):
["debug_rules.html"],
request,
{
"sorted_permissions": sorted(self.ds.permissions.keys()),
"sorted_actions": sorted(self.ds.actions.keys()),
},
)
@ -388,7 +384,7 @@ class PermissionRulesView(BaseView):
action = request.args.get("action")
if not action:
return Response.json({"error": "action parameter is required"}, status=400)
if action not in self.ds.permissions:
if action not in self.ds.actions:
return Response.json({"error": f"Unknown action: {action}"}, status=404)
actor = request.actor if isinstance(request.actor, dict) else None
@ -431,7 +427,7 @@ class PermissionRulesView(BaseView):
WITH rules AS (
{union_sql}
)
SELECT parent, child, allow, reason, source_plugin
SELECT parent, child, allow, reason
FROM rules
ORDER BY allow DESC, (parent IS NOT NULL), parent, child
LIMIT :limit OFFSET :offset
@ -450,7 +446,6 @@ class PermissionRulesView(BaseView):
"resource": _resource_path(parent, child),
"allow": row["allow"],
"reason": row["reason"],
"source_plugin": row["source_plugin"],
}
)
@ -505,7 +500,7 @@ class PermissionCheckView(BaseView):
["debug_check.html"],
request,
{
"sorted_permissions": sorted(self.ds.permissions.keys()),
"sorted_actions": sorted(self.ds.actions.keys()),
},
)
@ -513,7 +508,7 @@ class PermissionCheckView(BaseView):
action = request.args.get("action")
if not action:
return Response.json({"error": "action parameter is required"}, status=400)
if action not in self.ds.permissions:
if action not in self.ds.actions:
return Response.json({"error": f"Unknown action: {action}"}, status=404)
parent = request.args.get("parent")
@ -564,12 +559,10 @@ class PermissionCheckView(BaseView):
response["actor_id"] = request.actor["id"]
if info is not None:
response["used_default"] = info.get("used_default")
response["depth"] = info.get("depth")
# Only include sensitive fields if user has permissions-debug
if has_debug_permission:
response["reason"] = info.get("reason")
response["source_plugin"] = info.get("source_plugin")
return Response.json(response)
@ -687,16 +680,12 @@ class CreateTokenView(BaseView):
)
return {
"actor": request.actor,
"all_permissions": self.ds.permissions.keys(),
"all_permissions": self.ds.actions.keys(),
"database_permissions": [
key
for key, value in self.ds.permissions.items()
if value.takes_database
key for key, value in self.ds.actions.items() if value.takes_database
],
"resource_permissions": [
key
for key, value in self.ds.permissions.items()
if value.takes_resource
key for key, value in self.ds.actions.items() if value.takes_resource
],
"database_with_tables": database_with_tables,
}

View file

@ -247,7 +247,6 @@ async def test_rules_json_response_structure(ds_with_permissions):
assert "resource" in item
assert "allow" in item
assert "reason" in item
assert "source_plugin" in item
@pytest.mark.asyncio