340 lines
15 KiB
Markdown
340 lines
15 KiB
Markdown
# 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 更新无法到达客户端
|
||
|
||
---
|
||
|
||
*审计报告结束*
|