ZCLAW SaaS+Tauri 系统性功能审计报告 V8
审计日期: 2026-03-29
审计范围: 全量三端审计 — SaaS 后端 + Tauri 桌面端 + Admin 管理后台
审计方法: 五步审计流程 + 十项通用清单 + 五种差距模式 + 安全专项
前次审计: V7 (2026-03-28, 已归档)
一、执行摘要
| 指标 |
数值 |
| SaaS API 端点 |
76+ (9 模块, 22+ 数据表) |
| Tauri 命令 |
150+ (73 个 invoke 调用) |
| Admin 页面 |
12 (含 login) |
| 文档-代码对齐率 |
~95% |
| 数据流连通率 |
60% (3/5 完整连通, 1 部分连通, 1 断裂) |
| Dead Code |
28+ #[allow(dead_code)], 35+ 未调用 API 方法 |
| 安全漏洞 |
1 CRITICAL + 2 HIGH + 2 MEDIUM |
| 差距模式发现 |
12 个 (P0×1, P1×4, P2×4, P3×3) |
| 整体完成度 |
~82% (核心功能可用,集成链路存在断裂) |
二、功能清单与完成度矩阵
2.1 架构层
| 功能 |
设计目标 |
SaaS |
Tauri |
Admin |
完成度 |
关键差距 |
| 通信层 |
三模式连接 (Kernel/Gateway/SaaS) |
N/A |
✅ |
N/A |
85% |
hand_run 桩命令 |
| 状态管理 |
18 Zustand Store |
N/A |
N/A |
N/A |
80% |
消息不持久化 |
| 安全认证 |
Ed25519+JWT+TOTP |
✅ |
✅ |
✅ |
80% |
生物识别/FIDO2 未实现 |
2.2 核心功能
| 功能 |
设计目标 |
SaaS |
Tauri |
Admin |
完成度 |
关键差距 |
| 聊天界面 |
流式响应+多模型 |
✅ Relay |
✅ Stream |
N/A |
92% |
超长消息卡顿 |
| Agent 分身 |
CRUD+模板+切换 |
✅ Template |
✅ Agent |
✅ Template |
85% |
导入/导出未实现 |
| Hands 系统 |
9+ 自主能力 |
N/A |
✅ 9 Hands |
N/A |
70% |
Predictor/Lead 无代码 |
2.3 智能层
| 功能 |
设计目标 |
SaaS |
Tauri |
Admin |
完成度 |
关键差距 |
| Agent 记忆 |
跨会话+语义搜索 |
N/A |
✅ Viking |
N/A |
90% |
大量记忆检索变慢 |
| 身份演化 |
SOUL.md+自动改进 |
N/A |
✅ |
N/A |
70% |
Tauri 模式内存存储重启丢失 |
| 反思引擎 |
自动分析+建议 |
N/A |
✅ |
N/A |
65% |
建议具体性待改进 |
| 心跳巡检 |
定期巡检+主动提醒 |
✅ 设备心跳 |
✅ |
N/A |
70% |
持久化调度缺失 |
| 自主授权 |
三级授权+审批 |
N/A |
✅ |
N/A |
75% |
批量审批未实现 |
| 上下文压缩 |
智能摘要 |
N/A |
✅ |
N/A |
75% |
LLM 增强摘要未使用 |
2.4 平台层
| 功能 |
设计目标 |
SaaS |
Tauri |
Admin |
完成度 |
关键差距 |
| 技能系统 |
69 SKILL.md |
N/A |
✅ |
N/A |
80% |
WASM/Native 未实现 |
| 智能路由 |
语义匹配 |
N/A |
❌ |
N/A |
50% |
SemanticSkillRouter 核心未实现 |
| Pipeline DSL |
YAML 工作流 |
N/A |
✅ |
N/A |
90% |
无重大差距 |
| SaaS 平台 |
云端能力 |
✅ |
✅ |
✅ |
88% |
SQL 注入+配置单向同步+遥测空转 |
三、五步审计结果
3.1 Step 1: 文档对齐
| 检查项 |
结果 |
| SaaS API 路由 vs 文档 |
✅ 76+ 端点全部对齐 |
| Tauri 命令 vs 文档 |
✅ 150+ 命令已注册 |
| Admin 页面 vs 文档 |
✅ 12 页面全部存在 |
| 功能文档声称 vs 实际 |
⚠️ 部分功能声称高于实际 (智能路由 50% 声称 Phase 1 完成) |
对齐率: ~95%
3.2 Step 2: 数据流追踪
| # |
数据流 |
状态 |
断点 |
| DF1 |
认证 (Desktop→SaaS) |
✅ 完整 |
无 |
| DF2 |
聊天 Relay (Desktop→SaaS→LLM) |
⚠️ 部分 |
chatStore SaaS 模式走 WS 而非 HTTP relay |
| DF3 |
配置同步 (Desktop↔SaaS) |
❌ 单向 |
Pull✅, Push/Diff❌ (定义但未调用) |
| DF4 |
设备管理 (Desktop→SaaS) |
✅ 完整 |
心跳不传 OS/version |
| DF5 |
遥测上报 (Desktop→SaaS) |
❌ 断裂 |
recordLLMUsage/recordAuditEvent 零调用 |
连通率: 60% (3/5 完整)
3.3 Step 3: Dead Code 识别
Rust #[allow(dead_code)] — 28 处
| 分类 |
数量 |
说明 |
| Intelligence 模块 |
12 |
heartbeat/reflection/identity/compactor 预留给未来 Tauri 命令 |
| Memory 模块 |
3 |
persistent.rs 遗留迁移代码 |
| Runtime 驱动 |
4 |
反序列化字段未被访问 |
| Kernel/Pipeline |
4 |
预留功能 (export, intent, stage) |
| lib.rs |
2 |
HealthStatus 枚举 + legacy 函数 |
| Growth |
2 |
缓存+存储预留 |
未调用的 SaaS API 方法 — 35+ 个
需要关注的桌面端方法 (应在 desktop 中使用但未使用):
healthCheck() — 未被任何 health check 调用使用
listDevices() — 设备列表未在桌面端展示
getRelayTask() — 单个任务查询未使用
computeConfigDiff() — ❌ 零调用,配置差异计算断裂
syncConfig() — ❌ 零调用,配置推送断裂
Admin 专用方法 (桌面端不使用是正常的):
- Provider/Model/Account/Role/Permission CRUD (~30 个)
- 这些方法在 admin/src/ 中通过独立的 api-client.ts 调用
Rust TODO/FIXME — 5 处
| 文件 |
行号 |
内容 |
| pipeline_commands.rs |
529 |
// TODO: use actual time |
| pipeline_commands.rs |
869 |
// TODO: add pattern support |
| kernel/src/registry.rs |
56 |
// TODO: Track this |
| kernel/src/export/html.rs |
17 |
// TODO: Implement template-based HTML export |
| pipeline/src/actions/orchestration.rs |
41 |
// TODO: implement graph storage |
3.4 Step 4: 接口一致性
TS 类型差异 — 10+ 组
| 类型对 |
主要差异 |
| AccountPublic |
admin: 联合类型 role/status; desktop: string |
| OperationLog vs OperationLogInfo |
id 类型 string vs number; details 类型不同 |
| ConfigItem vs SaaSConfigItem |
current_value 类型不同; desktop 多 created_at/updated_at |
| RelayTask vs RelayTaskInfo |
status 联合类型 vs string; desktop 多 max_attempts/created_at |
| PromptTemplate vs PromptTemplateInfo |
source/status 联合类型 vs string |
| Provider vs ProviderInfo |
admin 有 api_key 字段; desktop 无 |
| Model vs ModelInfo |
desktop 多 created_at/updated_at |
3.5 Step 5: 端到端验证
| 测试流程 |
结果 |
说明 |
| 用户注册→登录→获取信息 |
✅ |
完整链路通畅 |
| 登录→设备注册→心跳 |
✅ |
降级逻辑正常 |
| 配置 Pull |
✅ |
仅拉取方向 |
| 配置 Push/Diff |
❌ |
方法未调用 |
| Relay chat→SSE |
✅ |
llm-service.ts 路径完整 |
| Admin 登录→管理→CRUD |
✅ |
全部页面可操作 |
四、十项通用审计清单
| # |
审计点 |
结果 |
说明 |
| 1 |
代码存在性 |
✅ 95% |
所有文档声明功能有对应代码 |
| 2 |
调用链连通 |
⚠️ 70% |
遥测/配置推送/OTA 链路断裂 |
| 3 |
配置传递 |
✅ 90% |
saas-config.toml 端到端有效 |
| 4 |
降级策略 |
✅ 85% |
3 次失败→tauri 模式降级正常 |
| 5 |
错误处理 |
⚠️ 75% |
Desktop 401 不自动 logout |
| 6 |
安全审计 |
❌ 60% |
SQL 注入 + 权限缺失 |
| 7 |
日志记录 |
⚠️ 70% |
migration/telemetry 模块缺 operation_logs |
| 8 |
测试覆盖 |
✅ 80% |
SaaS 62 个集成测试, 但覆盖率不足 |
| 9 |
类型一致性 |
⚠️ 70% |
10+ 组类型定义不同步 |
| 10 |
前后端接口匹配 |
⚠️ 75% |
大部分匹配, 部分字段差异 |
五、五种差距模式
5.1 "写了没接" — 5 项确认
| # |
项目 |
位置 |
严重级别 |
| G-01 |
recordLLMUsage / recordAuditEvent 零外部调用 |
telemetry-collector.ts |
P0 |
| G-02 |
startPromptOTASync 从未调用 |
llm-service.ts |
P1 |
| G-05 |
computeConfigDiff / syncConfig push 未接入 |
saas-client.ts |
P1 |
| G-10 |
hand_run_status / hand_run_list 后端桩命令 |
kernel_commands.rs |
P3 |
| — |
healthCheck() 未被 health check 流程调用 |
saas-client.ts |
P2 |
5.2 "接了没传" — 1 项确认
| # |
项目 |
位置 |
严重级别 |
| G-04 |
心跳仅传 device_id, 不传 OS/version |
saasStore.ts |
P1 |
5.3 "传了没存" — 2 项确认
| # |
项目 |
位置 |
严重级别 |
| G-06 |
telemetry 端点不写 operation_logs |
telemetry/handlers.rs |
P2 |
| G-09 |
心跳不写 operation_logs |
account/handlers.rs |
P2 |
5.4 "存了没用" — 2 项确认
| # |
项目 |
位置 |
严重级别 |
| G-03 |
max_queue_size / max_concurrent relay 未消费 |
relay/service.rs |
P1 |
| G-07 |
account_api_keys 被 relay 绕过 (用 provider_key_pool) |
model_config/ |
P2 |
5.5 "双系统不同步" — 2 项确认
| # |
项目 |
说明 |
严重级别 |
| G-08 |
Desktop 401 不自动 logout, Admin 会 |
用户体验不一致 |
P2 |
| G-12 |
双端错误类型不统一 (SaaSApiError vs ApiRequestError) |
不可复用 |
P3 |
六、安全审计专项
6.1 CRITICAL: SQL 注入
文件: crates/zclaw-saas/src/agent_template/service.rs
全文件使用 format!() 直接拼接用户输入到 SQL, 依赖手工 replace('\'', "''") 转义。这是项目中唯一未使用 $N 参数化查询的 service 文件。
受影响的操作:
list_templates() — WHERE 条件 (category, source, visibility, status)
update_template() — SET 字段 (description, model, system_prompt, tools, capabilities, visibility, status) + WHERE id
攻击向量示例:
修复方案: 改用 $N 参数化查询, 参照 account/service.rs 和 model_config/service.rs 的实现模式。
6.2 HIGH: 部分模块使用 format! 构造 SQL (但有 $N 绑定)
文件: prompt/service.rs, telemetry/service.rs
这些文件在 WHERE 条件拼接时使用 format!(), 但值通过 .replace('\'', "''") 转义。虽然后续使用 $N 绑定值, 但 WHERE 条件本身的构造仍依赖手工转义。
6.3 HIGH: 配置同步缺少权限检查
POST /api/v1/config/sync (migration/handlers.rs) 端点未验证调用者是否有 admin 权限。任何已认证用户都可以推送配置。
6.4 MEDIUM: 配额限制未执行
RelayConfig 定义了 max_queue_size (默认 1000) 和 max_concurrent_per_provider (默认 5), 但 execute_relay 中未做队列容量和并发控制检查。
6.5 MEDIUM: Desktop 401 处理不完整
Desktop 端 SaaSClient 在 401 刷新失败后不自动 logout, 可能导致用户卡在过期会话中。Admin 端会自动跳转到登录页。
七、问题优先级与修复计划
P0 — 立即修复 (阻塞功能)
| # |
问题 |
修复方案 |
影响范围 |
预估 |
| G-01 |
遥测系统全链路空转 |
在 llm-service.ts 的 chatCompletion 回调和 intelligence-hooks 中调用 recordLLMUsage / recordAuditEvent |
telemetry-collector.ts, llm-service.ts, intelligence_hooks.rs |
2h |
| SEC-01 |
SQL 注入 (agent_template) |
改用 $N 参数化查询 |
agent_template/service.rs |
2h |
P1 — 本周修复 (功能断裂)
| # |
问题 |
修复方案 |
影响范围 |
预估 |
| G-02 |
Prompt OTA 未启动 |
在 saasStore.restoreSession/login 中调用 startPromptOTASync |
llm-service.ts, saasStore.ts |
1h |
| G-03 |
Relay 无并发限制 |
在 execute_relay 中加入队列容量和并发检查 |
relay/service.rs |
2h |
| G-04 |
心跳不传 OS/version |
在 deviceHeartbeat 中携带 platform/app_version |
saas-client.ts, account/handlers.rs |
1h |
| G-05 |
配置只能单向拉取 |
在 saasStore 中接入 computeConfigDiff 和 syncConfig push |
saasStore.ts, saas-client.ts |
3h |
P2 — 两周内修复 (质量提升)
| # |
问题 |
修复方案 |
影响范围 |
预估 |
| G-06 |
Telemetry 端点缺审计日志 |
添加 log_operation 调用 |
telemetry/handlers.rs |
1h |
| G-07 |
account_api_keys 未被消费 |
明确用途: 要么让 relay 消费, 要么移除 |
model_config/, relay/ |
4h |
| G-08 |
Desktop 401 不自动 logout |
在 refresh 失败后调用 saasStore.logout() |
saas-client.ts |
1h |
| SEC-02 |
配置同步缺权限检查 |
在 migration handler 中添加 admin 权限校验 |
migration/handlers.rs |
1h |
P3 — 长期优化 (技术债)
| # |
问题 |
修复方案 |
影响范围 |
预估 |
| G-10 |
hand_run 桩命令 |
实现真实的运行状态追踪 |
kernel_commands.rs |
3h |
| G-12 |
双端错误类型不统一 |
抽取共享错误类型到 @zclaw/types |
admin+desktop |
4h |
| — |
28 处 dead_code |
评估后移除或保留 |
desktop/src-tauri/ |
2h |
| — |
10+ 组类型定义差异 |
统一类型定义, 消除不一致 |
admin+desktop types |
4h |
八、三端完成度评估
SaaS 后端: 88%
| 模块 |
API 路由 |
完成度 |
主要问题 |
| Auth |
8 |
95% |
refresh 缺审计日志 |
| Account |
12 |
90% |
dashboard 7 次串行查询 |
| Model Config |
14 |
90% |
account_api_keys 未被消费 |
| Relay |
9 |
85% |
无并发限制, SSRF 需复核 |
| Migration |
9 |
70% |
push 缺权限, 5 端点缺审计日志 |
| Role |
7 |
95% |
无重大问题 |
| Prompt OTA |
8 |
90% |
桌面端未启动 OTA |
| Agent Template |
5 |
75% |
SQL 注入 |
| Telemetry |
4 |
80% |
桌面端未调用上报函数 |
Tauri 桌面端: 78%
| 子系统 |
命令数 |
完成度 |
主要问题 |
| Kernel |
29 |
85% |
hand_run 桩, scheduled_task 未实现 |
| Pipeline |
13 |
90% |
时间戳占位符 |
| Viking |
13 |
95% |
无重大问题 |
| LLM |
3 |
95% |
无重大问题 |
| Intelligence |
6 |
80% |
多个预留函数 |
| Browser |
23 |
85% |
需要 Fantoccini 运行时 |
| SaaS 集成 |
30+ 方法 |
65% |
35+ 方法未调用, 遥测断裂 |
Admin 管理后台: 85%
| 维度 |
完成度 |
主要问题 |
| 页面覆盖 |
95% |
12 个页面全覆盖 |
| API 调用 |
90% |
分页未连接 API |
| 认证 |
90% |
token 刷新逻辑完善 |
| 类型定义 |
75% |
与桌面端不一致 |
九、关键决策建议
- 遥测系统 — 必须在聊天回调和智能层 hook 中接入 recordLLMUsage, 否则 SaaS 端的遥测统计页面展示全零数据
- SQL 注入 — agent_template/service.rs 必须立即改为参数化查询, 这是生产安全红线
- 配置同步 — 建议实现双向同步, 当前只能 SaaS→Desktop 单向拉取
- 类型共享 — 考虑抽取 @zclaw/types 共享包, 消除 admin/desktop 类型不一致
- Prompt OTA — 桌面端必须在登录后启动 OTA 同步, 否则 prompt 更新无法到达客户端
审计报告结束