mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:00:41 +00:00
fix(feishu): preserve disabled group policy for explicit groups
This commit is contained in:
@@ -1425,7 +1425,7 @@ describe("handleFeishuMessage command authorization", () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
feishu: {
|
||||
// groupPolicy intentionally omitted -> schema default is "allowlist"
|
||||
groupPolicy: "allowlist",
|
||||
// groupAllowFrom intentionally omitted -> empty []
|
||||
groups: {
|
||||
"oc-explicit-group": {
|
||||
@@ -1456,6 +1456,72 @@ describe("handleFeishuMessage command authorization", () => {
|
||||
expect(mockDispatchReplyFromConfig).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not let explicit group config override disabled group policy", async () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
feishu: {
|
||||
groupPolicy: "disabled",
|
||||
groups: {
|
||||
"oc-disabled-policy-group": {
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const event: FeishuMessageEvent = {
|
||||
sender: {
|
||||
sender_id: { open_id: "ou-sender" },
|
||||
},
|
||||
message: {
|
||||
message_id: "msg-disabled-policy-group",
|
||||
chat_id: "oc-disabled-policy-group",
|
||||
chat_type: "group",
|
||||
message_type: "text",
|
||||
content: JSON.stringify({ text: "hello bot" }),
|
||||
},
|
||||
};
|
||||
|
||||
await dispatchMessage({ cfg, event });
|
||||
|
||||
expect(mockFinalizeInboundContext).not.toHaveBeenCalled();
|
||||
expect(mockDispatchReplyFromConfig).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not treat wildcard group defaults as allowlist admission", async () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
feishu: {
|
||||
groupPolicy: "allowlist",
|
||||
groups: {
|
||||
"*": {
|
||||
requireMention: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const event: FeishuMessageEvent = {
|
||||
sender: {
|
||||
sender_id: { open_id: "ou-sender" },
|
||||
},
|
||||
message: {
|
||||
message_id: "msg-wildcard-group-default",
|
||||
chat_id: "oc-wildcard-only",
|
||||
chat_type: "group",
|
||||
message_type: "text",
|
||||
content: JSON.stringify({ text: "hello bot" }),
|
||||
},
|
||||
};
|
||||
|
||||
await dispatchMessage({ cfg, event });
|
||||
|
||||
expect(mockFinalizeInboundContext).not.toHaveBeenCalled();
|
||||
expect(mockDispatchReplyFromConfig).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("drops message when groupConfig.enabled is false", async () => {
|
||||
const cfg: ClawdbotConfig = {
|
||||
channels: {
|
||||
|
||||
@@ -44,10 +44,11 @@ import { finalizeFeishuMessageProcessing, tryRecordMessagePersistent } from "./d
|
||||
import { maybeCreateDynamicAgent } from "./dynamic-agent.js";
|
||||
import { extractMentionTargets, isMentionForwardRequest } from "./mention.js";
|
||||
import {
|
||||
hasExplicitFeishuGroupConfig,
|
||||
isFeishuGroupAllowed,
|
||||
resolveFeishuAllowlistMatch,
|
||||
resolveFeishuGroupConfig,
|
||||
resolveFeishuReplyPolicy,
|
||||
resolveFeishuAllowlistMatch,
|
||||
isFeishuGroupAllowed,
|
||||
} from "./policy.js";
|
||||
import { resolveFeishuReasoningPreviewEnabled } from "./reasoning-preview.js";
|
||||
import { createFeishuReplyDispatcher } from "./reply-dispatcher.js";
|
||||
@@ -554,23 +555,25 @@ export async function handleFeishuMessage(params: {
|
||||
const groupAllowFrom = feishuCfg?.groupAllowFrom ?? [];
|
||||
// DEBUG: log(`feishu[${account.accountId}]: groupPolicy=${groupPolicy}`);
|
||||
|
||||
// A group that is explicitly configured under `channels.feishu.groups.<chat_id>`
|
||||
// is treated as admitted regardless of `groupAllowFrom`. The reporter case in
|
||||
// #67687 only sets `groups.<chat_id>.requireMention=false` and leaves
|
||||
// `groupAllowFrom` empty; with the schema-default `groupPolicy="allowlist"`,
|
||||
// an empty allowlist would otherwise reject the group before any per-group
|
||||
// `requireMention` override is evaluated.
|
||||
const groupExplicitlyConfigured = groupConfig !== undefined;
|
||||
// A group explicitly configured under `channels.feishu.groups.<chat_id>` is
|
||||
// treated as admitted in allowlist mode even when `groupAllowFrom` is empty.
|
||||
// Wildcard defaults still configure matching groups, but they are not an
|
||||
// admission signal by themselves.
|
||||
const groupExplicitlyConfigured = hasExplicitFeishuGroupConfig({
|
||||
cfg: feishuCfg,
|
||||
groupId: ctx.chatId,
|
||||
});
|
||||
|
||||
// Check if this GROUP is allowed (groupAllowFrom contains group IDs like oc_xxx, not user IDs)
|
||||
const groupAllowed =
|
||||
groupExplicitlyConfigured ||
|
||||
isFeishuGroupAllowed({
|
||||
groupPolicy,
|
||||
allowFrom: groupAllowFrom,
|
||||
senderId: ctx.chatId, // Check group ID, not sender ID
|
||||
senderName: undefined,
|
||||
});
|
||||
groupPolicy !== "disabled" &&
|
||||
(groupExplicitlyConfigured ||
|
||||
isFeishuGroupAllowed({
|
||||
groupPolicy,
|
||||
allowFrom: groupAllowFrom,
|
||||
senderId: ctx.chatId, // Check group ID, not sender ID
|
||||
senderName: undefined,
|
||||
}));
|
||||
|
||||
if (!groupAllowed) {
|
||||
log(
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { FeishuConfigSchema } from "./config-schema.js";
|
||||
import {
|
||||
hasExplicitFeishuGroupConfig,
|
||||
isFeishuGroupAllowed,
|
||||
resolveFeishuAllowlistMatch,
|
||||
resolveFeishuGroupConfig,
|
||||
@@ -141,6 +142,29 @@ describe("resolveFeishuGroupConfig", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasExplicitFeishuGroupConfig", () => {
|
||||
it("matches direct and case-insensitive group ids", () => {
|
||||
const cfg = createFeishuConfig({
|
||||
groups: {
|
||||
OC_UPPER: { requireMention: true },
|
||||
},
|
||||
});
|
||||
|
||||
expect(hasExplicitFeishuGroupConfig({ cfg, groupId: "OC_UPPER" })).toBe(true);
|
||||
expect(hasExplicitFeishuGroupConfig({ cfg, groupId: "oc_upper" })).toBe(true);
|
||||
});
|
||||
|
||||
it("does not treat wildcard group defaults as explicit admission", () => {
|
||||
const cfg = createFeishuConfig({
|
||||
groups: {
|
||||
"*": { requireMention: false },
|
||||
},
|
||||
});
|
||||
|
||||
expect(hasExplicitFeishuGroupConfig({ cfg, groupId: "oc_any" })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveFeishuAllowlistMatch", () => {
|
||||
it("allows wildcard", () => {
|
||||
expect(
|
||||
|
||||
@@ -148,6 +148,25 @@ export function resolveFeishuGroupConfig(params: { cfg?: FeishuConfig; groupId?:
|
||||
return wildcard;
|
||||
}
|
||||
|
||||
export function hasExplicitFeishuGroupConfig(params: {
|
||||
cfg?: FeishuConfig;
|
||||
groupId?: string | null;
|
||||
}): boolean {
|
||||
const groups = params.cfg?.groups ?? {};
|
||||
const groupId = params.groupId?.trim();
|
||||
if (!groupId) {
|
||||
return false;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(groups, groupId) && groupId !== "*") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lowered = normalizeOptionalLowercaseString(groupId) ?? "";
|
||||
return Object.keys(groups).some(
|
||||
(key) => key !== "*" && normalizeOptionalLowercaseString(key) === lowered,
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveFeishuGroupToolPolicy(params: ChannelGroupContext) {
|
||||
const cfg = params.cfg.channels?.feishu;
|
||||
if (!cfg) {
|
||||
|
||||
Reference in New Issue
Block a user