# dsh-hub 质量审查报告(2026-09-01) > 审查对象:`dev-v2` 分支(HEAD 在 0.1.3 之后,含 0.1.0 正式版以来的全部增量)。 > 审查方式:三轮 × 多角度并行子代理(架构/契约/数据 → 安全/性能/测试 → UI/UX/文档/构建发布),共 9 个审查面。 > 结论:**整体达到可发布质量(T2 候选),无 P0 阻断项;存在 3 个 P0 级安全/隔离隐患需在下一版本优先修复。** --- ## 一、综合评分 | 维度 | 评分 | 一句话结论 | |---|---|---| | 架构与分层 | 7.4 | SPT 分层严格,但 Config 三真相漂移、SlotMap 残留 | | 契约与类型 | 7.4 | strict 零错、错误码统一,但静态资源漏 host-guard | | 数据与状态 | 6.8 | 核心原子写闭环,但插件直写 + 单实例未隔离 | | 安全 | 7.2 | 三件套纵深成体系,但路径校验停留在字符串前缀 | | 性能 | 7.6 | 泄漏治理成体系,但大列表无虚拟化、包体 1MB | | 测试与质量 | 7.8 | #91 并发坑根治,但核心 Helper 零单测、无 git hooks | | UI/UX | 8.0 | 卡片还原度近乎像素级,但标签栏浅色层次失效 | | 文档 | 7.5 | 踩坑/打包记录详尽,但 FUNCTIONS.md 版本号陈旧 | | 构建发布 | 8.5 | 四道防线闭环,但 verify-release 文档-代码不一致 | | **综合** | **7.6** | 补齐 P0/P1 后可至 8.5+ | --- ## 二、P0 级问题(安全 / 数据隔离,需优先修复) ### P0-1 工作区 list/git 任意绝对路径枚举 - **位置**:`src/server/workspace-api.ts:57,234,254` - **问题**:`queryPath` 仅校验 `isAbsolute`,未约束 `isWithinRoot`。`GET /api/dsh-hub/workspace/list?path=C:\Windows` 与 `/git` 在仅 `rejectIfBadHost` 保护下可被同源脚本枚举全盘文件与 git 状态。 - **建议**:`list/git` 复用 `open` 的 `withinRoot` 防线,或加 `verifyToken`。 ### P0-2 单实例未按 DSH_HOME 命名空间隔离 - **位置**:`src-tauri/src/managers/single_instance.rs:13` - **问题**:`tauri_plugin_single_instance` 全局互斥量未按 `DSH_HOME` 命名。隔离 Home 无法并行启动第二壳进程;`allowMultipleInstances=true` 对 Tauri 壳完全无效(被插件硬拦)。 - **建议**:以 `DSH_HOME` 哈希为插件 `identifier`,或条件注册插件。 ### P0-3 并发写 Lost Update(无进程内互斥) - **位置**:`src/services/config-store.ts:92-109`、`src/server/pins-api.ts:71-82`、`src/services/terminal-prefs.ts:64-82` - **问题**:三处原子写正确但无进程内互斥,两并发 POST 交错 `read→merge→write` 构成 Lost Update(后写覆盖前写非交集字段)。 - **建议**:加 `async-mutex` 或序列化队列。 --- ## 三、P1 级问题(重要,按主题归类) ### 安全一致性 1. **静态资源路由漏 host-guard**:`backgrounds-api.ts:42`、`icons-api.ts:40`、`sounds-api.ts:37` 三条 `kind:'prefix'` 路由未调 `rejectIfBadHost`,与项目"所有自有路由必过 host-guard"范式不一致。 2. **isWithinRoot 未 realpath**:`workspace-api.ts:97-106` 仅字符串前缀,符号链接/`..` 可绕过。 3. **csp:null 全局禁用 CSP**:`tauri.conf.json:20-23`,建议至少显式 `default-src 'self' http://127.0.0.1:*`。 4. **状态变更路由无 Token**:`config-api.ts:44`、`pins-api.ts:111`、`permission-guard/lib/index.js:312` 仅 Host+Origin,同源脚本无需 Token 即可持久化提权。 5. **open_workspace_path 任意路径**:`window_ops.rs:104-118` 经 invoke 直达 explorer,无白名单/域校验。 ### 数据持久化 6. **插件直写非原子**:`dsh-usage-stats/lib/index.js`(3 处 writeFile)、`dsh-permission-guard/lib/index.js:119,195`、`dsh-project-memory/lib/index.js:135-144`、`dsh-findings-ledger/lib/index.js:82,112,149` 均直写无 tmp+rename。 7. **state.rs / current.ico 非原子**:`state.rs:95-102` 直写 window-state.json;`icon.rs:287-299` 直拷 current.ico,崩溃产生半截文件。 8. **config 字段无白名单**:`config-api.ts:79-85` 的 skin/background/desktopIcon 仅长度校验,无 `^[a-z0-9-]{1,64}$` 白名单。 ### 契约与类型 9. **SlotMap 残留 + 分散**:`index.ts:54-61` 残留已废弃的 `settings.plugin.item` 声明;`conversation.input.model` 声明分散在 `model-select.tsx`。 10. **Config 三真相漂移**:`plugin-config.ts` vs `src/index.ts Config` vs `shell-config.ts` 三处字段不一致(如 `tray` 字段在 cordis.patch.yml 声明但 Config 未定义)。 11. **cordis.patch.yml tray 字段未定义**:`cordis.patch.yml:22` 的 `tray: true` 不在 Config schema,被 schemastery 静默 strip。 ### 性能 12. **pin-conversations 无虚拟化**:`pin-conversations.ts:375-440` 对百级会话全量 `getComputedStyle` 扫描,单次 sync O(rows×descendants)。 13. **pty-store 无 dispose**:`pty-store.ts:60,182-225` 的 EventSource/写队列模块级单例无 `disposeAll`,HMR 后旧连接常驻。 14. **lib/client.js 1MB 过大**:`skins.ts`(53KB)+ `@xterm/xterm` 打包进单闭包,无 code-split。 ### 测试与 CI 15. **核心 Helper/Manager 零单测**:`boot_theme.rs`、`quit.rs`、`icon.rs`、`window.rs`、`window_ops.rs`、`tray.rs`、`single_instance.rs`、`winutil.rs` 共 8 文件无 `#[cfg(test)]`。 16. **无 git hooks / CI 只覆盖 Rust**:`.github/workflows/rust.yml` 未跑 `npm run build`、`verify-release.mjs`;无 pre-commit/pre-push。 ### UI/UX 17. **标签栏浅色层次失效**:`SessionTabs.tsx:78,97` 的 layer-3 lift 在默认皮肤+浅色下(layer-1==layer-3==白)完全不可见。 ### 文档 18. **FUNCTIONS.md 版本号陈旧**:头部仍写 `0.1.0`,0.1.2/0.1.3 的设置页迁移与卡片风格变更未同步。 19. **README 设置卡描述陈旧**:仍写"设置→插件页",与一级设置页实际不符。 --- ## 四、P2 级问题(建议,摘要) - 权限 chip 裸 token 名写错(`--dsw-alias-state-warn` 应为 `-primary` 后缀) - 右键菜单与官方 Menu 几何偏差(字号 13 vs 14、圆角 10 vs 12、hover token 用错) - session-paths 泄露 homeDir;token 注入 HTML 用字面 `` 匹配脆弱 - 长函数(lib.rs run 266 行、node.rs 5 个函数超 40 行)、魔法数未抽常量 - lib/bridge 空目录残留、lib/client 冗余产物(tsc 副作用,无人消费) - verify-release P1 门禁与 BUILD.md 描述不一致(bundles 检查是 INFO 非 FAIL) - 打包记录 0.1.1 日期错误(应为 2026-08-31) --- ## 五、优点(保留) 1. **SPT 分层严格**:models 零副作用、services/server/controllers 职责分离,符合 AGENTS.md。 2. **安全三件套成体系**:host-guard(Host/Origin 双闸)+ token(256bit CSPRNG + timingSafeEqual + 双通道)+ 原子持久化(tmp+rename)。 3. **错误码统一**:`{ ok:false, error }` 固定码收敛,不泄 `String(e)`。 4. **#91 并发坑根治**:`ENV_LOCK` 静态 Mutex 串行化 + 中毒恢复,教科书级修复。 5. **fail-closed 契约可验证**:`combine_channels` 纯函数化 + 5 单测锁定"单通道失败不放行"。 6. **泄漏治理成体系**:前端三大 Portal 均 ctx.effect 托管,MutationObserver/EventSource 对称清理。 7. **卡片还原度近乎像素级**:settings-card 与官方 PluginCard 逐项一致。 8. **Splash 皮肤跟随链路完整**:boot_theme.rs → skin-colors.json → __MG_BOOT_THEME → shell-init.js 内联应用,15 皮肤无漂移。 9. **构建发布四道防线**:工具链检测零硬编码 + 完整性预检 + host 依赖守卫 + SHA256 校验,踩坑记录驱动。 10. **文档深度**:98 条踩坑 + 15 版本打包记录全链可追溯,PUBLISH.md 沉淀发布纪律。 --- ## 六、结论 dsh-hub 已具备 **T2 候选发布**条件,工程成熟度在同类 Tauri 壳中属上乘。核心风险集中在 **3 个 P0**(工作区路径枚举、单实例隔离、并发 Lost Update)与 **安全一致性 P1**(静态资源 host-guard、realpath、csp、状态变更 token)。建议下一版本(0.1.4)优先修复 P0 + 安全 P1,再随版本迭代补齐性能(虚拟化/code-split)与测试(单测/CI)缺口。详细修复清单见《修改优化意见报告》。