From 2972d6fa7929c293f4b62a606cd1dcb700ef5da7 Mon Sep 17 00:00:00 2001 From: Sid Date: Fri, 6 Mar 2026 01:32:01 +0800 Subject: [PATCH] fix(feishu): accept groupPolicy "allowall" as alias for "open" (#36358) * fix(feishu): accept groupPolicy "allowall" as alias for "open" When users configure groupPolicy: "allowall" in Feishu channel config, the Zod schema rejects the value and the runtime policy check falls through to the allowlist path. With an empty allowFrom array, all group messages are silently dropped despite the intended "allow all" semantics. Accept "allowall" at the schema level (transform to "open") and add a runtime guard in isFeishuGroupAllowed so the value is handled even if it bypasses schema validation. Closes #36312 Made-with: Cursor * Feishu: tighten allowall alias handling and coverage --------- Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + extensions/feishu/src/config-schema.test.ts | 8 +++++ extensions/feishu/src/config-schema.ts | 5 ++- extensions/feishu/src/policy.test.ts | 40 +++++++++++++++++++++ extensions/feishu/src/policy.ts | 4 +-- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f23a06ee3e..22570d3bcca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,6 +122,7 @@ Docs: https://docs.openclaw.ai - LINE/status/config/webhook synthesis: fix status false positives from snapshot/config state and accept LINE webhook HEAD probes for compatibility. (from #10487, #25726, #27537, #27908, #31387) Thanks @BlueBirdBack, @stakeswky, @loiie45e, @puritysb, and @mcaxtr. - LINE cleanup/test follow-ups: fold cleanup/test learnings into the synthesis review path while keeping runtime changes focused on regression fixes. (from #17630, #17289) Thanks @Clawborn and @davidahmann. - Mattermost/interactive buttons: add interactive button send/callback support with directory-based channel/user target resolution, and harden callbacks via account-scoped HMAC verification plus sender-scoped DM routing. (#19957) thanks @tonydehnke. +- Feishu/groupPolicy legacy alias compatibility: treat legacy `groupPolicy: "allowall"` as `open` in both schema parsing and runtime policy checks so intended open-group configs no longer silently drop group messages when `groupAllowFrom` is empty. (from #36358) Thanks @Sid-Qin. - Mattermost/plugin SDK import policy: replace remaining monolithic `openclaw/plugin-sdk` imports in Mattermost mention-gating paths/tests with scoped subpaths (`openclaw/plugin-sdk/compat` and `openclaw/plugin-sdk/mattermost`) so `pnpm check` passes `lint:plugins:no-monolithic-plugin-sdk-entry-imports` on baseline. (#36480) Thanks @Takhoffman. diff --git a/extensions/feishu/src/config-schema.test.ts b/extensions/feishu/src/config-schema.test.ts index 06c954cd164..035f89a2940 100644 --- a/extensions/feishu/src/config-schema.test.ts +++ b/extensions/feishu/src/config-schema.test.ts @@ -24,6 +24,14 @@ describe("FeishuConfigSchema webhook validation", () => { expect(result.accounts?.main?.requireMention).toBeUndefined(); }); + it("normalizes legacy groupPolicy allowall to open", () => { + const result = FeishuConfigSchema.parse({ + groupPolicy: "allowall", + }); + + expect(result.groupPolicy).toBe("open"); + }); + it("rejects top-level webhook mode without verificationToken", () => { const result = FeishuConfigSchema.safeParse({ connectionMode: "webhook", diff --git a/extensions/feishu/src/config-schema.ts b/extensions/feishu/src/config-schema.ts index c7efafe2938..f4acef5735c 100644 --- a/extensions/feishu/src/config-schema.ts +++ b/extensions/feishu/src/config-schema.ts @@ -4,7 +4,10 @@ export { z }; import { buildSecretInputSchema, hasConfiguredSecretInput } from "./secret-input.js"; const DmPolicySchema = z.enum(["open", "pairing", "allowlist"]); -const GroupPolicySchema = z.enum(["open", "allowlist", "disabled"]); +const GroupPolicySchema = z.union([ + z.enum(["open", "allowlist", "disabled"]), + z.literal("allowall").transform(() => "open" as const), +]); const FeishuDomainSchema = z.union([ z.enum(["feishu", "lark"]), z.string().url().startsWith("https://"), diff --git a/extensions/feishu/src/policy.test.ts b/extensions/feishu/src/policy.test.ts index 3a159023546..c53532df3ff 100644 --- a/extensions/feishu/src/policy.test.ts +++ b/extensions/feishu/src/policy.test.ts @@ -110,5 +110,45 @@ describe("feishu policy", () => { }), ).toBe(true); }); + + it("allows group when groupPolicy is 'open'", () => { + expect( + isFeishuGroupAllowed({ + groupPolicy: "open", + allowFrom: [], + senderId: "oc_group_999", + }), + ).toBe(true); + }); + + it("treats 'allowall' as equivalent to 'open'", () => { + expect( + isFeishuGroupAllowed({ + groupPolicy: "allowall", + allowFrom: [], + senderId: "oc_group_999", + }), + ).toBe(true); + }); + + it("rejects group when groupPolicy is 'disabled'", () => { + expect( + isFeishuGroupAllowed({ + groupPolicy: "disabled", + allowFrom: ["oc_group_999"], + senderId: "oc_group_999", + }), + ).toBe(false); + }); + + it("rejects group when groupPolicy is 'allowlist' and allowFrom is empty", () => { + expect( + isFeishuGroupAllowed({ + groupPolicy: "allowlist", + allowFrom: [], + senderId: "oc_group_999", + }), + ).toBe(false); + }); }); }); diff --git a/extensions/feishu/src/policy.ts b/extensions/feishu/src/policy.ts index 9c6164fc9e0..051c8bcdf7b 100644 --- a/extensions/feishu/src/policy.ts +++ b/extensions/feishu/src/policy.ts @@ -92,7 +92,7 @@ export function resolveFeishuGroupToolPolicy( } export function isFeishuGroupAllowed(params: { - groupPolicy: "open" | "allowlist" | "disabled"; + groupPolicy: "open" | "allowlist" | "disabled" | "allowall"; allowFrom: Array; senderId: string; senderIds?: Array; @@ -102,7 +102,7 @@ export function isFeishuGroupAllowed(params: { if (groupPolicy === "disabled") { return false; } - if (groupPolicy === "open") { + if (groupPolicy === "open" || groupPolicy === "allowall") { return true; } return resolveFeishuAllowlistMatch(params).allowed;