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
混合矩阵式审计:10 个功能模块 × 五维检查清单 - 项目整体健康度: 76/100 - 2 个 P0 (M4 双数据库 + 反思引擎 LLM 未接入) - 15 个 P1 (跨 M2/M3/M4/M5/M6/M7/M11) - 三类断链模式: 写了没接/接了不对/双实现未统一 - 三阶段修复路线图: P0(2-3天) → P1(5-7天) → P2(5-7天)
171 lines
9.6 KiB
Markdown
171 lines
9.6 KiB
Markdown
# 模块 M3 Hands 自主能力 审计报告
|
||
|
||
> **审计版本**: V12
|
||
> **审计日期**: 2026-04-04
|
||
> **审计范围**: 11 个自主能力包触发/审批/执行/回调完整流程
|
||
|
||
---
|
||
|
||
## 1. 模块概况
|
||
|
||
### 功能描述
|
||
9 个已实现 Hand(Browser/Researcher/Collector/Clip/Twitter/Whiteboard/Slideshow/Speech/Quiz),含触发、审批、执行、事件回调全流程。
|
||
|
||
### 涉及文件清单
|
||
|
||
**前端**
|
||
- Store: `desktop/src/store/handStore.ts`, `desktop/src/store/browserHandStore.ts`
|
||
- Client: `desktop/src/lib/kernel-hands.ts`, `desktop/src/lib/browser-client.ts`
|
||
- 自主管理: `desktop/src/lib/autonomy-manager.ts`
|
||
- UI: `desktop/src/components/Automation/` (ApprovalQueue, AutomationPanel, ExecutionResult 等)
|
||
|
||
**后端 (Rust)**
|
||
- Tauri 命令: `desktop/src-tauri/src/kernel_commands/hand.rs`, `approval.rs`
|
||
- Kernel: `crates/zclaw-kernel/src/kernel/hands.rs`, `crates/zclaw-kernel/src/kernel/approvals.rs`
|
||
- Registry: `crates/zclaw-hands/src/registry.rs`
|
||
- Hand 实现: `crates/zclaw-hands/src/hands/` (9 个 .rs 文件)
|
||
- 配置: `hands/*.HAND.toml` (9 个)
|
||
|
||
### 调用链路图
|
||
|
||
```
|
||
用户触发 Hand
|
||
→ AutomationPanel.triggerHand(id, params)
|
||
→ handStore.triggerHand()
|
||
→ canAutoExecute('hand_trigger', 5) [前端自主性检查]
|
||
→ client.triggerHand(name, params, autonomyLevel)
|
||
→ KernelClient.triggerHand() → invoke('hand_execute', { id, input, autonomyLevel })
|
||
→ Rust hand_execute:
|
||
├─ supervised 模式 → 创建 ApprovalEntry → 返回 pending_approval
|
||
├─ needs_approval + 非 autonomous → 创建 ApprovalEntry
|
||
└─ autonomous 或无需审批 → kernel.execute_hand()
|
||
→ HandRegistry.execute() → Hand::execute()
|
||
→ 创建 HandRun (Pending→Running→Completed/Failed)
|
||
→ emit("hand-execution-complete")
|
||
|
||
审批流程:
|
||
ApprovalQueue → handStore.respondToApproval()
|
||
→ invoke('approval_respond', { id, approved, reason })
|
||
→ kernel.respond_to_approval()
|
||
→ tokio::spawn 异步执行 Hand + 轮询完成
|
||
→ emit("hand-execution-complete")
|
||
|
||
前端事件接收:
|
||
kernel-hands.ts onHandExecutionComplete → listen("hand-execution-complete")
|
||
→ [问题: 前端未注册全局监听]
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 五维检查结果
|
||
|
||
### 2.1 链路完整性
|
||
|
||
| 链路 | 起点 | 终点 | 状态 | 备注 |
|
||
|------|------|------|------|------|
|
||
| Hand 列举 | AutomationPanel | Registry.list() | ✅ 连通 | |
|
||
| Hand 触发(直接执行) | handStore | Hand::execute() | ⚠️ **run_id 丢失** | hand.rs:184 丢弃 _run_id |
|
||
| Hand 触发(需审批) | handStore | ApprovalEntry | ✅ 连通 | |
|
||
| 审批确认 | ApprovalQueue | Hand::execute() | ✅ 连通 | 两条重复路径 |
|
||
| hand-execution-complete 事件 | Rust emit | 前端 listen | ⚠️ **无人接收** | onHandExecutionComplete 未被调用 |
|
||
| Browser Hand (Rust) | BrowserHand::execute() | 浏览器操作 | ❌ **断裂** | 只返回结构化指令不执行 |
|
||
| Browser Hand (前端) | browserHandStore | browser-client → Rust browser_* 命令 | ✅ 连通 | 但绕过审批流程 |
|
||
| Hand 取消 | handStore | cancel_flag AtomicBool | ✅ 连通 | |
|
||
| Hand 运行状态查询 | handStore | Rust hand_run_status | ✅ 连通 | |
|
||
|
||
### 2.2 参数/类型一致性
|
||
|
||
| 接口 | 前端参数 | 后端参数 | 一致性 | 备注 |
|
||
|------|---------|---------|--------|------|
|
||
| hand_execute | `{ id, input, autonomyLevel }` | `id, input, autonomy_level` | ✅ | camelCase 正确转换 |
|
||
| hand_approve | `{ handName, runId, approved, reason }` | `hand_name, run_id, approved, reason` | ✅ | |
|
||
| approval_respond | `{ id, approved, reason }` | `id, approved, reason` | ✅ | |
|
||
| hand_execute 返回值 | 期望 `{ instance_id, status }` | 实际 `{ success, output, error, durationMs }` | ❌ **不匹配** | 前端拿不到 run_id |
|
||
| TOML permissions/rate_limit | 定义了但未使用 | HandConfig 只有基础字段 | ❌ **配置未生效** | |
|
||
|
||
### 2.3 边界与错误处理
|
||
|
||
| 场景 | 预期行为 | 实际行为 | 级别 |
|
||
|------|---------|---------|------|
|
||
| 触发不存在的 Hand | 返回错误 | ✅ ZclawError::NotFound | P4 正确 |
|
||
| 并发触发同一 Hand | 限流/拒绝 | ❌ 无保护,可无限并发 | **P1** |
|
||
| Hand 执行超时 | 超时终止 | ❌ `timeout_secs` 定义但未使用 | **P1** |
|
||
| 审批不响应 | 超时清理 | ❌ 永不过期,pending 无限积累 | P2 |
|
||
| Hand 执行失败 | 错误传播到 UI | ✅ 错误传播链路完整 | P4 正确 |
|
||
| max_concurrent 限制 | 限制并发数 | ❌ TOML 定义但未实现 | P2 |
|
||
| Clip Hand 路径含单引号 | 正常执行 | ⚠️ FFmpeg concat 文件解析可能异常 | P3 |
|
||
|
||
### 2.4 状态管理
|
||
|
||
| Store/组件 | 状态机完整性 | 持久化 | 竞态风险 |
|
||
|-----------|------------|--------|---------|
|
||
| handStore | ✅ idle/running/needs_approval/error/unavailable/setup_needed | ❌ 无持久化 | ⚠️ triggerHand 后依赖异步 loadHands 更新状态 |
|
||
| browserHandStore | ✅ sessions/execution/logs/templates | ❌ 无持久化 | ⚠️ 独立于 handStore,绕过审批 |
|
||
| autonomy-manager | ✅ 三级自主+三级风险 | ✅ localStorage | ❌ 仅前端,后端无强制 |
|
||
|
||
### 2.5 安全与资源
|
||
|
||
| 检查项 | 状态 | 说明 |
|
||
|--------|------|------|
|
||
| 审批安全(跨 Hand 攻击防护) | ✅ | entry.hand_id == hand_name 校验 |
|
||
| Approval ID 不可预测 | ✅ | UUID v4 |
|
||
| Browser Hand 绕过审批 | ❌ **P1** | browserHandStore 完全绕过 autonomy-manager |
|
||
| TOML requires_approval 形同虚设 | ❌ **P1** | browserHandStore 不走审批流程 |
|
||
| 审批内存不释放 | ⚠️ P2 | Vec<ApprovalEntry> 无限增长 |
|
||
| Clip Hand 命令注入防护 | ✅ | 使用 Command::new + .args() 非 shell |
|
||
|
||
---
|
||
|
||
## 3. 问题清单
|
||
|
||
| ID | 描述 | 文件:行号 | 级别 | 修复建议 | 验证方法 |
|
||
|----|------|----------|------|---------|---------|
|
||
| M3-01 | **hand_execute 丢弃 run_id** — 前端拿不到执行 ID,无法追踪运行状态 | `hand.rs:184` | **P1** | 将 HandRunId 包含在返回结果中 | triggerHand 后检查返回值含 runId |
|
||
| M3-02 | **Browser Hand 双路径断裂** — Rust execute() 只返回结构化指令不执行实际操作 | `browser.rs:191-343` | **P1** | 统一路径:要么 Rust 端执行操作,要么移除 Rust BrowserHand | 通过 handStore 触发 browser 验证 |
|
||
| M3-03 | **browserHandStore 绕过审批** — 无视 TOML requires_approval = true | `browserHandStore.ts:222-339` | **P1** | browserHandStore 操作前检查 autonomy-manager | 在 autonomous=false 下执行浏览器操作 |
|
||
| M3-04 | **max_concurrent 未实现** — TOML 定义但运行时无检查 | `kernel/hands.rs` | **P1** | 在 execute_hand 中添加并发计数检查 | 并发触发同一 Hand |
|
||
| M3-05 | **timeout_secs 未实现** — Hand 可无限挂起 | `hand.rs:47` | **P1** | 在 execute 中使用 tokio::time::timeout 包装 | 启动长时间 Hand 验证超时 |
|
||
| M3-06 | hand_execute 返回值类型不匹配 | `kernel-hands.ts:94` vs Rust `HandResult` | **P2** | 统一返回类型定义 | 检查 triggerHand 返回值 |
|
||
| M3-07 | hand-execution-complete 事件前端无人监听 | `kernel-hands.ts:195` | **P2** | 应用初始化时注册全局监听 | 审批执行完成后检查 UI 更新 |
|
||
| M3-08 | 审批条目永不过期,内存不释放 | `approvals.rs:16-19` | **P2** | 添加 expires_at + 定期清理 | 检查长期运行后的 pending_approvals 大小 |
|
||
| M3-09 | 重复审批确认路径(hand_approve vs approval_respond) | `hand.rs:196-295` vs `approval.rs:54-142` | **P2** | 统一为单一审批路径 | 检查两路径是否行为一致 |
|
||
| M3-10 | tool_count/metric_count 硬编码为 0 | `hand.rs:82-83` | **P2** | 从 Hand 实际能力中计算 | 检查 hand_list 返回值 |
|
||
| M3-11 | TOML permissions/rate_limit/audit 配置未被读取 | `hands/*.HAND.toml` vs `hand.rs:10-32` | **P3** | 扩展 HandConfig 或在运行时解析 | 修改 TOML 验证行为无变化 |
|
||
| M3-12 | hand_trigger 在 autonomy-manager 中永远不自动允许 | `autonomy-manager.ts:268` | **P3** | 修正映射逻辑 | 设为 autonomous 后触发 Hand |
|
||
| M3-13 | Clip Hand concat 文件路径单引号未转义 | `clip.rs:448` | **P3** | 转义路径中的单引号 | 使用含单引号的路径执行 concat |
|
||
|
||
---
|
||
|
||
## 4. 改进建议
|
||
|
||
### 短期修复(按优先级)
|
||
|
||
1. **[P1]** 修复 `hand_execute` 返回 `run_id`:在 HandResult 中添加 `run_id` 字段
|
||
2. **[P1]** 统一 Browser Hand 路径:移除 Rust BrowserHand 的假执行,让 handStore 走 browserHandStore
|
||
3. **[P1]** browserHandStore 集成审批流程:在 executeTemplate 前检查 autonomy-manager
|
||
4. **[P1]** 实现 `max_concurrent` 并发限制
|
||
5. **[P1]** 实现 `timeout_secs` 超时保护
|
||
|
||
### 长期架构建议
|
||
|
||
- 注册 `hand-execution-complete` 全局监听器到 handStore
|
||
- 统一审批路径(移除重复的 hand_approve / approval_respond)
|
||
- 添加审批 TTL 和自动清理
|
||
- 扩展 HandConfig 解析 TOML 中的权限/限流/审计配置
|
||
|
||
---
|
||
|
||
## 5. 健康度评分
|
||
|
||
| 维度 | 评分 | 说明 |
|
||
|------|------|------|
|
||
| 链路完整性 | **55/100** | Browser Hand 断裂、事件无人接收、run_id 丢失 |
|
||
| 参数一致性 | **70/100** | invoke 参数匹配但返回值不匹配、TOML 配置未生效 |
|
||
| 边界处理 | **50/100** | 无并发限制、无超时、审批不过期 |
|
||
| 状态管理 | **60/100** | 基本状态机存在但 browserHandStore 独立运作 |
|
||
| 安全资源 | **55/100** | Browser Hand 绕过审批是核心安全问题 |
|
||
|
||
**综合健康度: 58/100**
|
||
|
||
5 个 P1 级问题集中在此模块(run_id 丢失、Browser 断裂、绕过审批、无并发限制、无超时)。修复 P1 后预计可提升至 75+。
|