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
移除不再使用的数据脱敏功能,包括: 1. 删除data_masking模块 2. 清理loop_runner中的unmask逻辑 3. 移除前端saas-relay-client.ts中的mask/unmask实现 4. 更新中间件层数从15层降为14层 5. 同步更新相关文档(CLAUDE.md、TRUTH.md、wiki等) 此次变更简化了系统架构,移除了不再需要的敏感数据处理逻辑。所有相关测试证据和截图已归档。
247 lines
9.8 KiB
Markdown
247 lines
9.8 KiB
Markdown
# ZCLAW 发布前审计设计文档
|
||
|
||
> 日期: 2026-04-18
|
||
> 目标: 全维度审计系统问题,为首次用户发布做准备
|
||
> 方法: 4 专家组并行分析 + 交叉评审
|
||
|
||
## 背景
|
||
|
||
ZCLAW 已完成稳定化基线,进入发布准备阶段。在发布前组织了一次多维度深度审计,通过 4 个专家代理(后端稳定性、前端质量、安全与数据、工程卫生)并行分析,发现并验证了 24 个问题点。经交叉评审后纠正了 4 项原始审计误判。
|
||
|
||
## 审计纠正(原始误判)
|
||
|
||
| 原始声称 | 实际情况 |
|
||
|----------|----------|
|
||
| Cargo.lock 缺失 | 已提交并跟踪,`git ls-files Cargo.lock` 确认 |
|
||
| 无 CI/CD | `.github/workflows/ci.yml` + `release.yml` 完整存在 |
|
||
| src-tauri LOC 偏差 3x | 实际 61,257 行,与 TRUTH.md ~61,400 基本一致 |
|
||
| Token INTEGER 溢出 | 每行存单次请求 token 不溢出,SUM() 已返回 BIGINT |
|
||
|
||
---
|
||
|
||
## 第一层:发布阻塞项(必须修复)
|
||
|
||
### 1. Director 死锁风险 — P0 CRITICAL
|
||
|
||
**文件**: `crates/zclaw-kernel/src/director.rs:506-536`
|
||
|
||
**问题**: `send_to_agent()` 顺序获取 `pending_requests.lock()`(L506)和 `inbox.lock()`(L519),后者在 `tokio::time::timeout` 内跨 `rx.recv().await` 持有(L521-536)。两个并发调用可互相阻塞。另有一条死信通道 `_response_tx/_response_rx`(L490)从未连接——sender 存入 pending_requests 但 receiver 无人读取。
|
||
|
||
**验证**: 修复后需添加并发 `send_to_agent()` 测试验证死锁消除。
|
||
|
||
**修复方案**: 用 `oneshot` channel 重构响应接收模式:
|
||
- 每次 `send_to_agent()` 创建 `oneshot::channel`
|
||
- sender 存入 `pending_requests`,receiver 配合 `tokio::time::timeout` 等待
|
||
- 新增独立的 inbox 消费任务分发响应到对应 oneshot sender
|
||
- 变更 `pending_requests` 类型为 `HashMap<String, oneshot::Sender<A2aEnvelope>>`
|
||
|
||
**工时**: 2-4h(重构 + 测试更新)
|
||
|
||
### 2. Pipeline Executor 内存泄漏 — P0 HIGH
|
||
|
||
**文件**: `crates/zclaw-pipeline/src/executor.rs`
|
||
|
||
**问题**: `runs: RwLock<HashMap<String, PipelineRun>>` 和 `cancellations: RwLock<HashMap<String, bool>>` 无限增长,无清理路径。
|
||
|
||
**修复方案**:
|
||
- 添加 `cleanup(max_age: Duration)` 方法,清除已完成/失败/取消的旧记录
|
||
- 在 `execute_with_id()` 完成后自动调用清理
|
||
- 设置 `max_completed_runs` 上限(如 100),超限淘汰最旧记录
|
||
|
||
**工时**: <1h
|
||
|
||
### 3. Pipeline 步骤超时缺失 + Delay 无上限 — P0 HIGH
|
||
|
||
**文件**: `crates/zclaw-pipeline/src/executor.rs`
|
||
|
||
**问题**: `ExecuteError::Timeout` 已定义但从未触发。每步执行无超时包装。`Action::Delay { ms }` 接受原始 u64,恶意 YAML 可设 `ms: u64::MAX`。
|
||
|
||
**修复方案**:
|
||
- 用 `tokio::time::timeout` 包装每步 `execute_action` 调用
|
||
- 使用 `PipelineSpec.timeout_secs`(已存在但未使用),cap 在 5 分钟
|
||
- Delay ms 上限 60000,超出时 warn 并截断
|
||
- `parser.rs`/`parser_v2.rs` 添加 YAML 解析时验证
|
||
|
||
**工时**: 1-2h
|
||
|
||
### 4. TRUTH.md Hands 数量偏差 — P0 (文档完整性)
|
||
|
||
**文件**: `docs/TRUTH.md`, `CLAUDE.md`
|
||
|
||
**问题**: 声称 9 个 Hand 启用,实际 kernel 注册 7 个:
|
||
- 6 个通过 `hands/*.HAND.toml` 扫描注册:Browser/Clip/Collector/Quiz/Researcher/Twitter
|
||
- 1 个通过 `kernel/mod.rs:96` 编程注册:ReminderHand(`_` 前缀豁免 HAND.toml 扫描,见 `trigger_manager.rs:139`)
|
||
- Whiteboard/Slideshow/Speech 的 HAND.toml 仅存在于 `.claude/worktrees/` 开发分支,无 `impl Hand for`,未合并到主分支
|
||
|
||
**修复方案**:
|
||
- TRUTH.md: 更新为 "6 HAND.toml + Reminder 系统内部 = 7 注册"
|
||
- CLAUDE.md §6: 明确标注 Whiteboard/Slideshow/Speech 为"开发中,未合并"
|
||
- 确认桌面 UI 是否展示 9 个 Hand,如有则同步更新
|
||
|
||
**工时**: <1h
|
||
|
||
### 5. rate_limit_events 清理 Worker 是空壳 — P0 (数据膨胀)
|
||
|
||
**文件**: `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs`
|
||
|
||
**问题**: Worker body 是 no-op(注释说"rate limit entries are in-memory"),但 main.rs 的 batch flush 确实将限流条目写入数据库。注意:内存中的 DashMap 清理每 300 秒运行一次(`state.rs:118`),但**数据库持久化条目**无限增长,无任何删除机制。
|
||
|
||
**修复方案**: 实现 Worker body,执行 `DELETE FROM rate_limit_events WHERE created_at < NOW() - INTERVAL '1 hour'`。确认调度器已注册此 Worker(main.rs:47 已注册)。
|
||
|
||
**工时**: <1h
|
||
|
||
---
|
||
|
||
## 第二层:强烈建议修复
|
||
|
||
### 6. TypeScript 编译排除安全关键文件
|
||
|
||
**文件**: `desktop/tsconfig.json`
|
||
|
||
**问题**: 排除了 `ErrorAlert.tsx`(文件已不存在,残留排除项)和 `ErrorBoundary.tsx`(527 行安全关键组件)。
|
||
|
||
**修复**: 删除排除项,运行 `tsc --noEmit` 验证 ErrorBoundary 无类型错误。
|
||
|
||
**工时**: <1h
|
||
|
||
### 7. LlmConfig api_key Debug 泄露
|
||
|
||
**文件**: `crates/zclaw-kernel/src/config.rs`
|
||
|
||
**问题**: `#[derive(Debug)]` 会在 `format!("{:?}", config)` 中打印 api_key 明文。虽然当前无代码 Debug-print 此结构,但日志调试时容易触发。
|
||
|
||
**修复**: 移除 `Debug` derive,实现自定义 `Debug` impl 用 `"***REDACTED***"` 遮蔽 api_key。
|
||
|
||
**工时**: <30min
|
||
|
||
### 8. 关键 .unwrap() 调用
|
||
|
||
**文件**:
|
||
- `crates/zclaw-saas/src/billing/handlers.rs:598` — Response builder unwrap
|
||
- `desktop/src-tauri/src/classroom_commands/mod.rs:58` — db_path.parent().unwrap()
|
||
|
||
**修复**: 替换为 `map_err` + `?` 传播。
|
||
|
||
**工时**: <1h
|
||
|
||
### 9. 静默吞错关键集群
|
||
|
||
**文件与修复**:
|
||
- `crates/zclaw-kernel/src/kernel/approvals.rs:88,93,124` — 已有 `tracing::warn!` 日志但级别应为 `error`(审批状态丢失是严重事件)
|
||
- `crates/zclaw-protocols/src/mcp_transport.rs:429` → 记录僵尸进程风险
|
||
- `crates/zclaw-kernel/src/events.rs:21` → `tracing::debug!("Event dropped: {:?}", e)`
|
||
- `crates/zclaw-runtime/src/tool/builtin/task.rs` → 日志记录 subtask 事件丢失
|
||
- `crates/zclaw-growth/src/storage/sqlite.rs` 迁移 → 匹配 `sqlx::Error::Database` 检查 SQLite 错误码 1 子错误 "duplicate column name",区分幂等迁移与真实错误
|
||
|
||
**工时**: 2-4h
|
||
|
||
### 10. 缺失数据库索引
|
||
|
||
**新文件**: `crates/zclaw-saas/migrations/20260418000001_add_missing_indexes.sql`
|
||
|
||
```sql
|
||
CREATE INDEX IF NOT EXISTS idx_rle_created_at ON rate_limit_events(created_at);
|
||
CREATE INDEX IF NOT EXISTS idx_billing_sub_plan ON billing_subscriptions(plan_id);
|
||
CREATE INDEX IF NOT EXISTS idx_ki_created_by ON knowledge_items(created_by);
|
||
```
|
||
|
||
**工时**: <1h
|
||
|
||
### 11. 配置验证缺失
|
||
|
||
**文件**: `crates/zclaw-saas/src/config.rs`
|
||
|
||
**修复**: 在 `SaaSConfig::load()` 添加:
|
||
- `jwt_expiration_hours >= 1`
|
||
- `max_connections > 0`
|
||
- 改善默认 DB URL 连接失败的错误信息
|
||
|
||
**工时**: <1h
|
||
|
||
### 12. MCP Transport 响应错配
|
||
|
||
**文件**: `crates/zclaw-protocols/src/mcp_transport.rs`
|
||
|
||
**问题**: stdin/stdout 分离的 Mutex 可导致并发请求收到错误响应。
|
||
|
||
**修复**: 合并 stdin + stdout 为单一 Mutex,在 write-then-read 周期内持有锁。
|
||
|
||
**工时**: 3-4h
|
||
|
||
---
|
||
|
||
## 第三层:可延后至首个补丁
|
||
|
||
| # | 问题 | 工时 |
|
||
|---|------|------|
|
||
| 13 | console.log 清理(105处→createLogger) | 2-3h |
|
||
| 14 | ChatStore 双源真相重构 | 2-4h |
|
||
| 15 | 33处内联样式→Tailwind | <1h |
|
||
| 16 | SaaS mixin `prototype: any` 类型约束 | <1h |
|
||
| 17 | serde_yaml 统一到 serde_yaml_bw | 1-2h |
|
||
| 18 | 32处 dead_code 审查清理 | 2-4h |
|
||
| 19 | webhook 废弃表删除迁移 | <30min |
|
||
| 20 | A2A feature gate 或移除 feature 定义 | <30min |
|
||
| 21 | dependency 内联声明→workspace 引用 | 1-2h |
|
||
| 22 | Kernel→Growth 隐式依赖显式化 | <30min |
|
||
| 23 | noUncheckedIndexedAccess 添加 | 2-4h |
|
||
| 24 | handStore/configStore duck-typing→discriminator | <1h |
|
||
|
||
---
|
||
|
||
## TRUTH.md 数值校准清单
|
||
|
||
| 指标 | 当前值 | 应更正为 | 验证命令 |
|
||
|------|--------|----------|----------|
|
||
| #[test] (crates) | 433 | 425 | `grep -rn '^\s*#\[test\]\s*$' crates/ --include="*.rs" \| wc -l` |
|
||
| #[tokio::test] (crates) | 368 | 309 | `grep -rn '^\s*#\[tokio::test\]' crates/ --include="*.rs" \| wc -l` |
|
||
| Zustand Store | 21 | 26 (含子目录) | `find desktop/src/store/ -name "*.ts" \| wc -l` |
|
||
| Admin V2 页面 | 15 | 17 | `ls admin-v2/src/pages/*.tsx \| wc -l` |
|
||
| Pipeline YAML | 17 | 18 | `find pipelines/ -name "*.yaml" \| wc -l` |
|
||
| Hands 启用 | 9 | 7 (6 HAND.toml + Reminder) | `ls hands/*.HAND.toml \| wc -l` + kernel registry |
|
||
|
||
---
|
||
|
||
## 实施计划
|
||
|
||
### Batch 1: 发布阻塞修复 (Day 1, 上午 + 下午)
|
||
|
||
按依赖顺序执行(总工时 ~6-9h,建议分上下午):
|
||
1. Pipeline 超时 + 内存泄漏 + Delay 上限(#2, #3)— 上午
|
||
2. Director 死锁修复(#1)— 上午,可并行
|
||
3. rate_limit_events Worker 实现(#5)— 下午
|
||
4. TRUTH.md + CLAUDE.md 数值校准(#4)— 下午
|
||
|
||
**验证**: `cargo test --workspace --exclude zclaw-saas` + `tsc --noEmit`
|
||
|
||
### Batch 2: 强烈建议修复 (Day 2)
|
||
|
||
5. tsconfig 修复(#6)
|
||
6. LlmConfig Debug 遮蔽(#7)
|
||
7. 关键 unwrap 修复(#8)
|
||
8. 静默吞错修复 — 关键集群(#9)
|
||
9. 缺失索引迁移(#10)
|
||
10. Config 验证(#11)
|
||
11. MCP Transport 锁合并(#12)
|
||
|
||
**验证**: `cargo test --workspace --exclude zclaw-saas` + `pnpm tsc --noEmit` + `pnpm vitest run`
|
||
|
||
### Batch 3: 补丁迭代 (Day 3+)
|
||
|
||
按优先级从高到低处理第三层 12 项。
|
||
|
||
---
|
||
|
||
## 关键文件列表
|
||
|
||
- `crates/zclaw-kernel/src/director.rs` — P0 Director 死锁
|
||
- `crates/zclaw-pipeline/src/executor.rs` — P0 Pipeline 内存泄漏 + 超时
|
||
- `crates/zclaw-saas/src/workers/cleanup_rate_limit.rs` — P0 Worker 空壳
|
||
- `docs/TRUTH.md` — P0 文档校准
|
||
- `desktop/tsconfig.json` — P1 类型排除
|
||
- `crates/zclaw-kernel/src/config.rs` — P1 Debug 泄露
|
||
- `crates/zclaw-saas/src/billing/handlers.rs` — P1 unwrap
|
||
- `desktop/src-tauri/src/classroom_commands/mod.rs` — P1 unwrap
|
||
- `crates/zclaw-protocols/src/mcp_transport.rs` — P1 响应错配
|
||
- `crates/zclaw-saas/src/config.rs` — P1 配置验证
|