"""scripts/load_path.py —— pbl_blueprint 模块 RBAC 路径注册。 规则(module-development-spec): - 禁止任何通配符(% / *),每条路径显式列出; - 角色分层:any(无需登录)/ logined(登录即可)/ owner.superuser(管理); - CRUD 子目录标准 5 条一组:目录 + index.ui + get_/add_/update_/delete_.dspy。 用法:cd <宿主应用根> && ./py3/bin/python /modules/pbl_blueprint/scripts/load_path.py """ import os import sys MODULE = 'pbl_blueprint' # 契约 API(登录可用) PATHS_LOGINED = [ '/pbl_blueprint', '/pbl_blueprint/index.ui', '/pbl_blueprint/api/pbl_blueprint_create.dspy', '/pbl_blueprint/api/pbl_blueprint_read.dspy', '/pbl_blueprint/api/pbl_blueprint_update.dspy', '/pbl_blueprint/api/pbl_blueprint_delete.dspy', '/pbl_blueprint/api/pbl_blueprint_list.dspy', '/pbl_blueprint/api/pbl_blueprint_tree.dspy', '/pbl_blueprint/api/pbl_blueprint_fork.dspy', '/pbl_blueprint/api/pbl_blueprint_subobject_save.dspy', '/pbl_blueprint/api/pbl_blueprint_subobject_list.dspy', '/pbl_blueprint/api/pbl_blueprint_subobject_delete.dspy', '/pbl_blueprint/api/pbl_blueprint_version_create.dspy', '/pbl_blueprint/api/pbl_blueprint_version_diff.dspy', '/pbl_blueprint/api/pbl_template_list.dspy', '/pbl_blueprint/api/pbl_template_instantiate.dspy', '/pbl_blueprint/api/pbl_template_save.dspy', '/pbl_blueprint/api/pbl_template_delete.dspy', ] # 静态资源(无需登录) PATHS_ANY = [ '/pbl_blueprint/menu.ui', ] # 管理级操作(删除/模板维护) PATHS_SUPERUSER = [ '/pbl_blueprint/api/pbl_template_delete.dspy', ] # CRUD 生成目录(每个 alias 5 条) CRUD_ALIASES = [ 'pbl_blueprint', 'pbl_blueprint_learning_goal', 'pbl_blueprint_role', 'pbl_blueprint_mission', 'pbl_blueprint_task', 'pbl_blueprint_artifact_spec', 'pbl_blueprint_evidence_spec', 'pbl_blueprint_reflection_spec', 'pbl_blueprint_version', 'pbl_template', ] def _crud_paths(): out = [] for alias in CRUD_ALIASES: base = '/%s/%s' % (MODULE, alias) out.append((base, 'logined')) out.append((base + '/index.ui', 'logined')) out.append((base + '/get_%s.dspy' % alias, 'logined')) out.append((base + '/add_%s.dspy' % alias, 'logined')) out.append((base + '/update_%s.dspy' % alias, 'logined')) out.append((base + '/delete_%s.dspy' % alias, 'logined')) return out def all_paths(): """返回 [(path, role), ...] 全量显式路径清单。""" items = [(p, 'logined') for p in PATHS_LOGINED] items += [(p, 'any') for p in PATHS_ANY] items += [(p, 'owner.superuser') for p in PATHS_SUPERUSER] items += _crud_paths() # 去重保序 seen = set() out = [] for p, r in items: if p in seen: continue seen.add(p) out.append((p, r)) return out def _find_app_root(): """向上查找宿主应用根(含 load_path.py / set_role_perm.py 的目录)。""" here = os.path.dirname(os.path.abspath(__file__)) cur = here for _ in range(8): for cand in (os.path.join(cur, 'set_role_perm.py'), os.path.join(cur, 'load_path.py')): if os.path.exists(cand): return cur nxt = os.path.dirname(cur) if nxt == cur: break cur = nxt for env_key in ('SAGE_ROOT', 'PBL_APP_ROOT'): v = os.environ.get(env_key) if v and os.path.isdir(v): return v return None def main(): paths = all_paths() root = _find_app_root() if root is None: print('[pbl_blueprint] 未找到宿主应用根(set_role_perm.py),' '仅打印待注册路径 %d 条:' % len(paths)) for p, r in paths: print('%s %s' % (p, r)) return 0 sys.path.insert(0, root) try: import set_role_perm except Exception as e: print('[pbl_blueprint] 导入 set_role_perm 失败: %s' % e) for p, r in paths: print('%s %s' % (p, r)) return 1 fn = getattr(set_role_perm, 'set_role_perm', None) or \ getattr(set_role_perm, 'main', None) ok = 0 for p, r in paths: try: if fn is not None: fn(p, r) ok += 1 except Exception as e: print('[pbl_blueprint] 注册失败 %s %s: %s' % (p, r, e)) print('[pbl_blueprint] RBAC 路径注册完成 %d/%d' % (ok, len(paths))) return 0 if __name__ == '__main__': sys.exit(main())