diff --git a/datasette/templates/permissions_debug.html b/datasette/templates/permissions_debug.html
index 5b2b67e1..558d16f2 100644
--- a/datasette/templates/permissions_debug.html
+++ b/datasette/templates/permissions_debug.html
@@ -112,6 +112,12 @@ debugPost.addEventListener('submit', function(ev) {
Recent permissions checks
+
+ {% if filter != "all" %}All{% else %}All{% endif %},
+ {% if filter != "exclude-yours" %}Exclude yours{% else %}Exclude yours{% endif %},
+ {% if filter != "only-yours" %}Only yours{% else %}Only yours{% endif %}
+
+
{% for check in permission_checks %}
diff --git a/datasette/views/special.py b/datasette/views/special.py
index 1db24d74..e6fbc9f3 100644
--- a/datasette/views/special.py
+++ b/datasette/views/special.py
@@ -121,12 +121,27 @@ class PermissionsDebugView(BaseView):
await self.ds.ensure_permissions(request.actor, ["view-instance"])
if not await self.ds.permission_allowed(request.actor, "permissions-debug"):
raise Forbidden("Permission denied")
+ filter_ = request.args.get("filter") or "all"
+ permission_checks = list(reversed(self.ds._permission_checks))
+ if filter_ == "exclude-yours":
+ permission_checks = [
+ check
+ for check in permission_checks
+ if (check["actor"] or {}).get("id") != request.actor["id"]
+ ]
+ elif filter_ == "only-yours":
+ permission_checks = [
+ check
+ for check in permission_checks
+ if (check["actor"] or {}).get("id") == request.actor["id"]
+ ]
return await self.render(
["permissions_debug.html"],
request,
# list() avoids error if check is performed during template render:
{
- "permission_checks": list(reversed(self.ds._permission_checks)),
+ "permission_checks": permission_checks,
+ "filter": filter_,
"permissions": [
{
"name": p.name,
diff --git a/tests/test_permissions.py b/tests/test_permissions.py
index 31ba104b..69a8a0b1 100644
--- a/tests/test_permissions.py
+++ b/tests/test_permissions.py
@@ -371,12 +371,15 @@ def test_permissions_checked(app_client, path, permissions):
@pytest.mark.asyncio
-async def test_permissions_debug(ds_client):
+@pytest.mark.parametrize("filter_", ("all", "exclude-yours", "only-yours"))
+async def test_permissions_debug(ds_client, filter_):
ds_client.ds._permission_checks.clear()
assert (await ds_client.get("/-/permissions")).status_code == 403
# With the cookie it should work
cookie = ds_client.actor_cookie({"id": "root"})
- response = await ds_client.get("/-/permissions", cookies={"ds_actor": cookie})
+ response = await ds_client.get(
+ f"/-/permissions?filter={filter_}", cookies={"ds_actor": cookie}
+ )
assert response.status_code == 200
# Should have a select box listing permissions
for fragment in (
@@ -398,17 +401,54 @@ async def test_permissions_debug(ds_client):
else bool(div.select(".check-result-true"))
),
"used_default": bool(div.select(".check-used-default")),
+ "actor": json.loads(
+ div.find(
+ "strong", string=lambda text: text and "Actor" in text
+ ).parent.text.split(": ", 1)[1]
+ ),
}
for div in check_divs
]
- assert checks == [
- {"action": "permissions-debug", "result": True, "used_default": False},
- {"action": "view-instance", "result": None, "used_default": True},
- {"action": "debug-menu", "result": False, "used_default": True},
- {"action": "view-instance", "result": True, "used_default": True},
- {"action": "permissions-debug", "result": False, "used_default": True},
- {"action": "view-instance", "result": None, "used_default": True},
+ expected_checks = [
+ {
+ "action": "permissions-debug",
+ "result": True,
+ "used_default": False,
+ "actor": {"id": "root"},
+ },
+ {
+ "action": "view-instance",
+ "result": None,
+ "used_default": True,
+ "actor": {"id": "root"},
+ },
+ {"action": "debug-menu", "result": False, "used_default": True, "actor": None},
+ {
+ "action": "view-instance",
+ "result": True,
+ "used_default": True,
+ "actor": None,
+ },
+ {
+ "action": "permissions-debug",
+ "result": False,
+ "used_default": True,
+ "actor": None,
+ },
+ {
+ "action": "view-instance",
+ "result": None,
+ "used_default": True,
+ "actor": None,
+ },
]
+ if filter_ == "only-yours":
+ expected_checks = [
+ check for check in expected_checks if check["actor"] is not None
+ ]
+ elif filter_ == "exclude-yours":
+ expected_checks = [check for check in expected_checks if check["actor"] is None]
+ assert checks == expected_checks
@pytest.mark.asyncio