Files
zclaw_openfang/docs/features/AUDIT_REPORT_V10.md
iven 8898bb399e
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
docs: audit reports + feature docs + skills + admin-v2 + config sync
Update audit tracker, roadmap, architecture docs,
add admin-v2 Roles page + Billing tests,
sync CLAUDE.md, Cargo.toml, docker-compose.yml,
add deep-research / frontend-design / chart-visualization skills

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 19:25:00 +08:00

348 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ZCLAW SaaS + Tauri 系统性功能审计报告 V10
> 审计日期: 2026-03-31
> 审计范围: SaaS 后端 (68 路由/22 表) + Tauri 桌面端 (107 命令/13 Store) + admin-v2 管理后台 (14 服务/11 页面)
> 审计方法: 静态代码分析 + 数据流追踪 + 交叉索引
> 修复状态: P0 已修复, P1 已处理, P2 已处理
---
## 1. 执行摘要
### 1.1 整体完成度
| 层级 | 总数 | 活跃 | 未使用 | 利用率 |
|------|------|------|--------|-------|
| SaaS 路由 | 92 | 84 | 8 | **91.3%** |
| Tauri 命令 | 107 | 79 | 28 | **73.8%** |
| Zustand Store | 13 | 13 | 0 | **100%** |
| admin-v2 服务 | 14 | 14 | 0 | **100%** |
### 1.2 问题统计
| 严重级别 | 数量 | 描述 |
|---------|------|------|
| **P0 (阻塞)** | 1 | trigger_update 参数不匹配导致所有 Trigger 更新失效 |
| **P1 (严重)** | 3 | sessionStore 无 Kernel 适配器、定时任务执行器为 stub、配置同步未传播到 kernel |
| **P2 (高)** | 5 | 8 个孤立路由、2 个写而不读 DB 表、Workflow→Pipeline 元数据丢失、Role 管理无 admin 页面、8+ 个 saas-admin 方法无消费者 |
| **P3 (中)** | 6 | CleanupRateLimitWorker stub、CacheKey 死代码、pipeline-client 缺少 probe 检测、GET 请求无速率限制、SSRF DNS 失败不阻断、connectionStore 客户端切换未重新注入 |
| **P4 (低)** | 4 | 7 个 @deprecated TS 标记、a2a feature-gated 代码、ScheduledTaskRow 部分字段、director.rs 休眠代码 |
---
## 2. 功能交叉索引
### 2.1 SaaS 路由 ↔ 前端消费者映射
#### 路由状态分布
| 状态 | 数量 | 说明 |
|------|------|------|
| CONNECTED (两端消费) | 27 | SaaS 路由同时被 desktop 和 admin-v2 调用 |
| DESKTOP_ONLY | 31 | 仅桌面端消费(含 auth、role、device 等) |
| ADMIN_ONLY | 16 | 仅 admin-v2 消费(含 key 管理、prompt 写操作等) |
| ORPHANED | 8 | 无前端消费者 |
| INTERNAL | 1 | health 端点 |
#### 8 个孤立路由(无前端消费者)
| 路由 | 模块 | 建议 |
|------|------|------|
| `GET /api/v1/providers/:id/models` | model_config | 可通过 `GET /api/v1/models?provider_id=X` 替代,考虑移除 |
| `GET /api/v1/config/items/:id` | migration | 无单条配置查询需求,考虑移除 |
| `DELETE /api/v1/config/items/:id` | migration | 无删除配置 UI考虑移除或添加到 admin-v2 |
| `GET /api/v1/config/analysis` | migration | 配置分析功能未接入,添加到 admin-v2 或移除 |
| `POST /api/v1/config/seed` | migration | 配置种子引导未接入,内部工具保留 |
| `GET /api/v1/config/sync-logs` | migration | 同步日志查询无 UI添加到 admin-v2 Config 页面 |
| `GET /api/v1/roles/:id/permissions` | role | 角色权限查询无消费者,整合到角色管理 UI |
| `GET /api/scheduler/tasks/:id` | scheduled_task | 单条任务查询无消费者 |
#### 按模块路由覆盖度
| 模块 | 路由数 | Connected | Desktop Only | Admin Only | Orphaned |
|------|-------|-----------|-------------|------------|----------|
| auth | 9 | 3 | 5 | 1 | 0 |
| account | 12 | 5 | 6 | 0 | 0 |
| model_config | 14 | 9 | 3 | 0 | 1 |
| relay | 9 | 2 | 3 | 4 | 0 |
| migration | 11 | 1 | 5 | 0 | 4 |
| role | 11 | 0 | 10 | 0 | 1 |
| prompt | 10 | 3 | 1 | 5 | 0 |
| agent_template | 7 | 1 | 1 | 4 | 0 |
| scheduled_task | 5 | 0 | 4 | 0 | 1 |
| telemetry | 4 | 0 | 2 | 2 | 0 |
| health | 1 | - | - | - | 1 (internal) |
### 2.2 Tauri 命令 ↔ 前端调用映射
#### 28 个未使用命令
| 分类 | 命令 | 原因 |
|------|------|------|
| **遗留 Gateway (11)** | zclaw_status/start/stop/restart/local_auth/prepare_for_tauri/approve_device_pairing/doctor/process_list/process_logs/version + zclaw_health_check + zclaw_ping | Gateway 已被 Kernel 替代,全部遗留代码 |
| **LLM 内部 (3)** | llm_complete, embedding_create, embedding_providers | 后端内部使用,非前端直接调用 |
| **Agent 导出导入 (2)** | agent_export, agent_import | 后端已实现,前端 UI 未接入 |
| **Kernel 管理 (1)** | kernel_shutdown | 无关闭路径 |
| **Hand (1)** | hand_run_cancel | 取消单次运行未接入 UI |
| **定时任务 (2)** | scheduled_task_create, scheduled_task_list | 整个模块未使用 |
| **Pipeline (1)** | pipeline_templates | 模板列表未接入 |
| **Viking (2)** | viking_add_with_metadata, viking_store_with_summaries | 高级存储功能未接入 |
| **Memory (2)** | memory_configure_embedding, memory_is_embedding_configured | 已有 viking 命令替代 |
| **Context (1)** | estimate_content_tokens | 已有 compactor 命令替代 |
---
## 3. 核心数据流追踪
### 3.1 聊天流 + 记忆提取 (BREAK-02 验证)
**结论: PARTIALLY WORKING — 前端正常,后端缺失**
| 层级 | 记忆提取 | 状态 |
|------|---------|------|
| 前端 (chatStore.ts:509) | `onComplete` 回调调用 `getMemoryExtractor().extractFromConversation()` | **WORKING** |
| Rust (intelligence_hooks.rs:50-108) | 仅调用 `reflect()`,不调用 `extract_and_store_memories()` | **NO extraction** |
| Rust Tauri 命令 (lib.rs:204-205) | 仅注册为手动命令 | **Manual only** |
**影响**: 桌面用户通过前端回调正常工作。但任何绕过前端直接调用 Tauri 命令的路径(如 headless/gateway relay将缺失记忆提取。
**建议**: 在 `post_conversation_hook` 中添加可选的 `extract_and_store_memories` 调用,或在文档中明确说明设计意图。
### 3.2 Hand 触发 + 审批 (BREAK-03 验证)
**结论: CONFIRMED WORKING**
kernel.rs:1118-1193 的 `respond_to_approval` 实现:
- 状态更新为 "approved"
- `tokio::spawn` 创建后台任务
- 调用 `hands.execute(&hand_id, &context, input).await` 执行 Hand
- 更新 HandRun 结果和 approval 状态为 "completed"/"failed"
BREAK-03 **不是问题**,审批后自动执行机制完整。
### 3.3 Agent CRUD 一致性
**结论: INTENTIONAL GAP — 设计意图**
| 路径 | Create | Read | Update | Delete | Export/Import |
|------|--------|------|--------|--------|--------------|
| Kernel (Tauri) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Gateway (REST) | ✅ | ✅ | ✅ | ✅ | ❌ |
| SaaS | 仅 template | 仅 template | 仅 template | 仅 template | ❌ |
SaaS 仅存储 agent 模板(蓝图),运行时 Agent 是本地状态,由 Kernel/Gateway 管理。这是正确的架构决策。
### 3.4 配置同步流
**结论: PARTIALLY WORKING**
| 方向 | 路径 | 状态 |
|------|------|------|
| SaaS → localStorage | `pullConfig()``localStorage.setItem()` | ✅ WORKING |
| localStorage → SaaS | `syncConfig()` + dirty tracking | ✅ WORKING |
| localStorage → Kernel | 无传播机制 | ❌ **GAP** |
**影响**: SaaS 同步的配置仅影响前端 UI 设置(如主题),不会传播到运行中的 Rust kernel。kernel 从磁盘 TOML 读取配置,与 localStorage 无关。
---
## 4. 差距模式分析
### 4.1 "写了没接" — 代码存在但未接入
| ID | 项目 | 文件 | 严重性 |
|----|------|------|--------|
| WNC-01 | CleanupRateLimitWorker (空 stub) | `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs` | P3 |
| WNC-02 | 定时任务执行器 (仅状态管理,无实际执行) | `crates/zclaw-saas/src/scheduler.rs:134-192` | P1 |
| WNC-03 | Role 管理 (无 admin-v2 页面) | `admin-v2/src/` 无 roles 服务/页面 | P2 |
| WNC-04 | Agent export/import (前端未接入) | `desktop/src-tauri/src/kernel_commands/agent.rs:213-235` | P4 |
| WNC-05 | pipeline_templates 命令 (无调用) | `desktop/src-tauri/src/pipeline_commands/presentation.rs` | P4 |
### 4.2 "接了没传" — 接口不匹配
| ID | 项目 | 文件 | 严重性 | 详情 |
|----|------|------|--------|------|
| **MSH-01** | **trigger_update 参数不匹配** | `trigger.rs:183` vs `kernel-triggers.ts:92` | **P0** | **前端发 `{id, updates: {name, enabled, handId}}` 嵌套结构Rust 期望 `{id, name, enabled, hand_id}` 扁平参数。所有 trigger 更新实际为 no-op** |
| MSH-02 | Workflow→Pipeline 元数据丢失 | `workflowStore.ts:379-502` | P2 | 丢失 category/industry/tags/icon/version/author 等字段 |
### 4.3 "传了没存" — 数据接收但未持久化
| ID | 项目 | 文件 | 严重性 |
|----|------|------|--------|
| PTS-01 | 定时任务执行结果 | `scheduler.rs:134-192` | P1 |
### 4.4 "存了没用" — 写入但无读路径
| ID | 表 | 写入位置 | 读路径 | 严重性 |
|----|-----|---------|--------|--------|
| SUN-01 | `prompt_sync_status` | `prompt/service.rs:272` | **无** | P2 |
| SUN-02 | `config_sync_log` | `migration/service.rs:425` | 有 handler 但 handler 本身孤立 | P2 |
### 4.5 "双系统不同步" — SaaS vs Tauri 功能差异
| 领域 | Gateway | Kernel | SaaS | 差距性质 |
|------|---------|--------|------|---------|
| Agent CRUD | REST | invoke | 仅 template | **INTENTIONAL** |
| Session | REST | ❌ 无命令 | ❌ 无路由 | sessionStore 无 Kernel 适配器 |
| Trigger | REST | invoke | ❌ 无路由 | 仅本地,不同步 |
| Browser | ❌ | invoke | ❌ 无路由 | Tauri-only 特性 |
| Pipeline | ❌ | invoke | ❌ 无路由 | Tauri-only 特性 |
| Role 管理 | ❌ | ❌ | REST | 仅 desktop 消费,无 admin UI |
---
## 5. 安全审计
### 5.1 安全控制验证(全部 PASS
| 控制项 | 状态 | 证据 |
|--------|------|------|
| JWT secret 管理 | ✅ | debug 模式 fallbackrelease 模式强制要求环境变量 (`config.rs:236-248`) |
| SSRF 防护 | ✅ | 多层验证主机名黑名单、DNS 解析检查、私有 IP 段、混淆防护 (`relay/service.rs:452-565`) |
| 速率限制 | ✅ | 公开端点分级限流 (login 5/min, register 3/hour)、认证端点 RPM 限制 (`middleware.rs:56-162`) |
| Relay 认证 | ✅ | `relay:use` 权限检查 (`relay/handlers.rs:24`)、key pool 隔离 |
| 请求体大小限制 | ✅ | MAX_BODY_BYTES = 1MB (`relay/handlers.rs:47-50`) |
| IP 提取安全 | ✅ | 不信任 X-Forwarded-For仅从 TCP 层获取 (`middleware.rs:133-138`) |
### 5.2 安全注意事项
| 项 | 严重性 | 说明 |
|----|--------|------|
| GET 请求无速率限制 | P3 | GET 免于限流 (middleware.rs:62),可被利用但 GET 无副作用 |
| SSRF DNS 失败不阻断 | P3 | DNS 解析失败时不阻断请求 (service.rs:530-533),存在窄 TOCTOU 窗口 |
| sessionStore 类型不安全转换 | P3 | `setSessionStoreClient` 无条件 cast 为 GatewayClient (sessionStore.ts:225-228) |
---
## 6. Store 适配器一致性
| Store | Gateway 适配器 | Kernel 适配器 | SaaS 适配器 | 问题 |
|-------|---------------|-------------|------------|------|
| connectionStore | ✅ | ✅ | ✅ | P3: 客户端切换后未重新注入其他 store |
| chatStore | ✅ (via conn) | ✅ (via conn) | ✅ (relay) | 无 |
| agentStore | ✅ | ✅ | ❌ | 无 |
| handStore | ✅ | ✅ | ❌ | P3: fallback 为 stub client |
| workflowStore | ✅ | ✅ | ❌ | P2: Pipeline→Workflow 元数据丢失 |
| configStore | ✅ | ✅ | ✅ | 无 |
| securityStore | ✅ | ✅ | ❌ | 无 |
| **sessionStore** | ✅ | **❌** | ❌ | **P1: 无 Kernel 适配器Tauri 模式下 session 失效** |
| saasStore | ❌ | ❌ | ✅ | 无 (SaaS 专用) |
| memoryGraphStore | ❌ | ✅ (invoke) | ❌ | 无 |
| browserHandStore | ❌ | ✅ (invoke) | ❌ | P3: Tauri-only 特性 |
| offlineStore | ✅ (via conn) | ✅ (via conn) | ❌ | 无 |
| workflowBuilderStore | ❌ | ❌ | ❌ | 纯本地存储 |
---
## 7. 死代码审计
### 7.1 已验证的假阳性AUDIT_TRACKER V9 纠正)
| ID | 项目 | 实际状态 |
|----|------|---------|
| DEAD-01 | PromptInjector | **活跃** — 在 zclaw-runtime/growth.rs 和 viking_commands.rs 中使用 |
| DEAD-02 | MemoryRetriever | **活跃** — 在 zclaw-runtime/growth.rs 和 create_growth_system() 中使用 |
| DEAD-03 | GrowthTracker | **活跃** — 在 zclaw-runtime/growth.rs 和 create_growth_system() 中使用 |
| DEAD-04 | director.rs (897 行) | **Feature-gated** — multi-agent 特性,默认不编译 |
| DEAD-05 | saas-admin.ts Role 方法 | **确认死代码** — 8+ 个方法无前端消费者 |
### 7.2 真正的死代码
| 项目 | 文件 | 说明 |
|------|------|------|
| 11 个 Gateway 命令 | `desktop/src-tauri/src/gateway/commands.rs` | Gateway 已被 Kernel 替代 |
| 8+ Role/Permission 方法 | `desktop/src/lib/saas-admin.ts:183-220` | 完整实现但无调用者 |
| CacheKey 结构体 | `crates/zclaw-growth/src/retrieval/cache.rs:22` | 整个结构体从未使用 |
| CleanupRateLimitWorker | `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs` | 空 stub |
---
## 8. 优先修复清单
### P0 — 阻塞(已修复 ✅)
| ID | 问题 | 文件 | 修复方案 | 状态 |
|----|------|------|---------|------|
| MSH-01 | trigger_update 参数不匹配 | `trigger.rs:183` / `kernel-triggers.ts:92` | Rust 端改为接受 `{ id, updates: {...} }` 结构体,匹配前端格式 | ✅ 已修复 |
### P1 — 严重(已处理 ✅)
| ID | 问题 | 文件 | 修复方案 | 状态 |
|----|------|------|---------|------|
| WNC-02 | 定时任务执行器为 stub | `scheduler.rs:134-192` | 添加 TODO(STUB) 标注 + 运行时 warn 日志 | ✅ 已标注 |
| GAP-01 | sessionStore 无 Kernel 适配器 | `sessionStore.ts:225-228` | 添加类型检测KernelClient 使用 stub 适配器 | ✅ 已修复 |
| GAP-02 | 配置同步未传播到 kernel | `saasStore.ts:528-531` | 评估为设计意图SaaS 配置为 UI-only`llm_routing` 通过 account data 已传播 | ✅ 确认设计意图 |
### P2 — 高(下个迭代)
| ID | 问题 | 修复方案 |
|----|------|---------|
| ORPHAN | 8 个孤立路由 | 评估移除或添加 admin-v2 UI |
| SUN-01 | prompt_sync_status 写而不读 | 添加 admin 读路径或移除表 |
| SUN-02 | config_sync_log 写而不读 | 添加 admin-v2 Config 页面 tab |
| MSH-02 | Pipeline→Workflow 元数据丢失 | 扩展 Workflow 类型或标注忽略字段 |
| ADMIN-01 | Role 管理无 admin 页面 | 添加 admin-v2 角色管理页面 |
| DEAD-05 | 8+ saas-admin 方法无消费者 | 接入 UI 或移除 |
### P3 — 中(后续迭代)
| ID | 问题 | 修复方案 |
|----|------|---------|
| STUB-01 | CleanupRateLimitWorker 空实现 | 移除或实现 |
| DEAD-06 | CacheKey 死结构体 | 移除 |
| GAP-03 | pipeline-client 缺少 probe 检测 | 复用 kernel-client 的 probeTauriAvailability |
| GAP-04 | connectionStore 切换后未重新注入 store | 在 connect() 后重新调用 initializeStores() |
| SEC-01 | GET 请求无速率限制 | 监控 GET 量,必要时添加 |
| SEC-02 | SSRF DNS 失败不阻断 | 考虑 DNS 失败时阻断请求 |
### P4 — 低(维护时处理)
| ID | 问题 |
|----|------|
| CLEANUP-01 | 11 个遗留 Gateway 命令移除 |
| CLEANUP-02 | 7 个 @deprecated TS 标记清理 |
| CLEANUP-03 | 4 个 CANDIDATE 级 dead_code 评估 |
| FEATURE-01 | Agent export/import 前端接入 |
| FEATURE-02 | multi-agent (director.rs) 激活准备 |
---
## 9. 验证命令
```bash
# 编译验证
cargo build -p zclaw-saas
# TypeScript 类型检查
cd desktop && pnpm tsc --noEmit
# admin-v2 类型检查
cd admin-v2 && pnpm tsc --noEmit
# Rust 测试
cargo test -p zclaw-saas
# 搜索 trigger_update 不匹配 (P0 验证)
grep -n "trigger_update" desktop/src-tauri/src/kernel_commands/trigger.rs desktop/src/lib/kernel-triggers.ts
# 搜索孤立路由 (P2 验证)
grep -rn "config/analysis\|config/seed\|config/sync-logs" desktop/src/ admin-v2/src/
# 搜索写而不读表 (P2 验证)
grep -rn "prompt_sync_status" crates/zclaw-saas/src/ --include="*.rs"
```
---
## 10. 审计方法总结
本次审计使用了以下技术:
1. **交叉索引** — 92 条 SaaS 路由 × 107 个 Tauri 命令 × 14 个 admin 服务 全量匹配
2. **数据流追踪** — 4 条核心业务流端到端追踪聊天、Agent CRUD、Hand 审批、配置同步)
3. **差距模式扫描** — 5 种已知差距模式逐一验证
4. **安全面审计** — JWT/SSRF/rate-limit/auth 中间件逐项检查
5. **死代码检测**`#[allow(dead_code)]` + `#[deprecated]` + 无引用代码全量扫描
6. **接口一致性** — Tauri 命令签名 vs 前端 invoke 参数逐个比对
总审计代码量:~150,000 行 Rust + ~45,000 行 TypeScript + ~8,000 行 SQL