pbl_compiler/scripts/load_path.py
2026-09-19 10:10:08 +08:00

108 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""pbl_compiler RBAC 路径注册(硬门禁 6.6 / QC #1、#11
约定:
- 路径 = 模块自动路由 `/pbl_compiler/api/<契约>.dspy`,不带端口、不带 /wss 前缀;
- 角色 `logined` = 登录即可访问;
- 由 apps/pbls/build.sh 第 8 步调用 `register()`rbac CLI 不在位时打印清单(不静默跳过);
- **禁止通配符**(规范硬规定),每条 .dspy 显式登记。
登记面与事实源(四处必须一一对应,数量一致):
① 实现pbl_compiler/api.py15 个 M3a 契约)+ pbl_compiler/rules_export_api.py5 个 M3b 契约)
② 导出pbl_compiler/__init__.py import + __all__
③ 注册pbl_compiler/init.py CONTRACTS共 20 条)
④ 端点wwwroot/api/<契约名>.dspy共 20 个)→ 本文件 PATHS共 20 条)
QC #1 整改(本轮,第四章 RBAC 硬门禁):
上一轮新增 5 个 M3b Web 契约pbl_compiler_export_rules / pbl_compiler_rules_preview /
pbl_compiler_rules_diff / pbl_game_definition_rules_get / pbl_script_rule_list
wwwroot/api/ 已有 20 个 .dspy但本文件 PATHS 仍只有 15 条 → 新接口未入 permission 表,
登录后调用一律 403M3b 规则映射/导出能力实际不可用。现逐条显式补齐至 20 条。
关于 CRUD 生成目录(/pbl_compiler/pbl_script_rule 及 index.ui/get_/add_/update_/delete_ 五条):
本模块 **未** 引入任何 pbl_script_rule 的 CRUD 定义json/ 下仅
compiler_pbl_capability_registry / compiler_pbl_compiler_version /
compiler_pbl_game_definition 三个只读列表定义,且 wwwroot/ 下无 CRUD 生成子目录,
仅 index.ui + api/。pbl_script_rule 的只读列表能力由手写契约
`api/pbl_script_rule_list.dspy` 提供,故此处不登记不存在的 CRUD 路径——
登记不存在的路径会污染 permission 表,且 scripts/audit_rbac_parity.py 会判为 FAIL。
自证(交付前实跑,见 scripts/audit_rbac_parity.py
grep -c "api/" scripts/load_path.py → 20
ls wwwroot/api/*.dspy | wc -l → 20
两者集合差为空(无漏登记、无幽灵登记)
"""
import os
import subprocess
import sys
MODULE = 'pbl_compiler'
# (path, role) —— 与 init.py CONTRACTS 一一对应20 个端点,无通配符)
PATHS = [
# —— M3a编译主流程 / 预览 / 对比3——
('/pbl_compiler/api/pbl_compiler_compile.dspy', 'logined'),
('/pbl_compiler/api/pbl_compiler_preview.dspy', 'logined'),
('/pbl_compiler/api/pbl_compiler_compare.dspy', 'logined'),
# —— M3a编译任务2——
('/pbl_compiler/api/pbl_compiler_task_get.dspy', 'logined'),
('/pbl_compiler/api/pbl_compiler_task_list.dspy', 'logined'),
# —— M3aGame Definition 产物2——
('/pbl_compiler/api/pbl_game_definition_get.dspy', 'logined'),
('/pbl_compiler/api/pbl_game_definition_get_by_blueprint.dspy', 'logined'),
# —— M3a确定性验证US-11 / F-CP-03 验收入口1——
('/pbl_compiler/api/pbl_compiler_verify_determinism.dspy', 'logined'),
# —— M3a编译器版本管理5——
('/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'),
# —— M3a能力注册表2——
('/pbl_compiler/api/pbl_capability_list.dspy', 'logined'),
('/pbl_compiler/api/pbl_capability_register.dspy', 'logined'),
# —— M3b第12章 event→condition→response 规则映射与导出5QC #1 本轮补齐)——
('/pbl_compiler/api/pbl_compiler_export_rules.dspy', 'logined'),
('/pbl_compiler/api/pbl_compiler_rules_preview.dspy', 'logined'),
('/pbl_compiler/api/pbl_compiler_rules_diff.dspy', 'logined'),
('/pbl_compiler/api/pbl_game_definition_rules_get.dspy', 'logined'),
('/pbl_compiler/api/pbl_script_rule_list.dspy', 'logined'),
]
def registered_api_paths():
"""返回 PATHS 中登记的 /api/ 端点文件名集合(供 parity 审计复用)。"""
return {p.rsplit('/', 1)[-1] for p, _role in PATHS if '/api/' in p}
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))
# 4 个占位符 ↔ 4 个实参QC #3 修复保持)
print('[%s] rbac paths: total=%d ok=%d pending=%d'
% (MODULE, len(PATHS), done, len(missing)))
for path, role in missing:
print(' PENDING %-12s %s' % (role, path))
return len(missing) == 0
if __name__ == '__main__':
sys.exit(0 if register() else 1)