pbl_common/scripts/load_path.py

101 lines
4.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_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())