@openclaw/feishu 2026.5.2-beta.2 → 2026.5.3-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accounts-Ba3-WP1z.js +423 -0
- package/dist/api.js +2280 -0
- package/dist/app-registration-B8qc1MCM.js +184 -0
- package/dist/audio-preflight.runtime-BPlzkO3l.js +7 -0
- package/dist/card-interaction-BfRLgvw_.js +96 -0
- package/dist/channel-CSD_Jt8I.js +1668 -0
- package/dist/channel-entry.js +22 -0
- package/dist/channel-plugin-api.js +2 -0
- package/dist/channel.runtime-DYsXcD36.js +700 -0
- package/dist/client-DBVoQL5w.js +157 -0
- package/dist/contract-api.js +9 -0
- package/dist/conversation-id-DWS3Ep2A.js +139 -0
- package/dist/directory.static-f3EeoRJd.js +44 -0
- package/dist/drive-C5eJLJr7.js +883 -0
- package/dist/index.js +68 -0
- package/dist/monitor-CT189QfR.js +60 -0
- package/dist/monitor.account-dJV2jO8C.js +4990 -0
- package/dist/monitor.state-DYM02ipp.js +100 -0
- package/dist/policy-D6c-wMPl.js +118 -0
- package/dist/probe-BNzzU_uR.js +149 -0
- package/dist/rolldown-runtime-DUslC3ob.js +14 -0
- package/dist/runtime-CG0DuRCy.js +8 -0
- package/dist/runtime-api.js +14 -0
- package/dist/secret-contract-Dm4Z_zQN.js +119 -0
- package/dist/secret-contract-api.js +2 -0
- package/dist/security-audit-DqJdocrN.js +11 -0
- package/dist/security-audit-shared-ByuMx9cJ.js +38 -0
- package/dist/security-contract-api.js +2 -0
- package/dist/send-DowxxbpH.js +1218 -0
- package/dist/session-conversation-B4nrW-vo.js +27 -0
- package/dist/session-key-api.js +2 -0
- package/dist/setup-api.js +2 -0
- package/dist/setup-entry.js +15 -0
- package/dist/subagent-hooks-C3UhPVLV.js +227 -0
- package/dist/subagent-hooks-api.js +23 -0
- package/dist/targets-JMFJRKSe.js +48 -0
- package/dist/thread-bindings-BmS6TLes.js +222 -0
- package/package.json +15 -6
- package/api.ts +0 -31
- package/channel-entry.ts +0 -20
- package/channel-plugin-api.ts +0 -1
- package/contract-api.ts +0 -16
- package/index.ts +0 -82
- package/runtime-api.ts +0 -55
- package/secret-contract-api.ts +0 -5
- package/security-contract-api.ts +0 -1
- package/session-key-api.ts +0 -1
- package/setup-api.ts +0 -3
- package/setup-entry.test.ts +0 -14
- package/setup-entry.ts +0 -13
- package/src/accounts.test.ts +0 -459
- package/src/accounts.ts +0 -326
- package/src/app-registration.ts +0 -331
- package/src/approval-auth.test.ts +0 -24
- package/src/approval-auth.ts +0 -25
- package/src/async.test.ts +0 -35
- package/src/async.ts +0 -104
- package/src/audio-preflight.runtime.ts +0 -9
- package/src/bitable.test.ts +0 -131
- package/src/bitable.ts +0 -762
- package/src/bot-content.ts +0 -474
- package/src/bot-group-name.test.ts +0 -108
- package/src/bot-runtime-api.ts +0 -12
- package/src/bot-sender-name.ts +0 -125
- package/src/bot.broadcast.test.ts +0 -463
- package/src/bot.card-action.test.ts +0 -577
- package/src/bot.checkBotMentioned.test.ts +0 -265
- package/src/bot.helpers.test.ts +0 -118
- package/src/bot.stripBotMention.test.ts +0 -126
- package/src/bot.test.ts +0 -3040
- package/src/bot.ts +0 -1559
- package/src/card-action.ts +0 -447
- package/src/card-interaction.test.ts +0 -129
- package/src/card-interaction.ts +0 -159
- package/src/card-test-helpers.ts +0 -47
- package/src/card-ux-approval.ts +0 -65
- package/src/card-ux-launcher.test.ts +0 -99
- package/src/card-ux-launcher.ts +0 -121
- package/src/card-ux-shared.ts +0 -33
- package/src/channel-runtime-api.ts +0 -16
- package/src/channel.runtime.ts +0 -47
- package/src/channel.test.ts +0 -959
- package/src/channel.ts +0 -1313
- package/src/chat-schema.ts +0 -25
- package/src/chat.test.ts +0 -196
- package/src/chat.ts +0 -188
- package/src/client.test.ts +0 -433
- package/src/client.ts +0 -290
- package/src/comment-dispatcher-runtime-api.ts +0 -6
- package/src/comment-dispatcher.test.ts +0 -169
- package/src/comment-dispatcher.ts +0 -107
- package/src/comment-handler-runtime-api.ts +0 -3
- package/src/comment-handler.test.ts +0 -486
- package/src/comment-handler.ts +0 -309
- package/src/comment-reaction.test.ts +0 -166
- package/src/comment-reaction.ts +0 -259
- package/src/comment-shared.test.ts +0 -182
- package/src/comment-shared.ts +0 -406
- package/src/comment-target.ts +0 -44
- package/src/config-schema.test.ts +0 -309
- package/src/config-schema.ts +0 -333
- package/src/conversation-id.test.ts +0 -18
- package/src/conversation-id.ts +0 -199
- package/src/dedup-runtime-api.ts +0 -1
- package/src/dedup.ts +0 -141
- package/src/directory.static.ts +0 -61
- package/src/directory.test.ts +0 -136
- package/src/directory.ts +0 -124
- package/src/doc-schema.ts +0 -182
- package/src/docx-batch-insert.test.ts +0 -91
- package/src/docx-batch-insert.ts +0 -223
- package/src/docx-color-text.ts +0 -154
- package/src/docx-table-ops.test.ts +0 -53
- package/src/docx-table-ops.ts +0 -316
- package/src/docx-types.ts +0 -38
- package/src/docx.account-selection.test.ts +0 -79
- package/src/docx.test.ts +0 -685
- package/src/docx.ts +0 -1616
- package/src/drive-schema.ts +0 -92
- package/src/drive.test.ts +0 -1219
- package/src/drive.ts +0 -829
- package/src/dynamic-agent.ts +0 -137
- package/src/event-types.ts +0 -45
- package/src/external-keys.test.ts +0 -20
- package/src/external-keys.ts +0 -19
- package/src/lifecycle.test-support.ts +0 -220
- package/src/media.test.ts +0 -900
- package/src/media.ts +0 -861
- package/src/mention-target.types.ts +0 -5
- package/src/mention.ts +0 -114
- package/src/message-action-contract.ts +0 -13
- package/src/monitor-state-runtime-api.ts +0 -7
- package/src/monitor-transport-runtime-api.ts +0 -7
- package/src/monitor.account.ts +0 -468
- package/src/monitor.acp-init-failure.lifecycle.test-support.ts +0 -219
- package/src/monitor.bot-identity.ts +0 -86
- package/src/monitor.bot-menu-handler.ts +0 -165
- package/src/monitor.bot-menu.lifecycle.test-support.ts +0 -224
- package/src/monitor.bot-menu.test.ts +0 -178
- package/src/monitor.broadcast.reply-once.lifecycle.test-support.ts +0 -264
- package/src/monitor.card-action.lifecycle.test-support.ts +0 -373
- package/src/monitor.cleanup.test.ts +0 -376
- package/src/monitor.comment-notice-handler.ts +0 -105
- package/src/monitor.comment.test.ts +0 -937
- package/src/monitor.comment.ts +0 -1386
- package/src/monitor.lifecycle.test.ts +0 -4
- package/src/monitor.message-handler.ts +0 -339
- package/src/monitor.reaction.lifecycle.test-support.ts +0 -68
- package/src/monitor.reaction.test.ts +0 -713
- package/src/monitor.startup.test.ts +0 -192
- package/src/monitor.startup.ts +0 -74
- package/src/monitor.state.defaults.test.ts +0 -46
- package/src/monitor.state.ts +0 -170
- package/src/monitor.synthetic-error.ts +0 -18
- package/src/monitor.test-mocks.ts +0 -45
- package/src/monitor.transport.ts +0 -424
- package/src/monitor.ts +0 -100
- package/src/monitor.webhook-e2e.test.ts +0 -272
- package/src/monitor.webhook-security.test.ts +0 -264
- package/src/monitor.webhook.test-helpers.ts +0 -116
- package/src/outbound-runtime-api.ts +0 -1
- package/src/outbound.test.ts +0 -935
- package/src/outbound.ts +0 -718
- package/src/perm-schema.ts +0 -52
- package/src/perm.ts +0 -170
- package/src/pins.ts +0 -108
- package/src/policy.test.ts +0 -334
- package/src/policy.ts +0 -236
- package/src/post.test.ts +0 -105
- package/src/post.ts +0 -275
- package/src/probe.test.ts +0 -275
- package/src/probe.ts +0 -166
- package/src/processing-claims.ts +0 -59
- package/src/qr-terminal.ts +0 -1
- package/src/reactions.ts +0 -123
- package/src/reasoning-preview.test.ts +0 -59
- package/src/reasoning-preview.ts +0 -20
- package/src/reply-dispatcher-runtime-api.ts +0 -7
- package/src/reply-dispatcher.test.ts +0 -1144
- package/src/reply-dispatcher.ts +0 -650
- package/src/runtime.ts +0 -9
- package/src/secret-contract.ts +0 -145
- package/src/secret-input.ts +0 -1
- package/src/security-audit-shared.ts +0 -69
- package/src/security-audit.test.ts +0 -61
- package/src/security-audit.ts +0 -1
- package/src/send-result.ts +0 -29
- package/src/send-target.test.ts +0 -80
- package/src/send-target.ts +0 -35
- package/src/send.reply-fallback.test.ts +0 -292
- package/src/send.test.ts +0 -550
- package/src/send.ts +0 -800
- package/src/sequential-key.test.ts +0 -72
- package/src/sequential-key.ts +0 -28
- package/src/sequential-queue.test.ts +0 -92
- package/src/sequential-queue.ts +0 -16
- package/src/session-conversation.ts +0 -42
- package/src/session-route.ts +0 -48
- package/src/setup-core.ts +0 -51
- package/src/setup-surface.test.ts +0 -174
- package/src/setup-surface.ts +0 -581
- package/src/streaming-card.test.ts +0 -190
- package/src/streaming-card.ts +0 -490
- package/src/subagent-hooks.test.ts +0 -603
- package/src/subagent-hooks.ts +0 -397
- package/src/targets.ts +0 -97
- package/src/test-support/lifecycle-test-support.ts +0 -453
- package/src/thread-bindings.test.ts +0 -143
- package/src/thread-bindings.ts +0 -330
- package/src/tool-account-routing.test.ts +0 -187
- package/src/tool-account.test.ts +0 -44
- package/src/tool-account.ts +0 -93
- package/src/tool-factory-test-harness.ts +0 -79
- package/src/tool-result.test.ts +0 -32
- package/src/tool-result.ts +0 -16
- package/src/tools-config.test.ts +0 -21
- package/src/tools-config.ts +0 -22
- package/src/types.ts +0 -104
- package/src/typing.test.ts +0 -144
- package/src/typing.ts +0 -214
- package/src/wiki-schema.ts +0 -55
- package/src/wiki.ts +0 -227
- package/subagent-hooks-api.ts +0 -31
- package/tsconfig.json +0 -16
package/src/secret-contract.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
collectConditionalChannelFieldAssignments,
|
|
3
|
-
collectSimpleChannelFieldAssignments,
|
|
4
|
-
getChannelSurface,
|
|
5
|
-
hasOwnProperty,
|
|
6
|
-
normalizeSecretStringValue,
|
|
7
|
-
type ResolverContext,
|
|
8
|
-
type SecretDefaults,
|
|
9
|
-
type SecretTargetRegistryEntry,
|
|
10
|
-
} from "openclaw/plugin-sdk/channel-secret-basic-runtime";
|
|
11
|
-
|
|
12
|
-
export const secretTargetRegistryEntries: SecretTargetRegistryEntry[] = [
|
|
13
|
-
{
|
|
14
|
-
id: "channels.feishu.accounts.*.appSecret",
|
|
15
|
-
targetType: "channels.feishu.accounts.*.appSecret",
|
|
16
|
-
configFile: "openclaw.json",
|
|
17
|
-
pathPattern: "channels.feishu.accounts.*.appSecret",
|
|
18
|
-
secretShape: "secret_input",
|
|
19
|
-
expectedResolvedValue: "string",
|
|
20
|
-
includeInPlan: true,
|
|
21
|
-
includeInConfigure: true,
|
|
22
|
-
includeInAudit: true,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: "channels.feishu.accounts.*.encryptKey",
|
|
26
|
-
targetType: "channels.feishu.accounts.*.encryptKey",
|
|
27
|
-
configFile: "openclaw.json",
|
|
28
|
-
pathPattern: "channels.feishu.accounts.*.encryptKey",
|
|
29
|
-
secretShape: "secret_input",
|
|
30
|
-
expectedResolvedValue: "string",
|
|
31
|
-
includeInPlan: true,
|
|
32
|
-
includeInConfigure: true,
|
|
33
|
-
includeInAudit: true,
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
id: "channels.feishu.accounts.*.verificationToken",
|
|
37
|
-
targetType: "channels.feishu.accounts.*.verificationToken",
|
|
38
|
-
configFile: "openclaw.json",
|
|
39
|
-
pathPattern: "channels.feishu.accounts.*.verificationToken",
|
|
40
|
-
secretShape: "secret_input",
|
|
41
|
-
expectedResolvedValue: "string",
|
|
42
|
-
includeInPlan: true,
|
|
43
|
-
includeInConfigure: true,
|
|
44
|
-
includeInAudit: true,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: "channels.feishu.appSecret",
|
|
48
|
-
targetType: "channels.feishu.appSecret",
|
|
49
|
-
configFile: "openclaw.json",
|
|
50
|
-
pathPattern: "channels.feishu.appSecret",
|
|
51
|
-
secretShape: "secret_input",
|
|
52
|
-
expectedResolvedValue: "string",
|
|
53
|
-
includeInPlan: true,
|
|
54
|
-
includeInConfigure: true,
|
|
55
|
-
includeInAudit: true,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: "channels.feishu.encryptKey",
|
|
59
|
-
targetType: "channels.feishu.encryptKey",
|
|
60
|
-
configFile: "openclaw.json",
|
|
61
|
-
pathPattern: "channels.feishu.encryptKey",
|
|
62
|
-
secretShape: "secret_input",
|
|
63
|
-
expectedResolvedValue: "string",
|
|
64
|
-
includeInPlan: true,
|
|
65
|
-
includeInConfigure: true,
|
|
66
|
-
includeInAudit: true,
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
id: "channels.feishu.verificationToken",
|
|
70
|
-
targetType: "channels.feishu.verificationToken",
|
|
71
|
-
configFile: "openclaw.json",
|
|
72
|
-
pathPattern: "channels.feishu.verificationToken",
|
|
73
|
-
secretShape: "secret_input",
|
|
74
|
-
expectedResolvedValue: "string",
|
|
75
|
-
includeInPlan: true,
|
|
76
|
-
includeInConfigure: true,
|
|
77
|
-
includeInAudit: true,
|
|
78
|
-
},
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
export function collectRuntimeConfigAssignments(params: {
|
|
82
|
-
config: { channels?: Record<string, unknown> };
|
|
83
|
-
defaults?: SecretDefaults;
|
|
84
|
-
context: ResolverContext;
|
|
85
|
-
}): void {
|
|
86
|
-
const resolved = getChannelSurface(params.config, "feishu");
|
|
87
|
-
if (!resolved) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const { channel: feishu, surface } = resolved;
|
|
91
|
-
collectSimpleChannelFieldAssignments({
|
|
92
|
-
channelKey: "feishu",
|
|
93
|
-
field: "appSecret",
|
|
94
|
-
channel: feishu,
|
|
95
|
-
surface,
|
|
96
|
-
defaults: params.defaults,
|
|
97
|
-
context: params.context,
|
|
98
|
-
topInactiveReason: "no enabled account inherits this top-level Feishu appSecret.",
|
|
99
|
-
accountInactiveReason: "Feishu account is disabled.",
|
|
100
|
-
});
|
|
101
|
-
const baseConnectionMode =
|
|
102
|
-
normalizeSecretStringValue(feishu.connectionMode) === "webhook" ? "webhook" : "websocket";
|
|
103
|
-
const resolveAccountMode = (account: Record<string, unknown>) =>
|
|
104
|
-
hasOwnProperty(account, "connectionMode")
|
|
105
|
-
? normalizeSecretStringValue(account.connectionMode)
|
|
106
|
-
: baseConnectionMode;
|
|
107
|
-
collectConditionalChannelFieldAssignments({
|
|
108
|
-
channelKey: "feishu",
|
|
109
|
-
field: "encryptKey",
|
|
110
|
-
channel: feishu,
|
|
111
|
-
surface,
|
|
112
|
-
defaults: params.defaults,
|
|
113
|
-
context: params.context,
|
|
114
|
-
topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
|
|
115
|
-
topLevelInheritedAccountActive: ({ account, enabled }) =>
|
|
116
|
-
enabled &&
|
|
117
|
-
!hasOwnProperty(account, "encryptKey") &&
|
|
118
|
-
resolveAccountMode(account) === "webhook",
|
|
119
|
-
accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
|
|
120
|
-
topInactiveReason: "no enabled Feishu webhook-mode surface inherits this top-level encryptKey.",
|
|
121
|
-
accountInactiveReason: "Feishu account is disabled or not running in webhook mode.",
|
|
122
|
-
});
|
|
123
|
-
collectConditionalChannelFieldAssignments({
|
|
124
|
-
channelKey: "feishu",
|
|
125
|
-
field: "verificationToken",
|
|
126
|
-
channel: feishu,
|
|
127
|
-
surface,
|
|
128
|
-
defaults: params.defaults,
|
|
129
|
-
context: params.context,
|
|
130
|
-
topLevelActiveWithoutAccounts: baseConnectionMode === "webhook",
|
|
131
|
-
topLevelInheritedAccountActive: ({ account, enabled }) =>
|
|
132
|
-
enabled &&
|
|
133
|
-
!hasOwnProperty(account, "verificationToken") &&
|
|
134
|
-
resolveAccountMode(account) === "webhook",
|
|
135
|
-
accountActive: ({ account, enabled }) => enabled && resolveAccountMode(account) === "webhook",
|
|
136
|
-
topInactiveReason:
|
|
137
|
-
"no enabled Feishu webhook-mode surface inherits this top-level verificationToken.",
|
|
138
|
-
accountInactiveReason: "Feishu account is disabled or not running in webhook mode.",
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const channelSecrets = {
|
|
143
|
-
secretTargetRegistryEntries,
|
|
144
|
-
collectRuntimeConfigAssignments,
|
|
145
|
-
};
|
package/src/secret-input.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { buildSecretInputSchema, hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input";
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { hasConfiguredSecretInput } from "openclaw/plugin-sdk/secret-input";
|
|
2
|
-
import type { OpenClawConfig } from "../runtime-api.js";
|
|
3
|
-
|
|
4
|
-
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
5
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
6
|
-
? (value as Record<string, unknown>)
|
|
7
|
-
: undefined;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function hasNonEmptyString(value: unknown): boolean {
|
|
11
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function isFeishuDocToolEnabled(cfg: OpenClawConfig): boolean {
|
|
15
|
-
const channels = asRecord(cfg.channels);
|
|
16
|
-
const feishu = asRecord(channels?.feishu);
|
|
17
|
-
if (!feishu || feishu.enabled === false) {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const baseTools = asRecord(feishu.tools);
|
|
22
|
-
const baseDocEnabled = baseTools?.doc !== false;
|
|
23
|
-
const baseAppId = hasNonEmptyString(feishu.appId);
|
|
24
|
-
const baseAppSecret = hasConfiguredSecretInput(feishu.appSecret, cfg.secrets?.defaults);
|
|
25
|
-
const baseConfigured = baseAppId && baseAppSecret;
|
|
26
|
-
|
|
27
|
-
const accounts = asRecord(feishu.accounts);
|
|
28
|
-
if (!accounts || Object.keys(accounts).length === 0) {
|
|
29
|
-
return baseDocEnabled && baseConfigured;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
for (const accountValue of Object.values(accounts)) {
|
|
33
|
-
const account = asRecord(accountValue) ?? {};
|
|
34
|
-
if (account.enabled === false) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
const accountTools = asRecord(account.tools);
|
|
38
|
-
const effectiveTools = accountTools ?? baseTools;
|
|
39
|
-
const docEnabled = effectiveTools?.doc !== false;
|
|
40
|
-
if (!docEnabled) {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const accountConfigured =
|
|
44
|
-
(hasNonEmptyString(account.appId) || baseAppId) &&
|
|
45
|
-
(hasConfiguredSecretInput(account.appSecret, cfg.secrets?.defaults) || baseAppSecret);
|
|
46
|
-
if (accountConfigured) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function collectFeishuSecurityAuditFindings(params: { cfg: OpenClawConfig }) {
|
|
55
|
-
if (!isFeishuDocToolEnabled(params.cfg)) {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
return [
|
|
59
|
-
{
|
|
60
|
-
checkId: "channels.feishu.doc_owner_open_id",
|
|
61
|
-
severity: "warn" as const,
|
|
62
|
-
title: "Feishu doc create can grant requester permissions",
|
|
63
|
-
detail:
|
|
64
|
-
'channels.feishu tools include "doc"; feishu_doc action "create" can grant document access to the trusted requesting Feishu user.',
|
|
65
|
-
remediation:
|
|
66
|
-
"Disable channels.feishu.tools.doc when not needed, and restrict tool access for untrusted prompts.",
|
|
67
|
-
},
|
|
68
|
-
];
|
|
69
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import type { OpenClawConfig } from "../runtime-api.js";
|
|
3
|
-
import { collectFeishuSecurityAuditFindings } from "./security-audit.js";
|
|
4
|
-
|
|
5
|
-
describe("Feishu security audit findings", () => {
|
|
6
|
-
it.each([
|
|
7
|
-
{
|
|
8
|
-
name: "warns when doc tool is enabled because create can grant requester access",
|
|
9
|
-
cfg: {
|
|
10
|
-
channels: {
|
|
11
|
-
feishu: {
|
|
12
|
-
appId: "cli_test",
|
|
13
|
-
appSecret: "secret_test",
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
} satisfies OpenClawConfig,
|
|
17
|
-
expectedFinding: "channels.feishu.doc_owner_open_id",
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: "treats SecretRef appSecret as configured for doc tool risk detection",
|
|
21
|
-
cfg: {
|
|
22
|
-
channels: {
|
|
23
|
-
feishu: {
|
|
24
|
-
appId: "cli_test",
|
|
25
|
-
appSecret: {
|
|
26
|
-
source: "env",
|
|
27
|
-
provider: "default",
|
|
28
|
-
id: "FEISHU_APP_SECRET",
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
} satisfies OpenClawConfig,
|
|
33
|
-
expectedFinding: "channels.feishu.doc_owner_open_id",
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "does not warn for doc grant risk when doc tools are disabled",
|
|
37
|
-
cfg: {
|
|
38
|
-
channels: {
|
|
39
|
-
feishu: {
|
|
40
|
-
appId: "cli_test",
|
|
41
|
-
appSecret: "secret_test",
|
|
42
|
-
tools: { doc: false },
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
} satisfies OpenClawConfig,
|
|
46
|
-
expectedNoFinding: "channels.feishu.doc_owner_open_id",
|
|
47
|
-
},
|
|
48
|
-
])("$name", ({ cfg, expectedFinding, expectedNoFinding }) => {
|
|
49
|
-
const findings = collectFeishuSecurityAuditFindings({ cfg });
|
|
50
|
-
if (expectedFinding) {
|
|
51
|
-
expect(
|
|
52
|
-
findings.some(
|
|
53
|
-
(finding) => finding.checkId === expectedFinding && finding.severity === "warn",
|
|
54
|
-
),
|
|
55
|
-
).toBe(true);
|
|
56
|
-
}
|
|
57
|
-
if (expectedNoFinding) {
|
|
58
|
-
expect(findings.some((finding) => finding.checkId === expectedNoFinding)).toBe(false);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
});
|
package/src/security-audit.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { collectFeishuSecurityAuditFindings } from "./security-audit-shared.js";
|
package/src/send-result.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
type FeishuMessageApiResponse = {
|
|
2
|
-
code?: number;
|
|
3
|
-
msg?: string;
|
|
4
|
-
data?: {
|
|
5
|
-
message_id?: string;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export function assertFeishuMessageApiSuccess(
|
|
10
|
-
response: FeishuMessageApiResponse,
|
|
11
|
-
errorPrefix: string,
|
|
12
|
-
) {
|
|
13
|
-
if (response.code !== 0) {
|
|
14
|
-
throw new Error(`${errorPrefix}: ${response.msg || `code ${response.code}`}`);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function toFeishuSendResult(
|
|
19
|
-
response: FeishuMessageApiResponse,
|
|
20
|
-
chatId: string,
|
|
21
|
-
): {
|
|
22
|
-
messageId: string;
|
|
23
|
-
chatId: string;
|
|
24
|
-
} {
|
|
25
|
-
return {
|
|
26
|
-
messageId: response.data?.message_id ?? "unknown",
|
|
27
|
-
chatId,
|
|
28
|
-
};
|
|
29
|
-
}
|
package/src/send-target.test.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import type { ClawdbotConfig } from "../runtime-api.js";
|
|
3
|
-
|
|
4
|
-
const resolveFeishuAccountMock = vi.hoisted(() => vi.fn());
|
|
5
|
-
const createFeishuClientMock = vi.hoisted(() => vi.fn());
|
|
6
|
-
|
|
7
|
-
vi.mock("./accounts.js", () => ({
|
|
8
|
-
resolveFeishuAccount: resolveFeishuAccountMock,
|
|
9
|
-
resolveFeishuRuntimeAccount: resolveFeishuAccountMock,
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
vi.mock("./client.js", () => ({
|
|
13
|
-
createFeishuClient: createFeishuClientMock,
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
let resolveFeishuSendTarget: typeof import("./send-target.js").resolveFeishuSendTarget;
|
|
17
|
-
|
|
18
|
-
describe("resolveFeishuSendTarget", () => {
|
|
19
|
-
const cfg = {} as ClawdbotConfig;
|
|
20
|
-
const client = { id: "client" };
|
|
21
|
-
|
|
22
|
-
beforeAll(async () => {
|
|
23
|
-
({ resolveFeishuSendTarget } = await import("./send-target.js"));
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
resolveFeishuAccountMock.mockReset().mockReturnValue({
|
|
28
|
-
accountId: "default",
|
|
29
|
-
enabled: true,
|
|
30
|
-
configured: true,
|
|
31
|
-
});
|
|
32
|
-
createFeishuClientMock.mockReset().mockReturnValue(client);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("keeps explicit group targets as chat_id even when ID shape is ambiguous", () => {
|
|
36
|
-
const result = resolveFeishuSendTarget({
|
|
37
|
-
cfg,
|
|
38
|
-
to: "feishu:group:group_room_alpha",
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
expect(result.receiveId).toBe("group_room_alpha");
|
|
42
|
-
expect(result.receiveIdType).toBe("chat_id");
|
|
43
|
-
expect(result.client).toBe(client);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("maps dm-prefixed open IDs to open_id", () => {
|
|
47
|
-
const result = resolveFeishuSendTarget({
|
|
48
|
-
cfg,
|
|
49
|
-
to: "lark:dm:ou_123",
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
expect(result.receiveId).toBe("ou_123");
|
|
53
|
-
expect(result.receiveIdType).toBe("open_id");
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("maps dm-prefixed non-open IDs to user_id", () => {
|
|
57
|
-
const result = resolveFeishuSendTarget({
|
|
58
|
-
cfg,
|
|
59
|
-
to: " feishu:dm:user_123 ",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(result.receiveId).toBe("user_123");
|
|
63
|
-
expect(result.receiveIdType).toBe("user_id");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("throws when target account is not configured", () => {
|
|
67
|
-
resolveFeishuAccountMock.mockReturnValue({
|
|
68
|
-
accountId: "default",
|
|
69
|
-
enabled: true,
|
|
70
|
-
configured: false,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(() =>
|
|
74
|
-
resolveFeishuSendTarget({
|
|
75
|
-
cfg,
|
|
76
|
-
to: "feishu:group:oc_123",
|
|
77
|
-
}),
|
|
78
|
-
).toThrow('Feishu account "default" not configured');
|
|
79
|
-
});
|
|
80
|
-
});
|
package/src/send-target.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { ClawdbotConfig } from "../runtime-api.js";
|
|
2
|
-
import { resolveFeishuRuntimeAccount } from "./accounts.js";
|
|
3
|
-
import { createFeishuClient } from "./client.js";
|
|
4
|
-
import { resolveReceiveIdType, normalizeFeishuTarget } from "./targets.js";
|
|
5
|
-
|
|
6
|
-
type FeishuSendTarget = {
|
|
7
|
-
client: ReturnType<typeof createFeishuClient>;
|
|
8
|
-
receiveId: string;
|
|
9
|
-
receiveIdType: ReturnType<typeof resolveReceiveIdType>;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export function resolveFeishuSendTarget(params: {
|
|
13
|
-
cfg: ClawdbotConfig;
|
|
14
|
-
to: string;
|
|
15
|
-
accountId?: string;
|
|
16
|
-
}): FeishuSendTarget {
|
|
17
|
-
const target = params.to.trim();
|
|
18
|
-
const account = resolveFeishuRuntimeAccount({ cfg: params.cfg, accountId: params.accountId });
|
|
19
|
-
if (!account.configured) {
|
|
20
|
-
throw new Error(`Feishu account "${account.accountId}" not configured`);
|
|
21
|
-
}
|
|
22
|
-
const client = createFeishuClient(account);
|
|
23
|
-
const receiveId = normalizeFeishuTarget(target);
|
|
24
|
-
if (!receiveId) {
|
|
25
|
-
throw new Error(`Invalid Feishu target: ${params.to}`);
|
|
26
|
-
}
|
|
27
|
-
// Preserve explicit routing prefixes (chat/group/user/dm/open_id) when present.
|
|
28
|
-
// normalizeFeishuTarget strips these prefixes, so infer type from the raw target first.
|
|
29
|
-
const withoutProviderPrefix = target.replace(/^(feishu|lark):/i, "");
|
|
30
|
-
return {
|
|
31
|
-
client,
|
|
32
|
-
receiveId,
|
|
33
|
-
receiveIdType: resolveReceiveIdType(withoutProviderPrefix),
|
|
34
|
-
};
|
|
35
|
-
}
|