feat: require explicit dashboard read permission
Module Package Release / publish-packages (push) Successful in 11s

This commit is contained in:
2026-08-24 01:15:42 +02:00
parent 1a48724f16
commit ec240ed219
11 changed files with 165 additions and 12 deletions
+28 -1
View File
@@ -12,6 +12,7 @@ from govoplan_core.auth import ApiPrincipal, get_api_principal
from govoplan_core.core.access import PrincipalRef
from govoplan_core.db.session import get_session
from govoplan_dashboard.backend.db.models import DashboardLayout
from govoplan_dashboard.backend.manifest import READ_SCOPE
from govoplan_dashboard.backend.router import router
@@ -19,13 +20,14 @@ def principal(
*,
tenant_id: str = "tenant-1",
account_id: str = "account-1",
scopes: frozenset[str] = frozenset({READ_SCOPE}),
) -> ApiPrincipal:
return ApiPrincipal(
principal=PrincipalRef(
account_id=account_id,
membership_id=f"membership:{tenant_id}:{account_id}",
tenant_id=tenant_id,
scopes=frozenset(),
scopes=scopes,
group_ids=frozenset(),
),
account=object(),
@@ -67,6 +69,31 @@ class DashboardLayoutApiTests(unittest.TestCase):
self.client.close()
self.engine.dispose()
def test_layout_endpoints_require_dashboard_read_permission(self) -> None:
self.active_principal = principal(scopes=frozenset())
for method in ("get", "put", "delete"):
response = getattr(self.client, method)(
"/api/v1/dashboard/layout",
**(
{
"json": {
"expected_revision": 0,
"layout_version": 1,
"placements": [],
"known_widget_ids": [],
}
}
if method == "put"
else {}
),
)
self.assertEqual(403, response.status_code)
self.assertEqual(
f"Missing required scope: {READ_SCOPE}",
response.json()["detail"],
)
def test_layouts_are_isolated_by_account_and_view(self) -> None:
initial = self.client.get("/api/v1/dashboard/layout")
self.assertEqual(200, initial.status_code)