Skip to content

feat(desktop): pre-trust bundled ApeMind recipes + let bundled apemind extension be editable#20

Merged
earayu merged 2 commits into
mainfrom
chore/seed-bundled-recipe-hashes
May 25, 2026
Merged

feat(desktop): pre-trust bundled ApeMind recipes + let bundled apemind extension be editable#20
earayu merged 2 commits into
mainfrom
chore/seed-bundled-recipe-hashes

Conversation

@earayu
Copy link
Copy Markdown
Collaborator

@earayu earayu commented May 25, 2026

现状

PR #19 把 ApeMind MCP 占位 + Recipe seeding 接到分发层后,3F 本机验证(@冯诺伊曼 msg c04c0ede)确认:

  • 3 个 ApeMind 工作流首启自动复制到 ~/.config/goose/recipes/
  • ApeMind 扩展卡片显示在扩展列表里、disabled、URI + Authorization Bearer 占位都写进了 config
  • 启动不报错

但 @earayu2 又给了两个 UX 反馈:

  1. "新工作流警告"弹窗(msg 924622a8):用户点击我们 bundle 的 ApeMind 工作流时,goose 会弹一个 "⚠️ New Workflow Warning",因为 userData/recipe_hashes/ 里没有这个 recipe 的 hash 记录 —— goose 默认认为这是用户没见过的"新工作流"。
  2. bundled apemind 扩展不能编辑(msg e61bdbb4):ExtensionItem.tsx 的 gating 规则把所有 bundled: true 扩展视为不可编辑(只有开关、没有齿轮按钮)。但 apemind 的 URL + token 是占位值,用户必须能编辑才能启用。

现象

  • 用户点击 apemind-knowledge-qa / apemind-deep-research / apemind-table-summary 工作流 → 弹"新工作流警告" → 体验差(明明是我们 ship 的工作流为啥还要警告)
  • 用户去扩展页想配 ApeMind 的真实 URL/token → 找不到编辑按钮,卡住

影响

  • 信任问题:用户对自家产品的 bundled workflow 还要被警告,感觉不专业
  • 阻断 UX:扩展无法编辑 = 用户无法启用 = bundled MCP 形同摆设

期望结果

两个最小改动:

  1. seedDefaultRecipes() 增加预信任 hashui/desktop/src/main.ts):

    • 对每个 bundled YAML,parse + JSON.stringify(parsed) + SHA-256
    • app.getPath('userData')/recipe_hashes/<hash>.hash 写时间戳
    • 这正是 ipcMain.handle('has-accepted-recipe-before', ...) 用的检查方式 —— 写文件后 goose 视为"用户已接受",不弹警告
    • 失败兜底:YAML parse 失败 / hash 不匹配 / 写文件失败 → log warn,不阻塞启动;最坏情况只是警告还是弹(与现状一致)
  2. ExtensionItem.tsx 给 apemind 开后门

    • 现有 gating:extension.type === 'builtin' || ('bundled' in extension && extension.bundled) → 不可编辑
    • 新增 carve-out:extension.name === 'apemind' → 即使 bundled 也允许编辑
    • 1 行条件扩展,rebase 友好

不解决什么

  • 不改 recipeHash.ts IPC handler 本身(保持上游 hash 检查 + record 逻辑不变)
  • 不改 RecipeWarningModal.tsx 弹窗组件(用户 trust 别的 recipe 时仍正常显示警告)
  • 不通用化 allow_configure 字段到 BundledExtension JSON schema(PoC 阶段就 apemind 一个,特例够用;通用化等多扩展时再做)
  • 不动 goose-rs 核心 recipe runner / extension runtime

验证

  • 静态:diff 只动 2 个文件
  • 计划:merge 后 @冯诺伊曼 3F 重新 package 验证:
    1. ~/.config/goose/recipes/ + userData/recipe_hashes/ 等用户状态
    2. pnpm -C ui/desktop run package + 打开新 app
    3. 工作流页点 apemind-knowledge-qa 等任一 ApeMind 工作流 → 应不弹"新工作流警告"
    4. 扩展页 ApeMind 卡片 → 应显示齿轮编辑按钮 → 点击可改 URL + token
    5. 改完启用 ApeMind → 应能连到真实 endpoint

关联

earayu added 2 commits May 25, 2026 13:23
…ning

When the user opens a bundled ApeMind workflow, goose currently shows the
"⚠️ New Workflow Warning" dialog because the recipe hash is not in the
user's `userData/recipe_hashes/` directory. For workflows we ship with
the app this is wrong — the user has already trusted them by installing
the distribution.

Extend `seedDefaultRecipes()` (added in earlier PR #19) to also:
- Parse each bundled YAML
- Compute SHA-256 over `JSON.stringify(parsed)` — same algorithm goose's
  Electron-side `recipeHash.ts` uses for the `has-accepted-recipe-before`
  IPC check
- Write a `<hash>.hash` file in `userData/recipe_hashes/` if absent

Effect: the bundled-recipe warning is suppressed on first open.

Failure mode (best-effort): if YAML parse fails or hash shape mismatches
goose's runtime serialization, the worst case is the warning shows once
and the user clicks "Trust and Execute" — same as the prior behavior.
Failure logs a warning, does not block startup.

5-cat compliance: still category 3 (默认配置) + 5 (打包分发). All in the
Electron main process; zero changes to goose-rs core or the warning
dialog logic.

Signed-off-by: earayu <earayu@163.com>
The `apemind` entry in bundled-extensions.json ships with placeholder URL
and Authorization Bearer token (per earayu2's #鹅岛 directive). With
`bundled: true` the existing ExtensionItem.tsx gating hides the edit
(gear) button entirely, so the user has no way to swap the placeholder
values from the UI.

Surgical carve-out: keep all other bundled / builtin extensions
read-only (preserve upstream security model), but special-case
`extension.name === 'apemind'` so its edit button appears. Users can
then open the configure modal and replace URL + Bearer token before
enabling.

5-cat compliance: still category 4 (UI 可见性微调) + 3 (默认配置 / bundled
extension config). The change is a one-condition extension to existing
logic and rebases cleanly with upstream.

Signed-off-by: earayu <earayu@163.com>
@earayu earayu merged commit 90356e4 into main May 25, 2026
20 checks passed
earayu added a commit that referenced this pull request May 28, 2026
…llback (#22)

* fix(desktop): trust bundled recipes by title when runtime hash mismatches

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>

* refine: match bundled recipe by title AND description to lower collision 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>

---------

Signed-off-by: earayu <earayu@163.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant