[Feat] Add grant request card for blocked mentions#276
Merged
deepcoldy merged 3 commits intoJun 22, 2026
Conversation
df51537 to
b524390
Compare
Review follow-up for deepcoldy#276: - grant-prefs-store:新增 autoGrantRequestCards 写回/删除/默认/局部 patch/catch 回退的 round-trip 测试(此前 0 覆盖,兄弟字段有 6 例)。 - event-dispatcher 测试:beforeEach 重置真实 grant-pending 表(消除跨用例 节流状态泄漏),并新增「同一 bot+群重复 @Blocked 只发一张卡」的节流去重测试。 - card-builder escapeMd:转义集合补 `<`/`>`,防 attacker 可控名字(如外部 bot 的 app 名)在 lark_md 卡片正文注入字面 `<at id=…></at>` 伪 mention。 - event-dispatcher:申请卡名字解析增加 observed-bots 花名册兜底——外部 bot 发送方 不在自己消息的 mentions 里,原实现只能给 owner 显示裸 open_id。 - i18n zh:card.grant.body_request 「对象」改「发送方」对齐英文 Sender、消歧。
修 Codex 抓的节流/失败恢复缺口: - maybeSendGrantRequestCard 在 replyMessage 失败时 clearPending()——原来只 log, pending 残留会把该发送方节流压死、owner 永远看不到卡片,只能等 daemon 重启或别的 target 触发全表 prune 才恢复。清掉后下次 @ 会重试发卡。 - isThrottled 对 pending 增加 stale 窗口回收(与 denied 冷却回收同构):超过 STALE_PENDING_MS 的废弃 pending 本 key 即时删除并放行。原实现对 pending 恒返 true, 单一发送方反复 @、无其它 grant 活动触发 prune 时,过 24h 也不会自然恢复。 - 补两条守护测试:grant-pending「同 key stale pending 无需跨 key sweep 即回收」、 event-dispatcher「发卡失败后下次 @Blocked 会重试」(均在去掉对应修复时失败)。
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.
Summary
This PR fixes the silent failure path for bot-to-bot handoffs in groups when an external bot @mentions the current bot but has not yet been granted talk access.
Previously, the human-message path already had a self-service
/grantrequest card: if a person explicitly @mentioned the bot but failed thecanTalkgate, BotMux would notify the owner with an approval card. The foreign-bot path used a separate gate, however. If the sender was not a known same-deployment peer, was not in this bot's oncall chat, and did not matchchatGrantsorglobalGrants, the dispatcher simply returned without any visible feedback. That made bot-to-bot collaboration look broken until an owner manually ran/grant @bot.What Changed
autoGrantRequestCardsbot config field.falseexplicitly disables automatic grant request cards and keeps the old silent-drop behavior.grant_chat/grant_globalactions.canTalkaccess./restart,/close, terminal write access, and config mutation remain governed byallowedUsers/ owner permissions.Auto grant card for blocked @mentions/未授权 @ 自动弹授权卡.bots-jsondocs in both zh/en to document the new field.Root Cause
BotMux had two different inbound routing paths:
checkGroupMessageAccess(). When a user explicitly @mentioned the bot but failedcanTalk, the dispatcher calledmaybeSendGrantRequestCard().chatGrant, orglobalGrant. That gate returned silently, so owners never saw an actionable authorization prompt.This PR makes the foreign-bot gate use the same grant request card mechanism before returning, while preserving the gate itself.
User / Developer Impact
autoGrantRequestCards: falseinbots.json.Validation
corepack pnpm vitest run test/event-dispatcher.test.ts test/bot-registry-grant.test.ts test/dashboard-bot-payload.test.tsPATH=/tmp/botmux-corepack-bin:$PATH pnpm buildgit diff --checkNotes
The first push to upstream
deepcoldy/botmuxwas denied for this SSH identity, so the branch is pushed from thenil-err/botmuxfork and this PR targetsdeepcoldy/botmux:master.