移除不再使用的数据脱敏功能,包括: 1. 删除data_masking模块 2. 清理loop_runner中的unmask逻辑 3. 移除前端saas-relay-client.ts中的mask/unmask实现 4. 更新中间件层数从15层降为14层 5. 同步更新相关文档(CLAUDE.md、TRUTH.md、wiki等) 此次变更简化了系统架构,移除了不再需要的敏感数据处理逻辑。所有相关测试证据和截图已归档。
9.8 KiB
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 unwrapdesktop/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
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 >= 1max_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,建议分上下午):
- Pipeline 超时 + 内存泄漏 + Delay 上限(#2, #3)— 上午
- Director 死锁修复(#1)— 上午,可并行
- rate_limit_events Worker 实现(#5)— 下午
- TRUTH.md + CLAUDE.md 数值校准(#4)— 下午
验证: cargo test --workspace --exclude zclaw-saas + tsc --noEmit
Batch 2: 强烈建议修复 (Day 2)
- tsconfig 修复(#6)
- LlmConfig Debug 遮蔽(#7)
- 关键 unwrap 修复(#8)
- 静默吞错修复 — 关键集群(#9)
- 缺失索引迁移(#10)
- Config 验证(#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 unwrapdesktop/src-tauri/src/classroom_commands/mod.rs— P1 unwrapcrates/zclaw-protocols/src/mcp_transport.rs— P1 响应错配crates/zclaw-saas/src/config.rs— P1 配置验证