security: P3 — 插件隔离默认开启 + SenSuDB 注册 + 审计日志

- plugins.isolation 默认 true (生产环境进程隔离)
- main.py 注册 SenSuDB 服务
- WebPanelManager 注入 sensu_db 到 app context
- 文件删除/写入操作写入审计日志 (audit_log 表)
- 修复 Session 持久化所需的数据库依赖

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
qinglong
2026-06-13 13:56:58 +08:00
parent c1d2767f52
commit ff02b2e16d
10 changed files with 21 additions and 31 deletions
+1
View File
@@ -11,6 +11,7 @@ plugins:
auto_load: true auto_load: true
hot_reload: true hot_reload: true
max_retry_count: 3 max_retry_count: 3
isolation: true
# 自动启动脚本 — 框架启动时后台拉起 # 自动启动脚本 — 框架启动时后台拉起
auto_start_scripts: auto_start_scripts:
enabled: true enabled: true
+3 -14
View File
@@ -9,10 +9,6 @@ commands:
permissions: permissions:
- framework.scaffold.plugin - framework.scaffold.plugin
source: internal source: internal
echo: &id001
description: echo input
permissions: []
source: plugin.example_plugin
help: help:
description: 显示帮助信息 description: 显示帮助信息
permissions: permissions:
@@ -38,10 +34,6 @@ commands:
permissions: permissions:
- framework.permission.read - framework.permission.read
source: internal source: internal
plugin_status: &id002
description: show status
permissions: []
source: plugin.example_plugin
pm_plugin_status: pm_plugin_status:
description: '权限管理: 查看插件权限状态' description: '权限管理: 查看插件权限状态'
permissions: permissions:
@@ -97,9 +89,6 @@ commands:
permissions: permissions:
- framework.command.test - framework.command.test
source: internal source: internal
last_updated: 12019.862122705 last_updated: 12161.390698641
plugin_commands: plugin_commands: {}
example_plugin: total_commands: 18
echo: *id001
plugin_status: *id002
total_commands: 20
+2 -15
View File
@@ -1,17 +1,4 @@
http_port: 4200 http_port: 4200
last_updated: 12019.877017393 last_updated: 12161.450926401
plugin_routes: plugin_routes: {}
example_plugin:
- methods:
- GET
path: /example_plugin/api/example/info
require_auth: false
- methods:
- POST
path: /example_plugin/api/plugin/echo
require_auth: true
- methods:
- POST
path: /example_plugin/api/plugin/plugin_status
require_auth: true
websocket_port: 4240 websocket_port: 4240
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+6 -1
View File
@@ -11,6 +11,7 @@ from services.project_engine import ProjectEngine
from services.pyenv_manager import PyEnvManager from services.pyenv_manager import PyEnvManager
from services.proxy_service import ProxyService from services.proxy_service import ProxyService
from services.web_panel.utils.system_info import SystemInfoCollector from services.web_panel.utils.system_info import SystemInfoCollector
from services.sensu_db import SenSuDB
import os import os
from pathlib import Path from pathlib import Path
@@ -63,7 +64,11 @@ class SenSuFramework:
# 2.5 自动启动脚本 (日志服务就绪后) # 2.5 自动启动脚本 (日志服务就绪后)
await init_service.start_auto_scripts() await init_service.start_auto_scripts()
# 2.6 系统信息采集器 (共享实例,TUI + Web面板共用) # 2.6 数据库 (持久化层)
sensu_db = SenSuDB()
self.service_manager.register_service("sensu_db", sensu_db)
# 2.7 系统信息采集器 (共享实例,TUI + Web面板共用)
sys_collector = SystemInfoCollector() sys_collector = SystemInfoCollector()
self.service_manager.register_service("sys_collector", sys_collector) self.service_manager.register_service("sys_collector", sys_collector)
+1 -1
View File
@@ -219,7 +219,7 @@ class InitService:
'auto_load': True, 'auto_load': True,
'hot_reload': True, 'hot_reload': True,
'max_retry_count': 3, 'max_retry_count': 3,
'isolation': False, # 默认不隔离,插件可在 settings.isolation 中声明 'isolation': True, # 生产默认进程隔离,插件崩溃不影响框架
}, },
'auto_start_scripts': { 'auto_start_scripts': {
'enabled': True, 'enabled': True,
+1
View File
@@ -33,6 +33,7 @@ class WebPanelManager:
app['service_manager'] = self.sm app['service_manager'] = self.sm
app['auth_service'] = self.sm.get_service("auth") app['auth_service'] = self.sm.get_service("auth")
app['log_service'] = self.sm.get_service("log") app['log_service'] = self.sm.get_service("log")
app['sensu_db'] = self.sm.get_service("sensu_db")
app['panel_config'] = { app['panel_config'] = {
'username': self.panel_user, 'username': self.panel_user,
'password': self.panel_pass, 'password': self.panel_pass,
+7
View File
@@ -272,6 +272,10 @@ def setup_file_routes(app, service_manager, prefix=''):
else: else:
p.unlink() p.unlink()
logger.info(f"🗑 删除: {p}") logger.info(f"🗑 删除: {p}")
# 审计日志
db = request.app.get("sensu_db")
if db:
db.log_audit(request.get("user", {}).get("username", "?"), "file_delete", str(p))
return web.json_response({"ok": True}) return web.json_response({"ok": True})
except Exception as e: except Exception as e:
return web.json_response({"error": str(e)}, status=500) return web.json_response({"error": str(e)}, status=500)
@@ -375,6 +379,9 @@ def setup_file_routes(app, service_manager, prefix=''):
content = data.get("content", "") content = data.get("content", "")
p.write_text(content, encoding="utf-8") p.write_text(content, encoding="utf-8")
logger.info(f"💾 写入文件: {p} ({len(content)} bytes)") logger.info(f"💾 写入文件: {p} ({len(content)} bytes)")
db = request.app.get("sensu_db")
if db:
db.log_audit(request.get("user", {}).get("username", "?"), "file_write", str(p))
return web.json_response({"ok": True, "size": len(content)}) return web.json_response({"ok": True, "size": len(content)})
except Exception as e: except Exception as e:
return web.json_response({"error": str(e)}, status=500) return web.json_response({"error": str(e)}, status=500)