agnes-the-ai-analyst/tests/test_permissions_api.py
ZdenekSrotyr 9c2bd3ff25 test: add 132 API gap tests across 8 endpoint modules
Covers upload (sessions, artifacts, local-md), scripts (deploy/run/delete),
settings (get/dataset), memory (CRUD, voting, admin governance),
access-requests (create, approve, deny), permissions (grant/revoke/list),
metadata (get/save/push), and admin configure+registry endpoints.

Each file tests happy path, auth required (401), role enforcement (403),
and input validation (422) independently using the seeded_app fixture.
2026-04-12 11:13:24 +02:00

168 lines
5.7 KiB
Python

"""Tests for admin permissions API — grant, revoke, list."""
import pytest
def _auth(token):
return {"Authorization": f"Bearer {token}"}
class TestGrantPermission:
def test_grant_permission_as_admin(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
resp = c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "sales", "access": "read"},
headers=_auth(token),
)
assert resp.status_code == 201
data = resp.json()
assert data["user_id"] == "analyst1"
assert data["dataset"] == "sales"
assert data["access"] == "read"
def test_grant_analyst_gets_403(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["analyst_token"]
resp = c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "sales", "access": "read"},
headers=_auth(token),
)
assert resp.status_code == 403
def test_grant_requires_auth(self, seeded_app):
c = seeded_app["client"]
resp = c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "sales", "access": "read"},
)
assert resp.status_code == 401
def test_grant_missing_fields_returns_422(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
resp = c.post(
"/api/admin/permissions",
json={"user_id": "analyst1"}, # missing 'dataset'
headers=_auth(token),
)
assert resp.status_code == 422
class TestRevokePermission:
def _delete_with_json(self, c, url, body, headers=None):
"""TestClient.delete() does not support a body — use request() method."""
import json
h = {"Content-Type": "application/json"}
if headers:
h.update(headers)
return c.request("DELETE", url, content=json.dumps(body), headers=h)
def test_revoke_permission_as_admin(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
# Grant first
c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "to_revoke", "access": "read"},
headers=_auth(token),
)
# Then revoke
resp = self._delete_with_json(
c, "/api/admin/permissions",
{"user_id": "analyst1", "dataset": "to_revoke"},
headers=_auth(token),
)
assert resp.status_code == 200
assert resp.json()["revoked"] is True
def test_revoke_analyst_gets_403(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["analyst_token"]
resp = self._delete_with_json(
c, "/api/admin/permissions",
{"user_id": "analyst1", "dataset": "sales"},
headers=_auth(token),
)
assert resp.status_code == 403
def test_revoke_requires_auth(self, seeded_app):
c = seeded_app["client"]
resp = self._delete_with_json(
c, "/api/admin/permissions",
{"user_id": "analyst1", "dataset": "sales"},
)
assert resp.status_code == 401
class TestListUserPermissions:
def test_list_user_permissions_as_admin(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
# Grant a permission
c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "finance", "access": "read"},
headers=_auth(token),
)
resp = c.get("/api/admin/permissions/analyst1", headers=_auth(token))
assert resp.status_code == 200
data = resp.json()
assert data["user_id"] == "analyst1"
assert "permissions" in data
datasets = [p["dataset"] for p in data["permissions"]]
assert "finance" in datasets
def test_list_user_permissions_analyst_gets_403(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["analyst_token"]
resp = c.get("/api/admin/permissions/analyst1", headers=_auth(token))
assert resp.status_code == 403
def test_list_user_permissions_requires_auth(self, seeded_app):
c = seeded_app["client"]
resp = c.get("/api/admin/permissions/analyst1")
assert resp.status_code == 401
class TestListAllPermissions:
def test_list_all_permissions_empty(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
resp = c.get("/api/admin/permissions", headers=_auth(token))
assert resp.status_code == 200
data = resp.json()
assert "permissions" in data
assert isinstance(data["permissions"], list)
def test_list_all_permissions_after_grant(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["admin_token"]
c.post(
"/api/admin/permissions",
json={"user_id": "analyst1", "dataset": "all_perms_test", "access": "read"},
headers=_auth(token),
)
resp = c.get("/api/admin/permissions", headers=_auth(token))
assert resp.status_code == 200
datasets = [p["dataset"] for p in resp.json()["permissions"]]
assert "all_perms_test" in datasets
def test_list_all_permissions_analyst_gets_403(self, seeded_app):
c = seeded_app["client"]
token = seeded_app["analyst_token"]
resp = c.get("/api/admin/permissions", headers=_auth(token))
assert resp.status_code == 403
def test_list_all_permissions_requires_auth(self, seeded_app):
c = seeded_app["client"]
resp = c.get("/api/admin/permissions")
assert resp.status_code == 401