Skip to content

fix(dashboard): 修复按触发人鉴权开关刷新回显丢失,并修正 PUT 把策略存成字符串 - #1332

Open
DeepColds wants to merge 1 commit into
masterfrom
fix/dashboard-trigger-user-auth-echo
Open

fix(dashboard): 修复按触发人鉴权开关刷新回显丢失,并修正 PUT 把策略存成字符串#1332
DeepColds wants to merge 1 commit into
masterfrom
fix/dashboard-trigger-user-auth-echo

Conversation

@DeepColds

@DeepColds DeepColds commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

问题

用户反馈:Dashboard 里「按触发人鉴权」开关打开后,刷新配置页又变回关闭。

排查中发现这条路径上还有一个更严重的静默 bug,一并修复。

1. 刷新回显丢失(用户报告的现象)

配置页刷新时通过聚合接口 /api/bots 重载,而它依赖 daemon 的 GET /api/bot-default-oncall。该响应从未返回 triggerUserAuth,聚合层 botDefaultsPayload 拿不到字段后输出 null,前端开关据此渲染为关闭。

修复:在 /api/bot-default-oncall 私有响应中补上规范化后的 triggerUserAuth。缺失 / 关闭仍为 null,开启时完整保留 enabled / tools / fallback

2. PUT 把策略存成 JSON 字符串(排查中发现,比现象更严重)

PUT /api/bot-trigger-user-auth 直接把 JSON.stringify 的结果交给 applyConfigField,而 json kind 的 applyConfigField 不解析、原样写入,于是 bots.json 里存的是一个 JSON 字符串而不是对象。三个后果全是静默的:

后果 影响
getBot().config.triggerUserAuthstring?.enabled 恒为 undefined 开关看着开了,凭证边界从未真正建立 —— 用户以为已生效的安全设置并未生效
共享 parser 从未被调用 fallback:'device' 这类被刻意禁止的值也会 200 落盘
下次 daemon 重启时 bot-registry 的 parser 抛 must be an object 整个 bots.json 加载失败 —— 一个开关足以让 daemon 拒绝启动

实测复现(修复前,在临时目录里跑真实 IPC server):

PUT status 200 {"ok":true}
ON DISK   typeof = string  "{\"enabled\":true,\"tools\":[\"lark-cli\"],\"fallback\":\"none\"}"
IN MEMORY typeof = string  "{\"enabled\":true,\"tools\":[\"lark-cli\"],\"fallback\":\"none\"}"
BAD fallback=device status 200 {"ok":true}     ← 本该被拒绝
RELOAD THREW: Bot config [0]: triggerUserAuth must be an object

修复:改走 coerceConfigValue + applyConfigField,与 /botconfig set 的 json 分支完全同一口径(同一个 parser、同样的拒绝文案),落盘为归一化后的对象。同时 PUT 回响生效值,前端保存后无需再拉一次聚合接口。

顺带修正的两处

  • PUT 合并保存:dashboard 只编辑 enabled/tools/fallback 三个字段,现在合并保留 UI 没有编辑器的 gitHost / gitTokenExchangeUrl,避免用户只勾一个 tool 就静默删掉「按当轮身份鉴权 git push」的配置(与既有 /api/bot-riffRIFF_UI_EDITABLE_KEYS 同款做法)
  • 聚合层走共享 parser:手改坏的值降级为 null(关闭)而不是让整页 bot 行崩掉

影响面

公共 Bot Defaults 聚合路径(/api/bot-default-oncallbotDefaultsPayload/api/bots)。

  • GET 只多回一个不含密钥的策略对象(仅说明覆盖哪些工具、未授权时如何降级),已断言 larkAppSecret 不进该响应
  • 不涉及 CLI 适配器、后端(PtyBackend / TmuxBackend)与会话类型(话题 / 群 / adopt)
  • chat 侧 /botconfig 入口逻辑未改动 —— 本次是让 dashboard 入口对齐它,两个门从此共用同一 parser,不会再各自漂移

⚠️ 存量数据注意:在此修复前用过该开关的 bots.json 里可能已存有字符串形态的 triggerUserAuth,会导致 daemon 启动时报 must be an object 而拒启。

两种恢复方式(已实测):

  • daemon 还在跑:在 Dashboard 里再保存一次该开关即会自愈——修复后的 PUT 落盘为对象,随后 loadBotConfigs() 可正常加载(实测 PUT 200 → 磁盘 typeof = object → reload ok)
  • daemon 已因此拒启:手工把该字段改为对象,或删掉该字段后重新开启

测试验证

新增用例(在修复前全部失败、修复后全部通过,已用 git stash 逐条验证):

  • test/dashboard-ipc.test.ts 三例
    • 开启后刷新 GET 仍回显开启;并断言落盘为对象内存热更新为对象写出的配置能被 loadBotConfigs() 重新加载(即不再拒启 daemon);省略 tools 时回显归一化后的全量工具
    • tools-only 保存不丢 gitHost / gitTokenExchangeUrl
    • device / 错误 tool 名 / 错类型 / 非法 gitHost / 非对象共 5 类非法输入全部 400 且不落盘
  • test/dashboard-bot-payload.test.ts 一例:聚合层开启原样透传,缺失 / null / 显式关闭均为 off,畸形值降级为 null 不抛,且不进公开 summary;并把 triggerUserAuth 加入「每个可编辑字段都在聚合行里」的契约清单

已 rebase 到最新 master(含 #1283 / #1315 / #1326),在新基线上重跑:

vitest run test/dashboard*.test.ts test/bot-*.test.ts test/config*.test.ts \
  test/trigger-user-auth.test.ts test/command-handler.test.ts \
  test/turn-cli-identity.test.ts test/credential-boundary-prompt.test.ts
→ Test Files 124 passed (124) | Tests 2905 passed | 1 skipped

构建 / 类型检查(rebase 后重跑):tsc 全量、tsc -p tsconfig.scripts.jsontsc -p tsconfig.test-mocks.jsonaudit-public-domains.mjsbuild-dashboard.mjs 均通过。

说明:本机(Linux 排查环境)没装 bun,故按 bun run build 的组成逐步执行了上述等价步骤。该环境的共享 node_modulesyaml 包,src/dsh-runner.ts 会报一条 TS2307——与本改动无关,master 上同样存在(已核对)。

UI 效果

后端字段修复,无视觉改动:开关位置与样式不变,行为上从「刷新后复位为关闭」变为「刷新后保持开启,并正确回显已勾选的 tools 与 fallback」。

🤖 Generated with Claude Code

@DeepColds
DeepColds requested a review from deepcoldy as a code owner September 8, 2026 13:51
按触发人鉴权(triggerUserAuth)开关在 Dashboard 打开后刷新配置页会复位为关闭。
排查中发现同一条路径上还有一个更严重的静默 bug,一并修复。

配置页刷新时通过聚合接口 /api/bots 重载,而它依赖 daemon 的
GET /api/bot-default-oncall。该响应从未返回 triggerUserAuth,聚合层
botDefaultsPayload 拿不到字段后输出 null,前端开关据此渲染为关闭。

修复:在 /api/bot-default-oncall 私有响应中补上规范化后的 triggerUserAuth。
缺失 / 关闭仍为 null,开启时完整保留 enabled / tools / fallback。

PUT /api/bot-trigger-user-auth 直接把 JSON.stringify 的结果交给
applyConfigField,而 json kind 的 applyConfigField 不解析、原样写入,于是
bots.json 里存的是一个 JSON **字符串**而不是对象。三个后果全是静默的:

- getBot().config.triggerUserAuth 是 string,`?.enabled` 恒为 undefined
  —— 开关看着开了,凭证边界从未真正建立(即用户以为已生效的安全设置并未生效)
- 共享 parser 从未被调用,fallback:'device' 这类被刻意禁止的值也会 200 落盘
- 下次 daemon 重启时 bot-registry 的 parser 抛 "must be an object",整个
  bots.json 加载失败 —— 一个开关足以让 daemon 拒绝启动

修复:改走 coerceConfigValue + applyConfigField,与 /botconfig set 的 json
分支完全同一口径(同一个 parser、同样的拒绝文案),落盘为归一化后的对象。
同时 PUT 回响生效值,前端保存后无需再拉一次聚合接口。

顺带修正:dashboard 只编辑 enabled/tools/fallback 三个字段,PUT 现在合并保留
UI 没有编辑器的 gitHost / gitTokenExchangeUrl,避免用户只勾一个 tool 就静默
删掉「按当轮身份鉴权 git push」的配置;聚合层也改走共享 parser,手改坏的值
降级为 null(关闭)而不是让整页 bot 行崩掉。

公共 Bot Defaults 聚合路径(/api/bot-default-oncall → botDefaultsPayload →
/api/bots)。GET 只多回一个不含密钥的策略对象(仅说明覆盖哪些工具、未授权时
如何降级),已验证 larkAppSecret 不进该响应。改动不涉及 CLI 适配器、后端
(PtyBackend / TmuxBackend)与会话类型,chat 侧 /botconfig 入口逻辑未改动
(本次是让 dashboard 入口对齐它)。

注意:在此修复前用过该开关的 bots.json 里可能已存有字符串形态的
triggerUserAuth,会导致 daemon 启动时报 "must be an object";此时手工把该
字段改为对象(或删掉该字段重新开启)即可恢复。

- 新增 test/dashboard-ipc.test.ts 三例:开启后刷新 GET 仍回显开启(并断言
  落盘为对象、内存热更新为对象、写出的配置能被 loadBotConfigs 重新加载);
  tools-only 保存不丢 gitHost / gitTokenExchangeUrl;device / 错误 tool 名 /
  错类型 / 非法 gitHost / 非对象共 5 类非法输入全部 400 且不落盘
- 新增 test/dashboard-bot-payload.test.ts 一例:聚合层开启原样透传,缺失 /
  null / 显式关闭均为 off,畸形值降级为 null 不抛,且不进公开 summary
- 三例新增用例在修复前全部失败、修复后全部通过(已 git stash 验证)
- vitest run test/dashboard-ipc.test.ts test/dashboard-bot-payload.test.ts
  test/trigger-user-auth.test.ts test/command-handler.test.ts
  test/turn-cli-identity.test.ts test/credential-boundary-prompt.test.ts
  → 6 files / 654 passed
- vitest run test/dashboard*.test.ts test/bot-*.test.ts test/config*.test.ts
  → 120 files / 2528 passed, 1 skipped
- tsc 全量类型检查通过;tsc -p tsconfig.scripts.json、
  -p tsconfig.test-mocks.json、audit-public-domains.mjs、
  build-dashboard.mjs 均通过(本机 node_modules 缺 yaml 包,src/dsh-runner.ts
  报一条与本改动无关的 TS2307,master 上同样存在)
@DeepColds
DeepColds force-pushed the fix/dashboard-trigger-user-auth-echo branch from 8c5383d to dbe1836 Compare September 8, 2026 13:56
@deepcoldy

Copy link
Copy Markdown
Owner

已为本 PR 创建自动评审群:https://applink.feishu.cn/client/chat/open?openChatId=oc_1655fa007d8a14408ea848ca361b4627

不过暂时没能把您拉进群——自动拉人依赖一份作者名单文档,您的 GitHub 账号还没登记在里面。麻烦您把 GitHub 账号和飞书信息补进名单文档:https://bytedance.larkoffice.com/wiki/WJ1nwWbtxi89erkNGNbcgkt9nUe ,补好之后后续复审会自动把您拉进群。

(本条为自动评审流程发出,评审结论仅供参考,最终以维护者审阅为准。)

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.

2 participants