fix(desktop): trust bundled ApeMind workflows by title+description fallback#22
Merged
Merged
Conversation
…ches PR #20 pre-computed SHA-256 over `JSON.stringify(yaml.parse(file))` and wrote `userData/recipe_hashes/<hash>.hash` for each bundled YAML. Field inspection on 3F (冯诺伊曼) confirms three `.hash` files exist for the three bundled recipes, but earayu2 still sees "⚠️ 新配方警告" when opening any of them. Root cause: the `recipe` object passed to the `has-accepted-recipe-before` IPC at runtime comes from goose-server (Rust). Its `JSON.stringify` shape (field order, `null` for absent optional fields, extra metadata) differs from a naive `JSON.stringify(yaml.parse(file))`, so the SHA-256 hashes do not match and the existing pre-trusted file is never found. Fix: add a second match path that does not depend on byte-exact JSON serialization: 1. `seedDefaultRecipes` also writes `userData/bundled-recipe-titles.json` — an array of the `title` fields parsed from each bundled YAML. 2. `recipeHash.ts` `has-accepted-recipe-before` handler: when the hash lookup misses with ENOENT, fall back to checking whether `recipe.title` is in the bundled-titles list. If yes, return true. Effect: bundled recipes are trusted on first open even if the runtime recipe shape differs from yaml.parse output. Existing hash-based trust still works for user-recorded acceptances (e.g. user clicks "Trust and Execute" on a non-bundled recipe). 5-cat compliance: still category 3 (默认配置) + category 4 (UI behavior). The IPC handler change is localized to one file; no change to goose-rs / RecipeWarningModal / recipe loading logic. Signed-off-by: earayu <earayu@163.com>
…ion risk @梅西 raised that pure title match could false-positive on user-imported recipes with the same title. Tighten by requiring both `title` and `description` to match the bundled entry. Both fields are stable identifiers of bundled ApeMind workflows (authored by 梅西, unlikely to collide with random user imports). User edits that change description still see the warning, which is the intended security behavior for modified recipes. Signed-off-by: earayu <earayu@163.com>
Merged
This was referenced May 28, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
PR #20 用 SHA-256(⚠️ 新配方警告"。
JSON.stringify(yaml.parse(file))) 预先种 hash 文件到userData/recipe_hashes/,希望 bundled ApeMind workflow 首次打开时不弹"问题
@earayu2 反馈:本地最新构建上点击 bundled workflow 仍然弹警告(#鹅岛 msg e8cb0f3b)。
@冯诺伊曼 在 3F 本机查
~/Library/Application Support/ApeMind Agent/recipe_hashes/确认有 3 个.hash文件,说明seedDefaultRecipes跑过了 hash 文件也写好了。但弹窗仍然出现,说明 IPC handlerhas-accepted-recipe-before收到的recipe对象 hash 与种入时的 hash 不一致。根因
has-accepted-recipe-beforeIPC 处理函数收到的 recipe 对象,是 goose-server(Rust 后端)通过 REST 返回给 Desktop 的。Rust 侧JSON.stringify后的字节序列(字段顺序、null占位、可能的额外元数据)跟 Node 端直接JSON.stringify(yaml.parse(content))不一致,所以 SHA-256 不相等,hash 文件存在但匹配不上。方案
不去逆向 Rust 序列化(耦合上游、rebase 成本高),改成在 hash 不命中时按 title + description 双字段做兜底匹配:
seedDefaultRecipes(main.ts):除了写.hash文件,再写一个userData/bundled-recipe-titles.json,内容是[{ title, description }, ...],列出当前 bundled 的所有 workflow。recipeHash.tshas-accepted-recipe-before处理:原有 hash 命中逻辑保留;当 ENOENT(没匹配的 hash 文件)时调用新的isBundledRecipeByTitleAndDescription,从bundled-recipe-titles.json读列表,看运行时 recipe 的title+description是否完全在列表里。两个字段都匹配才返回true。为什么 title + description 双字段:
影响
验收
userData/bundled-recipe-titles.json存在且内容为 3 条{ title, description }不解决什么
JSON.stringify输出(不动 goose-rs)RecipeWarningModal弹窗组件本身