50 lines
3.1 KiB
Markdown
50 lines
3.1 KiB
Markdown
# 7-28 [done][bug] markdown_edit 未强制 selection 允许块边界
|
||||
|
|
|
|||
|
|
> 发现时间:2026-05-18
|
|||
|
|
>
|
|||
|
|
> 状态:`[done]`
|
|||
|
|
>
|
|||
|
|
> 关联主线:`07-ai`
|
|||
|
|
|
|||
|
|
## 1. 问题定义
|
|||
|
|
|
|||
|
|
页面 AI context 已经可以携带 `allowedTargetBlockIds`,用于表达 `scope=selection` 时本次 run 允许修改的块集合。但 `mnote.doc.markdown_edit` 当前只按文本 search/replace 写回,不检查最终变化的 block 是否落在允许集合内。
|
|||
|
|
|
|||
|
|
如果 fast workflow 或未来调用者传入了过宽的 `pageText`,模型返回了选区外文本的 search/replace,服务端仍可能写入选区外块。
|
|||
|
|
|
|||
|
|
## 2. 证据
|
|||
|
|
|
|||
|
|
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:91) fast workflow 调用 `mnote.doc.markdown_edit`。
|
|||
|
|
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:299) 读取了 `allowedTargetBlockIds`,但未传给写工具或参与校验。
|
|||
|
|
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2860) 工具指导要求 `scope=selection` 时只能修改 `allowedTargetBlockIds` 内的块。
|
|||
|
|
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:1220) `markdown_edit` 生成 `changedBlocks` 后直接 dry-run 或写回,没有 selection 范围校验。
|
|||
|
|
|
|||
|
|
## 3. 影响
|
|||
|
|
|
|||
|
|
- 页面 AI 对选中文本执行编辑时,服务端缺少最终兜底边界。
|
|||
|
|
- 上下文构造或模型输出一旦漂移,选区外块可能被写入。
|
|||
|
|
- 与 `mnote.block.*` 已有 `allowedTargetBlockIds` / blockId 前置条件相比,`markdown_edit` 的写入安全边界较弱。
|
|||
|
|
|
|||
|
|
## 4. 修复
|
|||
|
|
|
|||
|
|
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:91) fast workflow 将 `aiContext.allowedTargetBlockIds` 透传给 `mnote.doc.markdown_edit`。
|
|||
|
|
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:855) `mnote.doc.markdown_edit` 在生成 `changedBlocks` 后,如果存在 `allowedTargetBlockIds` / `selectedBlockIds`:
|
|||
|
|
- 任何带 `blockId` 的变更必须属于允许集合。
|
|||
|
|
- 无 `blockId` 的 insert/full_content 变更在 selection scope 下拒绝,避免无法归属的选区外写入。
|
|||
|
|
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs:2308) 增加 route 测试:`allowedTargetBlockIds=["p_2"]` 时替换 `p_1` 必须返回 `mnote_markdown_edit_target_out_of_scope`。
|
|||
|
|
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:742) 增加 fast workflow 测试:模型输出修改 `p_1`,而 selection 只允许 `p_2`,必须被服务端拒绝。
|
|||
|
|
|
|||
|
|
## 5. 验证
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web markdown_edit_rejects_selection_out_of_scope -- --nocapture
|
|||
|
|
cargo test --manifest-path rust/Cargo.toml -p mnote-web block_edit_workflow -- --nocapture
|
|||
|
|
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
结果:
|
|||
|
|
|
|||
|
|
- `hermes_tools_markdown_edit_rejects_selection_out_of_scope`:`1 passed`。
|
|||
|
|
- `block_edit_workflow_forwards_allowed_target_blocks_to_markdown_edit`:`1 passed`。
|
|||
|
|
- Rust workspace format check 通过。
|