优化前后端权限一致性

This commit is contained in:
Cheng Zhou
2026-05-26 14:53:17 +08:00
parent 41bd423be0
commit c909fc9387
15 changed files with 184 additions and 26 deletions
+31 -4
View File
@@ -3,7 +3,7 @@
import pytest
import uuid
from pathlib import Path
import re
import ast
from sqlalchemy import delete
from sqlalchemy.ext.asyncio import AsyncSession
@@ -14,6 +14,7 @@ from app.core.permission_cache import PermissionCache, set_permission_cache
from app.core.permission_monitor import PermissionMonitor, set_permission_monitor
from app.models.api_endpoint_permission import ApiEndpointPermission
from app.models.study import Study
from app.models.user import UserRole
from app.schemas.member import StudyMemberCreate
@@ -43,20 +44,46 @@ def test_all_backend_permission_guards_are_configurable():
"""确保后端实际鉴权使用的 operation key 都能在权限管理中配置。"""
api_dir = Path(__file__).resolve().parents[1] / "app" / "api" / "v1"
used_keys: set[str] = set()
pattern = re.compile(r"require_api_permission\(\s*[\"']([^\"']+)[\"']")
for path in api_dir.rglob("*.py"):
used_keys.update(pattern.findall(path.read_text()))
source = path.read_text()
tree = ast.parse(source)
for node in ast.walk(tree):
if not isinstance(node, ast.Call):
continue
if isinstance(node.func, ast.Name) and node.func.id == "require_api_permission":
if node.args and isinstance(node.args[0], ast.Constant) and isinstance(node.args[0].value, str):
used_keys.add(node.args[0].value)
if isinstance(node.func, ast.Name) and node.func.id == "_ensure_project_access":
if len(node.args) >= 4 and isinstance(node.args[3], ast.Constant) and isinstance(node.args[3].value, str):
used_keys.add(node.args[3].value)
assert used_keys
assert used_keys <= set(API_ENDPOINT_PERMISSIONS)
def test_document_service_uses_specific_document_permission_keys():
"""文档模块应使用 create/update/delete 细粒度权限,而不是全部退化为 update。"""
service_path = Path(__file__).resolve().parents[1] / "app" / "services" / "document_service.py"
source = service_path.read_text()
assert '"create_document": "documents:create"' in source
assert '"create_version": "documents:update"' in source
assert '"delete_document": "documents:delete"' in source
assert 'else "documents:update"' not in source
def test_user_role_no_longer_contains_qa():
assert "QA" not in {role.value for role in UserRole}
@pytest.mark.asyncio
async def test_default_matrix_covers_every_role_and_permission(db_session: AsyncSession):
"""逐一验证 6 个预设角色在每个权限上的默认矩阵。"""
"""逐一验证预设项目权限角色在每个权限上的默认矩阵。"""
study_id = uuid.uuid4()
matrix = await get_api_endpoint_permissions(db_session, study_id)
assert "QA" not in PROJECT_PERMISSION_ROLES
assert all("QA" not in config["default_roles"] for config in API_ENDPOINT_PERMISSIONS.values())
assert set(matrix) == set(PROJECT_PERMISSION_ROLES)
for role in PROJECT_PERMISSION_ROLES:
assert set(matrix[role]) == set(API_ENDPOINT_PERMISSIONS)