Skip to content

Commit 55f0463

Browse files
fix(feishu): suppress stale missing-scope grant notices (openclaw#31870) thanks @liuxiaopai-ai
Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check (fails on unrelated baseline lint in src/browser/chrome.ts) Co-authored-by: liuxiaopai-ai <[email protected]> Co-authored-by: Tak Hoffman <[email protected]>
1 parent f22fc17 commit 55f0463

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Docs: https://docs.openclaw.ai
3131
- Feishu/topic session routing: use `thread_id` as topic session scope fallback when `root_id` is absent, keep first-turn topic keys stable across thread creation, and force thread replies when inbound events already carry topic/thread context. (#29788) Thanks @songyaolun.
3232
- Feishu/DM pairing reply target: send pairing challenge replies to `chat:<chat_id>` instead of `user:<sender_open_id>` so Lark/Feishu private chats with user-id-only sender payloads receive pairing messages reliably. (#31403) Thanks @stakeswky.
3333
- Feishu/Lark private DM routing: treat inbound `chat_type: "private"` as direct-message context for pairing/mention-forward/reaction synthetic handling so Lark private chats behave like Feishu p2p DMs. (#31400) Thanks @stakeswky.
34+
- Feishu/Sender lookup permissions: suppress user-facing grant prompts for stale non-existent scope errors (`contact:contact.base:readonly`) during best-effort sender-name resolution so inbound messages continue without repeated false permission notices. (#31761)
3435
- Sandbox/workspace mount permissions: make primary `/workspace` bind mounts read-only whenever `workspaceAccess` is not `rw` (including `none`) across both core sandbox container and sandbox browser create flows. (#32227) Thanks @guanyu-zhang.
3536
- Security audit/skills workspace hardening: add `skills.workspace.symlink_escape` warning in `openclaw security audit` when workspace `skills/**/SKILL.md` resolves outside the workspace root (for example symlink-chain drift), plus docs coverage in the security glossary.
3637
- Signal/message actions: allow `react` to fall back to `toolContext.currentMessageId` when `messageId` is omitted, matching Telegram behavior and unblocking agent-initiated reactions on inbound turns. (#32217) Thanks @dunamismax.

extensions/feishu/src/bot.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,67 @@ describe("handleFeishuMessage command authorization", () => {
10731073
);
10741074
});
10751075

1076+
it("ignores stale non-existent contact scope permission errors", async () => {
1077+
mockShouldComputeCommandAuthorized.mockReturnValue(false);
1078+
mockCreateFeishuClient.mockReturnValue({
1079+
contact: {
1080+
user: {
1081+
get: vi.fn().mockRejectedValue({
1082+
response: {
1083+
data: {
1084+
code: 99991672,
1085+
msg: "permission denied: contact:contact.base:readonly https://open.feishu.cn/app/cli_scope_bug",
1086+
},
1087+
},
1088+
}),
1089+
},
1090+
},
1091+
});
1092+
1093+
const cfg: ClawdbotConfig = {
1094+
channels: {
1095+
feishu: {
1096+
appId: "cli_scope_bug",
1097+
appSecret: "sec_scope_bug",
1098+
groups: {
1099+
"oc-group": {
1100+
requireMention: false,
1101+
},
1102+
},
1103+
},
1104+
},
1105+
} as ClawdbotConfig;
1106+
1107+
const event: FeishuMessageEvent = {
1108+
sender: {
1109+
sender_id: {
1110+
open_id: "ou-perm-scope",
1111+
},
1112+
},
1113+
message: {
1114+
message_id: "msg-perm-scope-1",
1115+
chat_id: "oc-group",
1116+
chat_type: "group",
1117+
message_type: "text",
1118+
content: JSON.stringify({ text: "hello group" }),
1119+
},
1120+
};
1121+
1122+
await dispatchMessage({ cfg, event });
1123+
1124+
expect(mockDispatchReplyFromConfig).toHaveBeenCalledTimes(1);
1125+
expect(mockFinalizeInboundContext).toHaveBeenCalledWith(
1126+
expect.objectContaining({
1127+
BodyForAgent: expect.not.stringContaining("Permission grant URL"),
1128+
}),
1129+
);
1130+
expect(mockFinalizeInboundContext).toHaveBeenCalledWith(
1131+
expect.objectContaining({
1132+
BodyForAgent: expect.stringContaining("ou-perm-scope: hello group"),
1133+
}),
1134+
);
1135+
});
1136+
10761137
it("routes group sessions by sender when groupSessionScope=group_sender", async () => {
10771138
mockShouldComputeCommandAuthorized.mockReturnValue(false);
10781139

extensions/feishu/src/bot.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ type PermissionError = {
4444
grantUrl?: string;
4545
};
4646

47+
const IGNORED_PERMISSION_SCOPE_TOKENS = ["contact:contact.base:readonly"];
48+
49+
function shouldSuppressPermissionErrorNotice(permissionError: PermissionError): boolean {
50+
const message = permissionError.message.toLowerCase();
51+
return IGNORED_PERMISSION_SCOPE_TOKENS.some((token) => message.includes(token));
52+
}
53+
4754
function extractPermissionError(err: unknown): PermissionError | null {
4855
if (!err || typeof err !== "object") return null;
4956

@@ -140,6 +147,10 @@ async function resolveFeishuSenderName(params: {
140147
// Check if this is a permission error
141148
const permErr = extractPermissionError(err);
142149
if (permErr) {
150+
if (shouldSuppressPermissionErrorNotice(permErr)) {
151+
log(`feishu: ignoring stale permission scope error: ${permErr.message}`);
152+
return {};
153+
}
143154
log(`feishu: permission error resolving sender name: code=${permErr.code}`);
144155
return { permissionError: permErr };
145156
}

0 commit comments

Comments
 (0)