fix(feishu): guard routed tool disables
This commit is contained in:
parent
b75a55da5d
commit
5339a790d5
@ -1,9 +1,13 @@
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { listEnabledFeishuAccountConfigs, resolveFeishuAccountConfigState } from "./accounts.js";
|
||||
import { listEnabledFeishuAccountConfigs } from "./accounts.js";
|
||||
import { FeishuChatSchema, type FeishuChatParams } from "./chat-schema.js";
|
||||
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
|
||||
import { resolveToolsConfig } from "./tools-config.js";
|
||||
import {
|
||||
createFeishuToolClient,
|
||||
isFeishuToolEnabledForRoutedAccount,
|
||||
resolveAnyEnabledFeishuToolsConfig,
|
||||
resolveFeishuToolAccountConfigState,
|
||||
} from "./tool-account.js";
|
||||
|
||||
function json(data: unknown) {
|
||||
return {
|
||||
@ -151,11 +155,19 @@ export function registerFeishuChatTools(api: OpenClawPluginApi) {
|
||||
async execute(_toolCallId, params) {
|
||||
const p = params as FeishuChatExecuteParams;
|
||||
try {
|
||||
const account = resolveFeishuAccountConfigState({
|
||||
cfg: api.config,
|
||||
accountId: p.accountId ?? defaultAccountId ?? undefined,
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
});
|
||||
if (!resolveToolsConfig(account.config.tools).chat) {
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
tool: "chat",
|
||||
})
|
||||
) {
|
||||
return json({
|
||||
error: `Feishu chat is disabled for account "${account.accountId}".`,
|
||||
});
|
||||
|
||||
@ -67,4 +67,37 @@ describe("feishu_doc account selection", () => {
|
||||
|
||||
expect(createFeishuClientMock.mock.calls.at(-1)?.[0]?.appId).toBe("app-a");
|
||||
});
|
||||
|
||||
test("blocks execution when configured defaultAccount disables doc", async () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
feishu: {
|
||||
enabled: true,
|
||||
defaultAccount: "b",
|
||||
accounts: {
|
||||
a: { appId: "app-a", appSecret: "sec-a", tools: { doc: true } }, // pragma: allowlist secret
|
||||
b: { appId: "app-b", appSecret: "sec-b", tools: { doc: false } }, // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawPluginApi["config"];
|
||||
|
||||
const { api, resolveTool } = createToolFactoryHarness(cfg);
|
||||
registerFeishuDocTools(api);
|
||||
|
||||
const docTool = resolveTool("feishu_doc", { agentAccountId: "a" });
|
||||
const result = await docTool.execute("call-disabled", {
|
||||
action: "list_blocks",
|
||||
doc_token: "d",
|
||||
});
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
details: expect.objectContaining({
|
||||
error: 'Feishu doc is disabled for account "b".',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(createFeishuClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@ -20,7 +20,9 @@ import {
|
||||
import { getFeishuRuntime } from "./runtime.js";
|
||||
import {
|
||||
createFeishuToolClient,
|
||||
isFeishuToolEnabledForRoutedAccount,
|
||||
resolveAnyEnabledFeishuToolsConfig,
|
||||
resolveFeishuToolAccountConfigState,
|
||||
resolveFeishuToolAccount,
|
||||
} from "./tool-account.js";
|
||||
|
||||
@ -1273,6 +1275,23 @@ export function registerFeishuDocTools(api: OpenClawPluginApi) {
|
||||
async execute(_toolCallId, params) {
|
||||
const p = params as FeishuDocExecuteParams;
|
||||
try {
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
});
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
tool: "doc",
|
||||
})
|
||||
) {
|
||||
return json({
|
||||
error: `Feishu doc is disabled for account "${account.accountId}".`,
|
||||
});
|
||||
}
|
||||
const client = getClient(p, defaultAccountId);
|
||||
switch (p.action) {
|
||||
case "read":
|
||||
@ -1442,6 +1461,21 @@ export function registerFeishuDocTools(api: OpenClawPluginApi) {
|
||||
parameters: Type.Object({}),
|
||||
async execute() {
|
||||
try {
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
defaultAccountId: ctx.agentAccountId,
|
||||
});
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
defaultAccountId: ctx.agentAccountId,
|
||||
tool: "scopes",
|
||||
})
|
||||
) {
|
||||
return json({
|
||||
error: `Feishu scopes are disabled for account "${account.accountId}".`,
|
||||
});
|
||||
}
|
||||
const result = await listAppScopes(getClient(undefined, ctx.agentAccountId));
|
||||
return json(result);
|
||||
} catch (err) {
|
||||
|
||||
@ -2,7 +2,12 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { listEnabledFeishuAccountConfigs } from "./accounts.js";
|
||||
import { FeishuDriveSchema, type FeishuDriveParams } from "./drive-schema.js";
|
||||
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
|
||||
import {
|
||||
createFeishuToolClient,
|
||||
isFeishuToolEnabledForRoutedAccount,
|
||||
resolveAnyEnabledFeishuToolsConfig,
|
||||
resolveFeishuToolAccountConfigState,
|
||||
} from "./tool-account.js";
|
||||
import {
|
||||
jsonToolResult,
|
||||
toolExecutionErrorResult,
|
||||
@ -195,6 +200,23 @@ export function registerFeishuDriveTools(api: OpenClawPluginApi) {
|
||||
async execute(_toolCallId, params) {
|
||||
const p = params as FeishuDriveExecuteParams;
|
||||
try {
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
});
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
tool: "drive",
|
||||
})
|
||||
) {
|
||||
return jsonToolResult({
|
||||
error: `Feishu drive is disabled for account "${account.accountId}".`,
|
||||
});
|
||||
}
|
||||
const client = createFeishuToolClient({
|
||||
api,
|
||||
executeParams: p,
|
||||
|
||||
@ -2,7 +2,12 @@ import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { listEnabledFeishuAccountConfigs } from "./accounts.js";
|
||||
import { FeishuPermSchema, type FeishuPermParams } from "./perm-schema.js";
|
||||
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
|
||||
import {
|
||||
createFeishuToolClient,
|
||||
isFeishuToolEnabledForRoutedAccount,
|
||||
resolveAnyEnabledFeishuToolsConfig,
|
||||
resolveFeishuToolAccountConfigState,
|
||||
} from "./tool-account.js";
|
||||
import {
|
||||
jsonToolResult,
|
||||
toolExecutionErrorResult,
|
||||
@ -143,6 +148,23 @@ export function registerFeishuPermTools(api: OpenClawPluginApi) {
|
||||
async execute(_toolCallId, params) {
|
||||
const p = params as FeishuPermExecuteParams;
|
||||
try {
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
});
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
tool: "perm",
|
||||
})
|
||||
) {
|
||||
return jsonToolResult({
|
||||
error: `Feishu perm is disabled for account "${account.accountId}".`,
|
||||
});
|
||||
}
|
||||
const client = createFeishuToolClient({
|
||||
api,
|
||||
executeParams: p,
|
||||
|
||||
@ -162,6 +162,29 @@ describe("feishu tool account routing", () => {
|
||||
expect(createFeishuClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("chat tool checks the same routed account precedence as execution", async () => {
|
||||
const { api, resolveTool } = createToolFactoryHarness(
|
||||
createConfig({
|
||||
defaultAccount: "b",
|
||||
toolsA: { chat: true },
|
||||
toolsB: { chat: false },
|
||||
}),
|
||||
);
|
||||
registerFeishuChatTools(api);
|
||||
|
||||
const tool = resolveTool("feishu_chat", { agentAccountId: "a" });
|
||||
const result = await tool.execute("call", { action: "info", chat_id: "oc_b" });
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
details: expect.objectContaining({
|
||||
error: 'Feishu chat is disabled for account "b".',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
expect(createFeishuClientMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("perm tool registers when only second account enables it and routes to agentAccountId", async () => {
|
||||
const { api, resolveTool } = createToolFactoryHarness(
|
||||
createConfig({
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { resolveFeishuAccount } from "./accounts.js";
|
||||
import { resolveFeishuAccount, resolveFeishuAccountConfigState } from "./accounts.js";
|
||||
import { createFeishuClient } from "./client.js";
|
||||
import { resolveToolsConfig } from "./tools-config.js";
|
||||
import type { FeishuToolsConfig, ResolvedFeishuAccount } from "./types.js";
|
||||
@ -38,6 +38,33 @@ export function resolveFeishuToolAccount(params: {
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveFeishuToolAccountConfigState(params: {
|
||||
api: Pick<OpenClawPluginApi, "config">;
|
||||
executeParams?: AccountAwareParams;
|
||||
defaultAccountId?: string;
|
||||
}) {
|
||||
if (!params.api.config) {
|
||||
throw new Error("Feishu config unavailable");
|
||||
}
|
||||
return resolveFeishuAccountConfigState({
|
||||
cfg: params.api.config,
|
||||
accountId:
|
||||
normalizeOptionalAccountId(params.executeParams?.accountId) ??
|
||||
readConfiguredDefaultAccountId(params.api.config) ??
|
||||
normalizeOptionalAccountId(params.defaultAccountId),
|
||||
});
|
||||
}
|
||||
|
||||
export function isFeishuToolEnabledForRoutedAccount(params: {
|
||||
api: Pick<OpenClawPluginApi, "config">;
|
||||
executeParams?: AccountAwareParams;
|
||||
defaultAccountId?: string;
|
||||
tool: keyof Required<FeishuToolsConfig>;
|
||||
}): boolean {
|
||||
const account = resolveFeishuToolAccountConfigState(params);
|
||||
return resolveToolsConfig(account.config.tools)[params.tool];
|
||||
}
|
||||
|
||||
export function createFeishuToolClient(params: {
|
||||
api: Pick<OpenClawPluginApi, "config">;
|
||||
executeParams?: AccountAwareParams;
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import type * as Lark from "@larksuiteoapi/node-sdk";
|
||||
import type { OpenClawPluginApi } from "../runtime-api.js";
|
||||
import { listEnabledFeishuAccountConfigs } from "./accounts.js";
|
||||
import { createFeishuToolClient, resolveAnyEnabledFeishuToolsConfig } from "./tool-account.js";
|
||||
import {
|
||||
createFeishuToolClient,
|
||||
isFeishuToolEnabledForRoutedAccount,
|
||||
resolveAnyEnabledFeishuToolsConfig,
|
||||
resolveFeishuToolAccountConfigState,
|
||||
} from "./tool-account.js";
|
||||
import {
|
||||
jsonToolResult,
|
||||
toolExecutionErrorResult,
|
||||
@ -183,6 +188,23 @@ export function registerFeishuWikiTools(api: OpenClawPluginApi) {
|
||||
async execute(_toolCallId, params) {
|
||||
const p = params as FeishuWikiExecuteParams;
|
||||
try {
|
||||
const account = resolveFeishuToolAccountConfigState({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
});
|
||||
if (
|
||||
!isFeishuToolEnabledForRoutedAccount({
|
||||
api,
|
||||
executeParams: p,
|
||||
defaultAccountId,
|
||||
tool: "wiki",
|
||||
})
|
||||
) {
|
||||
return jsonToolResult({
|
||||
error: `Feishu wiki is disabled for account "${account.accountId}".`,
|
||||
});
|
||||
}
|
||||
const client = createFeishuToolClient({
|
||||
api,
|
||||
executeParams: p,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user