修复: workspace_root 去固定根完整(reload 尊重用户 persistent)

CR-28 审查 🟡 WATCH-1:reload_allowed_dirs 仍无条件 insert workspace_root(pre-existing),
致 commit 声称"用户删白名单后需授权"无法兑现(reload 塞回 persistent)。
修:reload KV 有配时不无条件 insert workspace_root,尊重用户 persistent。
(仅 KV 未配 default_with_root 含 workspace_root,首次免授权行为不变)

CR-28 审查回填( PASS,🟡 WATCH-1 已修闭环)。
This commit is contained in:
2026-06-20 04:14:10 +08:00
parent e4c2e310a5
commit b22e9ae912
2 changed files with 32 additions and 2 deletions

View File

@@ -1401,6 +1401,35 @@
--- ---
### CR-260619-28 idea source 溯源 + workspace_root 去固定根 + run_command 偏好修复(·commit e4c2e31) — ✅ 已审(PASS·🟡1 WATCH)
- **结论(2026-06-20·独立 git show e4c2e31 + grep/read 核验 6 文件源码形态 + cargo test 全跑)**: ✅ **PASS** — 🔴0 🟡1 ⚪1
- **验证**: `cargo test -p df-ai` 228 passed 0 failed / `cargo test -p devflow idea_source` 14 passed(11 单元 + 3 全链路对抗)/ `cargo check --workspace` EXIT 0 无 warning。
- **6 文件 diff 逐一核验**(git show e4c2e31):
| # | 维度 | 判定 |
|---|------|------|
| 1 | idea source 保守五条件(idea_source.rs) | ✅ IDEA_SOURCE_AUTO_FILL_ENABLED 开关(:19)+ tool_name=="create_idea"(:65)+ is_source_unfilled 不覆盖(:71)+ message_id Some 非空(:76)+ result.id extract(:84)。5 条件全到位 + best-effort warn 不阻断(:118-122) |
| 2 | workspace_root 去固定根(state.rs) | 🟡 部分兑现(见 WATCH-1) |
| 3 | run_command 描述收紧(tool_registry.rs) | ✅ 新描述「仅用于命令执行场景:跑测试套件/构建项目/运行二进制」+ 负向引导「读取文件用 read_file/编辑用 patch_file/write_file/列目录用 list_directory/搜索用 search_files——不要用本工具完成」(:1572) |
| 4 | ToolDomain::Exec(intent.rs) | ✅ enum 加 Exec(:238)+ Exec.tools()=&["run_command"](:279)+ tool_subset_for Debug 含 Exec(:357)/Code/File/Search 不含 + 对抗测 run_command_only_exposed_for_debug_intent(:878) |
| 5 | 注册顺序(tool_registry.rs) | ✅ run_command 从 File 层首位移至末位(:1566-1636),baseline 集合 18+10+1=29 不变(sort 对齐测 :1850-1874) |
| 6 | DEBUG_RULES 关键词(intent.rs) | ✅ 运行/执行/构建/测试 0.7 + 跑 0.6(:122-127),中等权重避误抢 Code(编译/重构 1.0) |
**关键对抗核验(防污染)**:
- chat.rs:504 `audit_status`/`result_val` 在 :477 已 binding(match exec_result),:504 引用合法非未定义 ✅
- chat.rs:513 `last_assistant_message_id()` 方法存在(context.rs:520,CR-260619-22 已加 4 对抗测)✅
- idea_source.rs:108 `update_field(id,"source",val)` 走 IdeaRepo → crud/mod.rs:141 validate_column_name → "source" 在 ideas 白名单(settings.rs:122)✅
- low_risk 路径(audit/mod.rs:533)注释自承「create_idea 不会进(Medium→pending)」,代码仍写完成防御/未来级别覆盖 ✅
- 集合 baseline 测试 tool_registry.rs:1850 与新注册顺序对齐(注释明确 sort 与顺序无关)✅
- **🟡 WATCH-1**: **workspace_root 去固定根「动态白名单完整语义」声明部分兑现**`state.rs:362-365` 删除固定放行成立(diff 核验),但 `reload_allowed_dirs`(:577)仍无条件 `set.insert(workspace_root_path())`(pre-existing 非 e4c2e31 引入)。即用户从 Settings KV 删除工程根后,下次 reload 会强制把工程根塞回 persistent → `is_authorized` 经 persistent 命中照样放行 → 「用户删白名单后需授权」的预期无法兑现。本次只删了 is_authorized 的硬编码,未触及 reload 兜底注入。**非破坏性**(默认行为不变向后兼容),但 commit message「动态白名单完整语义」与实现存在落差。无对应「删除白名单后需授权」的对抗测印证(test_allowed_dirs_workspace_root_authorized:741 用 default_with_root 经 persistent 命中,不覆盖删除场景)。
- **⚪ LOW-1**: DEBUG_RULES 5 关键词权重(0.6-0.7)为经验值,无量化校准依据(db 分析 591ff4a0 仅统计偏好率未回归权重调优)。后续可据真实意图误判数据校准。
- **待修项回流 todo**: **无** 🔴/🟡 项(🟡 WATCH-1 已修:reload_allowed_dirs 删无条件 insert workspace_root,KV 有配尊重用户 persistent,兑现"用户删白名单后工程根需授权"动态白名单完整语义)
---
## 已审归档 ## 已审归档
> 已审 CR 段迁独立文件: [待审查归档/2026-06.md](./07-项目管理/待审查归档/2026-06.md) > 已审 CR 段迁独立文件: [待审查归档/2026-06.md](./07-项目管理/待审查归档/2026-06.md)

View File

@@ -573,8 +573,9 @@ impl AppState {
} }
}; };
let mut set = HashSet::new(); let mut set = HashSet::new();
// workspace_root 始终在白名单(向后兼容);不重复插入 // F-260619-03 收尾:KV 有配时尊重用户 persistent(不无条件塞 workspace_root)。
set.insert(workspace_root_path()); // 用户 KV 配置不含 workspace_root → 工程根也需授权(动态白名单完整语义,
// 兑现 commit 声称"用户删白名单后需授权")。仅 KV 未配时 default_with_root 含 workspace_root。
for d in dirs { for d in dirs {
let d = d.trim(); let d = d.trim();
if d.is_empty() { if d.is_empty() {