#!/usr/bin/env python3 # -*- coding: utf-8 -*- """pbl_common 模块 RBAC / 路径声明脚本(per-module,中央层 apps/pbls 聚合)。 ═══════════════════════════════════════════════════════════════════════════════ 结论:本模块 **零 Web 可访问路径**(NO_WEB_PATHS = True,显式声明) ═══════════════════════════════════════════════════════════════════════════════ pbl_common 是 PBL 公共内核(租户上下文 / DB 适配 / 错误码 / 审计 / CRUD 工厂), 只交付 Python 库函数(``pbl_common/*.py``),由宿主应用进程内 import 调用, **不提供任何 .dspy / .ui / .js / .css 文件**,因此 RBAC permission 表零登记项。 为什么写成显式声明而不是留空(M11b-2c-T3 QC 退回意见 #2 的连带治理): 中央聚合器 apps/pbls/scripts/load_path.py 现在把「有 scripts/load_path.py 但 一条路径都没聚合到」判为**聚合失败**(rc=1),除非模块显式声明 ``NO_WEB_PATHS``。 「无路径」是事实断言,必须可 grep、可复核,不允许用留空表达。 用法: python3 load_path.py # 打印声明(零路径,无需登记) python3 load_path.py --check # 自检:无通配符 + 与磁盘 wwwroot 一致性 """ import os import sys MODULE = 'pbl_common' # ── 显式零路径声明(中央聚合器据此判定「合法的空」而非「聚合失败」)────────── NO_WEB_PATHS = True DECLARATION = ( 'pbl_common 仅提供 Python 库函数(租户上下文/DB 适配/错误码/审计/CRUD 工厂),' '不新增任何 .dspy/.ui/.js/.css 可访问路径,故 RBAC 零登记项;' '禁通配符(%/*),后续若新增 Web 路径须按 any/logined/owner.* 分层逐条登记。' ) # 分层常量保持为空列表(显式,非缺失) PATHS_ANY = [] PATHS_LOGINED = [] PATHS_OWNER_SUPERUSER = [] PATHS_OWNER_OPERATOR = [] PATHS = [] FORBIDDEN_WILDCARDS = ('%', '*') def _wwwroot_files(): """列出本模块 wwwroot 下真实存在的 Web 文件(.dspy/.ui/.js/.css)。""" root = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'wwwroot') found = [] for base, _dirs, files in os.walk(root): for fn in files: if fn.endswith(('.dspy', '.ui', '.js', '.css')): found.append(os.path.relpath(os.path.join(base, fn), root)) return sorted(found) def check(): """离线自检:零路径声明与磁盘事实一致 + 无通配符。""" print('=' * 78) print('[%s] RBAC 路径声明自检 (--check) module=%s' % (MODULE, MODULE)) print('=' * 78) print(' NO_WEB_PATHS = %s' % NO_WEB_PATHS) print(' 声明: %s' % DECLARATION) rc = 0 tiers = (('any', PATHS_ANY), ('logined', PATHS_LOGINED), ('owner.superuser', PATHS_OWNER_SUPERUSER), ('owner.operator', PATHS_OWNER_OPERATOR)) bad = [t + ':' + p for t, ps in tiers for p in ps if any(w in p for w in FORBIDDEN_WILDCARDS)] if bad: print(' FAIL 含禁用通配符: %s' % bad) rc = 1 else: print(' OK 通配符检查通过(无任何路径,自然无通配符)') total = sum(len(ps) for _t, ps in tiers) if total: print(' FAIL NO_WEB_PATHS=True 但声明了 %d 条路径(自相矛盾)' % total) rc = 1 else: print(' OK 声明路径合计 0 条,与 NO_WEB_PATHS=True 一致') on_disk = _wwwroot_files() if on_disk: print(' FAIL 磁盘 wwwroot 存在 %d 个 Web 文件却未登记: %s' % (len(on_disk), on_disk)) rc = 1 else: print(' OK 磁盘 wwwroot 无 .dspy/.ui/.js/.css 文件,与零路径声明一致') print('[%s] --check 结论: %s' % (MODULE, 'PASS' if rc == 0 else 'FAIL')) return rc def main(): if '--check' in sys.argv[1:]: return check() print('[%s] %s' % (MODULE, DECLARATION)) print('[%s] 无路径需要登记(NO_WEB_PATHS=True);可执行 `--check` 离线复核。' % MODULE) return 0 if __name__ == '__main__': sys.exit(main())