Files
group_fqcd_jr/tools/verify_offsite_worker_identity.py

68 lines
2.4 KiB
Python

"""只读核验场外 Worker 技术账号和最小权限。"""
from __future__ import annotations
import asyncio
import sys
from pathlib import Path
from sqlalchemy import text
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from app.core.contracts import RequestContext # noqa: E402
from app.infrastructure.db import SessionFactory, engine # noqa: E402
from app.service.identity_service import IdentityService # noqa: E402
WORKER_USER_NO = "OFFSITE-WORKER"
WORKER_USERNAME = "offsite_worker"
REQUIRED_ROLE = "operator"
REQUIRED_PERMISSION = "offsite:write"
async def main() -> None:
async with SessionFactory() as session:
row = (
await session.execute(
text(
"""
SELECT id, user_no, username, user_type, employee_role, status
FROM sys_user
WHERE user_no=:user_no AND username=:username
"""
),
{"user_no": WORKER_USER_NO, "username": WORKER_USERNAME},
)
).mappings().first()
if row is None:
raise SystemExit("未找到场外 Worker 技术账号,请先执行 Alembic 迁移")
if row["user_type"] != "员工" or row["employee_role"] != REQUIRED_ROLE:
raise SystemExit("场外 Worker 技术账号身份属性不符合最小权限方案")
if row["status"] != "正常":
raise SystemExit("场外 Worker 技术账号未启用")
user_id = str(row["id"])
context = await IdentityService().resolve(
RequestContext(user_id=user_id, trace_id="verify-offsite-worker-identity")
)
roles = set(context.roles)
permissions = set(context.permissions)
if REQUIRED_ROLE not in roles:
raise SystemExit("场外 Worker 技术账号缺少 operator 角色")
if REQUIRED_PERMISSION not in permissions:
raise SystemExit("场外 Worker 技术账号缺少 offsite:write 权限")
extra_permissions = permissions - {REQUIRED_PERMISSION}
if extra_permissions:
raise SystemExit(f"场外 Worker 技术账号存在额外权限:{sorted(extra_permissions)}")
print("场外 Worker 技术账号核验通过")
print(f"OFFSITE_WORKER_USER_ID={user_id}")
print(f"roles={sorted(roles)}")
print(f"permissions={sorted(permissions)}")
await engine.dispose()
if __name__ == "__main__":
asyncio.run(main())