#!/usr/bin/env python3 # -*- coding: utf-8 -*- """pbl_compiler RBAC 路径注册(硬门禁 6.6 / QC #11)。 约定: - 路径 = 模块自动路由 `/pbl_compiler/api/<契约>.dspy`,不带端口、不带 /wss 前缀; - 角色 `logined` = 登录即可访问;写接口(compile/register/save)按角色分级; - 由 apps/pbls/build.sh 第 8 步调用 `register()`;rbac CLI 不在位时打印清单(不静默跳过)。 QC #2 整改(本轮):PATHS 补齐 8 个此前漏注册的契约端点(task_get/task_list/ game_definition_get/game_definition_get_by_blueprint/verify_determinism/ version_register/version_get/version_diff),与 init.py CONTRACTS、__init__.py __all__ 三处同步,共 15 个 .dspy 端点。 QC #3 整改(本轮):register() 格式串占位符与实参数量错位导致 `TypeError: not enough arguments for format string`—— 第 39 行 '[%s] rbac paths: total=%d ok=%d pending=%d' 有 4 个占位符只传 3 个参数; 第 44 行 '%%-12s %s' 转义错位。 现改为 % (MODULE, len(PATHS), done, len(missing)) 与 % (role, path), python3 -c 实测 register() 可跑通(见 scripts/test_m3a_selfcheck.py 第 4 组断言)。 """ import os import subprocess import sys MODULE = 'pbl_compiler' # (path, role) —— 与 init.py CONTRACTS 一一对应(15 个端点,无通配符) PATHS = [ # 编译主流程 / 预览 / 对比 ('/pbl_compiler/api/pbl_compiler_compile.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_preview.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_compare.dspy', 'logined'), # 编译任务(QC #2 补) ('/pbl_compiler/api/pbl_compiler_task_get.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_task_list.dspy', 'logined'), # Game Definition 产物(QC #2 补) ('/pbl_compiler/api/pbl_game_definition_get.dspy', 'logined'), ('/pbl_compiler/api/pbl_game_definition_get_by_blueprint.dspy', 'logined'), # 确定性验证(QC #2 补:US-11/F-CP-03 验收入口) ('/pbl_compiler/api/pbl_compiler_verify_determinism.dspy', 'logined'), # 编译器版本管理(QC #2 补:register/get/diff) ('/pbl_compiler/api/pbl_compiler_version_register.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_version_get.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_version_list.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_version_diff.dspy', 'logined'), ('/pbl_compiler/api/pbl_compiler_version_save.dspy', 'logined'), # 能力注册表 ('/pbl_compiler/api/pbl_capability_list.dspy', 'logined'), ('/pbl_compiler/api/pbl_capability_register.dspy', 'logined'), ] def register(): """逐条注册 RBAC 路径。rbac CLI 不在位时收集为 pending 并打印(不静默跳过)。 :return: True 全部注册成功;False 存在 pending(调用方据此决定退出码)。 """ tool = os.environ.get('RBAC_SET_PERM', 'set_role_perm.py') py = sys.executable if os.environ.get('PY') else 'python3' done, missing = 0, [] for path, role in PATHS: try: rc = subprocess.call([py, tool, role, path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except Exception: # noqa: BLE001 - CLI 缺失不崩,记 pending rc = 1 if rc == 0: done += 1 else: missing.append((path, role)) # QC #3 修复:4 个占位符 ↔ 4 个实参 print('[%s] rbac paths: total=%d ok=%d pending=%d' % (MODULE, len(PATHS), done, len(missing))) for path, role in missing: # QC #3 修复:去掉多余的 % 转义,2 个占位符 ↔ 2 个实参 print(' PENDING %-12s %s' % (role, path)) return len(missing) == 0 if __name__ == '__main__': sys.exit(0 if register() else 1)