feat: 新增脚手架/开发模式/权限白名单/system-monitor插件
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled

- nebula create mod/key/list-templates 模组脚手架
- nebula dev 开发模式热重载
- manifest permissions.imports 权限白名单机制
- system-monitor 系统监控仪表盘插件
- 默认端口统一为 10086
- 修复 _init_nbpf 误读 Ed25519 私钥为 RSA 的 bug
- 更新 README.md 文档
This commit is contained in:
starlight-apk
2026-05-16 20:20:43 +08:00
parent bce27db4ac
commit 5fbc5cc335
14 changed files with 1225 additions and 312 deletions

View File

@@ -46,7 +46,7 @@ class NIRCompiler:
# ── 编译 ──
def compile_source(self, source: str, filename: str = "<nbpf>") -> bytes:
def compile_source(self, source: str, filename: str = "<nbpf>", allowed_imports: list[str] = None) -> bytes:
"""将 Python 源码编译为序列化的 code object
Args:
@@ -61,7 +61,7 @@ class NIRCompiler:
"""
try:
# 静态安全检查
self._static_check(source, filename)
self._static_check(source, filename, allowed_imports or [])
# 编译为 code object
code = compile(source, filename, 'exec')
@@ -79,11 +79,12 @@ class NIRCompiler:
except Exception as e:
raise NIRCompileError(f"编译失败: {type(e).__name__}: {e}") from e
def compile_plugin(self, plugin_dir: Path) -> dict[str, bytes]:
def compile_plugin(self, plugin_dir: Path, allowed_imports: list[str] = None) -> dict[str, bytes]:
"""编译整个插件目录为 NIR
Args:
plugin_dir: 插件目录路径
allowed_imports: 允许导入的系统模块白名单(来自 manifest permissions.imports
Returns:
{module_name: nir_bytes} 字典
@@ -105,7 +106,7 @@ class NIRCompiler:
module_name = rel_path.replace(".py", "").replace("/", ".")
if module_name.endswith(".__init__"):
module_name = module_name[:-9] # 去掉 .__init__
nir_data[module_name] = self.compile_source(source, str(plugin_dir / rel_path))
nir_data[module_name] = self.compile_source(source, str(plugin_dir / rel_path), allowed_imports)
return nir_data
@@ -163,7 +164,7 @@ class NIRCompiler:
# ── 静态安全检查 ──
def _static_check(self, source: str, filename: str):
def _static_check(self, source: str, filename: str, allowed_imports: list[str] = None):
"""静态源码安全检查"""
try:
tree = ast.parse(source, filename=filename)
@@ -174,12 +175,12 @@ class NIRCompiler:
# 检查 import 语句
if isinstance(node, ast.Import):
for alias in node.names:
self._check_module(alias.name, node.lineno)
self._check_module(alias.name, node.lineno, allowed_imports)
# 检查 from ... import 语句
elif isinstance(node, ast.ImportFrom):
if node.module:
self._check_module(node.module, node.lineno)
self._check_module(node.module, node.lineno, allowed_imports)
# 检查 __import__ 调用
elif isinstance(node, ast.Call):
@@ -196,12 +197,16 @@ class NIRCompiler:
f"{filename}:{node.lineno} - 禁止使用 {node.func.id}()"
)
def _check_module(self, module_name: str, lineno: int):
"""检查模块是否被禁止"""
def _check_module(self, module_name: str, lineno: int, allowed_imports: list[str] = None):
"""检查模块是否被禁止(支持白名单豁免)"""
base = module_name.split(".")[0]
if base in self.FORBIDDEN_MODULES:
# 检查是否在白名单中
if allowed_imports and base in allowed_imports:
return # 白名单放行
raise NIRCompileError(
f"{lineno} 行 - 禁止导入系统模块: '{module_name}'"
f"(如需使用请在 manifest.json 的 permissions.imports 中声明)"
)
def _reject_c_extensions(self, plugin_dir: Path):