修复(权限管理):统一 PM 系统导航与权限校验
This commit is contained in:
@@ -69,7 +69,19 @@ async def test_system_permission_monitoring_definitions_are_admin_only():
|
||||
assert all("PM" not in item["roles"] for item in monitoring_items)
|
||||
|
||||
|
||||
async def _seed_permission_log(db_session, study_id: uuid.UUID, user_id: uuid.UUID, *, allowed: bool, elapsed_ms: float) -> None:
|
||||
async def _seed_permission_log(
|
||||
db_session,
|
||||
study_id: uuid.UUID,
|
||||
user_id: uuid.UUID,
|
||||
*,
|
||||
allowed: bool,
|
||||
elapsed_ms: float,
|
||||
endpoint_key: str = "admin.permissions.read",
|
||||
role: str = "PM",
|
||||
client_type: str | None = None,
|
||||
client_version: str | None = None,
|
||||
client_platform: str | None = None,
|
||||
) -> None:
|
||||
study_exists = (
|
||||
await db_session.execute(text("SELECT id FROM studies WHERE id = :id"), {"id": str(study_id)})
|
||||
).scalar_one_or_none()
|
||||
@@ -119,21 +131,24 @@ async def _seed_permission_log(db_session, study_id: uuid.UUID, user_id: uuid.UU
|
||||
"""
|
||||
INSERT INTO permission_access_logs
|
||||
(id, study_id, user_id, endpoint_key, role, allowed, elapsed_ms, ip_address,
|
||||
request_snapshot, created_at)
|
||||
client_type, client_version, client_platform, request_snapshot, created_at)
|
||||
VALUES
|
||||
(:id, :study_id, :user_id, :endpoint_key, :role, :allowed, :elapsed_ms, :ip_address,
|
||||
:request_snapshot, CURRENT_TIMESTAMP)
|
||||
:client_type, :client_version, :client_platform, :request_snapshot, CURRENT_TIMESTAMP)
|
||||
"""
|
||||
),
|
||||
{
|
||||
"id": str(uuid.uuid4()),
|
||||
"study_id": str(study_id),
|
||||
"user_id": str(user_id),
|
||||
"endpoint_key": "admin.permissions.read",
|
||||
"role": "PM",
|
||||
"endpoint_key": endpoint_key,
|
||||
"role": role,
|
||||
"allowed": allowed,
|
||||
"elapsed_ms": elapsed_ms,
|
||||
"ip_address": "127.0.0.1",
|
||||
"client_type": client_type,
|
||||
"client_version": client_version,
|
||||
"client_platform": client_platform,
|
||||
"request_snapshot": None,
|
||||
},
|
||||
)
|
||||
@@ -159,6 +174,53 @@ async def test_get_permission_metrics(db_session):
|
||||
assert data["check_metrics"]["denied_checks"] == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_trends_returns_dense_summary_comparison_and_attribution(db_session):
|
||||
baseline = await permission_monitoring.get_trends(db=db_session, _=AdminUserStub(), period="24h")
|
||||
study_id = uuid.uuid4()
|
||||
user_id = uuid.uuid4()
|
||||
await _seed_permission_log(
|
||||
db_session,
|
||||
study_id,
|
||||
user_id,
|
||||
allowed=True,
|
||||
elapsed_ms=5,
|
||||
endpoint_key="subjects.read",
|
||||
client_type="web",
|
||||
client_version="0.1.0",
|
||||
client_platform="macos",
|
||||
)
|
||||
await _seed_permission_log(
|
||||
db_session,
|
||||
study_id,
|
||||
user_id,
|
||||
allowed=False,
|
||||
elapsed_ms=80,
|
||||
endpoint_key="subjects.export",
|
||||
client_type="web",
|
||||
client_version="0.1.0",
|
||||
client_platform="macos",
|
||||
)
|
||||
|
||||
data = await permission_monitoring.get_trends(db=db_session, _=AdminUserStub(), period="24h")
|
||||
|
||||
assert data["period"] == "24h"
|
||||
assert data["range"]["bucket_seconds"] == 3600
|
||||
assert len(data["data_points"]) == 24
|
||||
assert data["data_points"][-1]["sample_state"] == "partial"
|
||||
assert data["summary"]["total_checks"] == baseline["summary"]["total_checks"] + 2
|
||||
assert data["summary"]["denied_checks"] == baseline["summary"]["denied_checks"] + 1
|
||||
assert data["summary"]["slow_check_count"] == baseline["summary"]["slow_check_count"] + 1
|
||||
assert data["summary"]["active_study_count"] == baseline["summary"]["active_study_count"] + 1
|
||||
assert data["summary"]["active_user_count"] == baseline["summary"]["active_user_count"] + 1
|
||||
assert data["summary"]["active_endpoint_count"] >= 2
|
||||
assert data["summary"]["max_elapsed_ms"] >= data["summary"]["p95_elapsed_ms"]
|
||||
assert data["previous_summary"]["total_checks"] == 0
|
||||
assert any(item["endpoint_key"] == "subjects.export" for item in data["attribution"]["top_denied"])
|
||||
assert data["attribution"]["top_slow"][0]["endpoint_key"] == "subjects.export"
|
||||
assert any(item["client_type"] == "web" for item in data["attribution"]["client_breakdown"])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cache_statistics(db_session):
|
||||
"""测试获取缓存统计"""
|
||||
@@ -1206,6 +1268,26 @@ async def test_access_logs_include_security_events_for_admin(db_session, monkeyp
|
||||
assert items_by_type["permission"]["request_snapshot"]["path"] == "/api/v1/projects/overview"
|
||||
assert items_by_type["security"]["request_snapshot"]["headers"]["authorization"] == "[redacted]"
|
||||
|
||||
permission_only = await permission_monitoring.get_access_logs(
|
||||
db=db_session,
|
||||
_=AdminUserStub(),
|
||||
study_id=None,
|
||||
user_id=None,
|
||||
endpoint_key=None,
|
||||
role=None,
|
||||
allowed=None,
|
||||
start_time=None,
|
||||
end_time=None,
|
||||
client_ip=None,
|
||||
client_type=None,
|
||||
event_type="permission",
|
||||
keyword=None,
|
||||
page=1,
|
||||
page_size=50,
|
||||
)
|
||||
assert permission_only["total"] == 1
|
||||
assert permission_only["items"][0]["event_type"] == "permission"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_access_logs_ip_ranking_aggregates_by_ip_total(db_session):
|
||||
|
||||
Reference in New Issue
Block a user