# 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 **攻击向量示例**: ```sql -- category 参数: `' OR 1=1 --` → 绕过 WHERE 条件 -- id 参数: `' OR '1'='1` → 更新所有记录 ``` **修复方案**: 改用 `$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% | 与桌面端不一致 | --- ## 九、关键决策建议 1. **遥测系统** — 必须在聊天回调和智能层 hook 中接入 recordLLMUsage, 否则 SaaS 端的遥测统计页面展示全零数据 2. **SQL 注入** — agent_template/service.rs 必须立即改为参数化查询, 这是生产安全红线 3. **配置同步** — 建议实现双向同步, 当前只能 SaaS→Desktop 单向拉取 4. **类型共享** — 考虑抽取 @zclaw/types 共享包, 消除 admin/desktop 类型不一致 5. **Prompt OTA** — 桌面端必须在登录后启动 OTA 同步, 否则 prompt 更新无法到达客户端 --- *审计报告结束*