@openclaw/msteams 2026.3.2 → 2026.3.8-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/CHANGELOG.md +24 -0
- package/index.ts +2 -2
- package/package.json +6 -1
- package/src/attachments/graph.ts +1 -1
- package/src/attachments/payload.ts +1 -1
- package/src/attachments/remote-media.ts +1 -1
- package/src/attachments/shared.ts +2 -2
- package/src/attachments.test.ts +1 -1
- package/src/channel.directory.test.ts +1 -1
- package/src/channel.ts +95 -101
- package/src/directory-live.ts +1 -1
- package/src/file-lock.ts +1 -1
- package/src/graph.ts +1 -1
- package/src/media-helpers.ts +1 -1
- package/src/messenger.test.ts +16 -19
- package/src/messenger.ts +1 -1
- package/src/monitor-handler/message-handler.authz.test.ts +68 -12
- package/src/monitor-handler/message-handler.ts +56 -53
- package/src/monitor-handler.file-consent.test.ts +1 -1
- package/src/monitor-handler.ts +1 -1
- package/src/monitor.lifecycle.test.ts +9 -3
- package/src/monitor.ts +1 -1
- package/src/onboarding.ts +23 -47
- package/src/outbound.test.ts +131 -0
- package/src/outbound.ts +1 -1
- package/src/policy.test.ts +1 -1
- package/src/policy.ts +9 -10
- package/src/probe.test.ts +1 -1
- package/src/probe.ts +6 -2
- package/src/reply-dispatcher.ts +1 -1
- package/src/resolve-allowlist.test.ts +78 -0
- package/src/resolve-allowlist.ts +70 -79
- package/src/runtime.ts +5 -13
- package/src/secret-input.ts +1 -1
- package/src/send-context.ts +1 -1
- package/src/send.test.ts +2 -2
- package/src/send.ts +42 -43
- package/src/store-fs.ts +1 -1
- package/src/test-runtime.ts +1 -1
- package/src/token.test.ts +1 -1
- package/src/token.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.3.8-beta.1
|
|
4
|
+
|
|
5
|
+
### Changes
|
|
6
|
+
|
|
7
|
+
- Version alignment with core OpenClaw release numbers.
|
|
8
|
+
|
|
9
|
+
## 2026.3.8
|
|
10
|
+
|
|
11
|
+
### Changes
|
|
12
|
+
|
|
13
|
+
- Version alignment with core OpenClaw release numbers.
|
|
14
|
+
|
|
15
|
+
## 2026.3.7
|
|
16
|
+
|
|
17
|
+
### Changes
|
|
18
|
+
|
|
19
|
+
- Version alignment with core OpenClaw release numbers.
|
|
20
|
+
|
|
21
|
+
## 2026.3.3
|
|
22
|
+
|
|
23
|
+
### Changes
|
|
24
|
+
|
|
25
|
+
- Version alignment with core OpenClaw release numbers.
|
|
26
|
+
|
|
3
27
|
## 2026.3.2
|
|
4
28
|
|
|
5
29
|
### Changes
|
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
-
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/msteams";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk/msteams";
|
|
3
3
|
import { msteamsPlugin } from "./src/channel.js";
|
|
4
4
|
import { setMSTeamsRuntime } from "./src/runtime.js";
|
|
5
5
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/msteams",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.8-beta.1",
|
|
4
4
|
"description": "OpenClaw Microsoft Teams channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"npmSpec": "@openclaw/msteams",
|
|
28
28
|
"localPath": "extensions/msteams",
|
|
29
29
|
"defaultChoice": "npm"
|
|
30
|
+
},
|
|
31
|
+
"releaseChecks": {
|
|
32
|
+
"rootDependencyMirrorAllowlist": [
|
|
33
|
+
"@microsoft/agents-hosting"
|
|
34
|
+
]
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
}
|
package/src/attachments/graph.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk";
|
|
1
|
+
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/msteams";
|
|
2
2
|
import { getMSTeamsRuntime } from "../runtime.js";
|
|
3
3
|
import { downloadMSTeamsAttachments } from "./download.js";
|
|
4
4
|
import { downloadAndStoreMSTeamsRemoteMedia } from "./remote-media.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SsrFPolicy } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { SsrFPolicy } from "openclaw/plugin-sdk/msteams";
|
|
2
2
|
import { getMSTeamsRuntime } from "../runtime.js";
|
|
3
3
|
import { inferPlaceholder } from "./shared.js";
|
|
4
4
|
import type { MSTeamsInboundMedia } from "./types.js";
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
isHttpsUrlAllowedByHostnameSuffixAllowlist,
|
|
5
5
|
isPrivateIpAddress,
|
|
6
6
|
normalizeHostnameSuffixAllowlist,
|
|
7
|
-
} from "openclaw/plugin-sdk";
|
|
8
|
-
import type { SsrFPolicy } from "openclaw/plugin-sdk";
|
|
7
|
+
} from "openclaw/plugin-sdk/msteams";
|
|
8
|
+
import type { SsrFPolicy } from "openclaw/plugin-sdk/msteams";
|
|
9
9
|
import type { MSTeamsAttachmentLike } from "./types.js";
|
|
10
10
|
|
|
11
11
|
type InlineImageCandidate =
|
package/src/attachments.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginRuntime, SsrFPolicy } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { PluginRuntime, SsrFPolicy } from "openclaw/plugin-sdk/msteams";
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { createPluginRuntimeMock } from "../../test-utils/plugin-runtime-mock.js";
|
|
4
4
|
import {
|
package/src/channel.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import type { ChannelMessageActionName, ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
1
|
import {
|
|
3
|
-
|
|
2
|
+
collectAllowlistProviderRestrictSendersWarnings,
|
|
3
|
+
formatAllowFromLowercase,
|
|
4
|
+
} from "openclaw/plugin-sdk/compat";
|
|
5
|
+
import type {
|
|
6
|
+
ChannelMessageActionName,
|
|
7
|
+
ChannelPlugin,
|
|
8
|
+
OpenClawConfig,
|
|
9
|
+
} from "openclaw/plugin-sdk/msteams";
|
|
10
|
+
import {
|
|
11
|
+
buildProbeChannelStatusSummary,
|
|
12
|
+
buildRuntimeAccountStatusSnapshot,
|
|
4
13
|
buildChannelConfigSchema,
|
|
5
14
|
createDefaultChannelRuntimeState,
|
|
6
15
|
DEFAULT_ACCOUNT_ID,
|
|
7
16
|
MSTeamsConfigSchema,
|
|
8
17
|
PAIRING_APPROVED_MESSAGE,
|
|
9
|
-
|
|
10
|
-
resolveDefaultGroupPolicy,
|
|
11
|
-
} from "openclaw/plugin-sdk";
|
|
18
|
+
} from "openclaw/plugin-sdk/msteams";
|
|
12
19
|
import { listMSTeamsDirectoryGroupsLive, listMSTeamsDirectoryPeersLive } from "./directory-live.js";
|
|
13
20
|
import { msteamsOnboardingAdapter } from "./onboarding.js";
|
|
14
21
|
import { msteamsOutbound } from "./outbound.js";
|
|
@@ -120,27 +127,20 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
|
|
120
127
|
configured: account.configured,
|
|
121
128
|
}),
|
|
122
129
|
resolveAllowFrom: ({ cfg }) => cfg.channels?.msteams?.allowFrom ?? [],
|
|
123
|
-
formatAllowFrom: ({ allowFrom }) =>
|
|
124
|
-
allowFrom
|
|
125
|
-
.map((entry) => String(entry).trim())
|
|
126
|
-
.filter(Boolean)
|
|
127
|
-
.map((entry) => entry.toLowerCase()),
|
|
130
|
+
formatAllowFrom: ({ allowFrom }) => formatAllowFromLowercase({ allowFrom }),
|
|
128
131
|
resolveDefaultTo: ({ cfg }) => cfg.channels?.msteams?.defaultTo?.trim() || undefined,
|
|
129
132
|
},
|
|
130
133
|
security: {
|
|
131
134
|
collectWarnings: ({ cfg }) => {
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
return collectAllowlistProviderRestrictSendersWarnings({
|
|
136
|
+
cfg,
|
|
134
137
|
providerConfigPresent: cfg.channels?.msteams !== undefined,
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
configuredGroupPolicy: cfg.channels?.msteams?.groupPolicy,
|
|
139
|
+
surface: "MS Teams groups",
|
|
140
|
+
openScope: "any member",
|
|
141
|
+
groupPolicyPath: "channels.msteams.groupPolicy",
|
|
142
|
+
groupAllowFromPath: "channels.msteams.groupAllowFrom",
|
|
137
143
|
});
|
|
138
|
-
if (groupPolicy !== "open") {
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
return [
|
|
142
|
-
`- MS Teams groups: groupPolicy="open" allows any member to trigger (mention-gated). Set channels.msteams.groupPolicy="allowlist" + channels.msteams.groupAllowFrom to restrict senders.`,
|
|
143
|
-
];
|
|
144
144
|
},
|
|
145
145
|
},
|
|
146
146
|
setup: {
|
|
@@ -246,11 +246,43 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
|
|
246
246
|
name: undefined as string | undefined,
|
|
247
247
|
note: undefined as string | undefined,
|
|
248
248
|
}));
|
|
249
|
+
type ResolveTargetResultEntry = (typeof results)[number];
|
|
250
|
+
type PendingTargetEntry = { input: string; query: string; index: number };
|
|
249
251
|
|
|
250
252
|
const stripPrefix = (value: string) => normalizeMSTeamsUserInput(value);
|
|
253
|
+
const markPendingLookupFailed = (pending: PendingTargetEntry[]) => {
|
|
254
|
+
pending.forEach(({ index }) => {
|
|
255
|
+
const entry = results[index];
|
|
256
|
+
if (entry) {
|
|
257
|
+
entry.note = "lookup failed";
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
const resolvePending = async <T>(
|
|
262
|
+
pending: PendingTargetEntry[],
|
|
263
|
+
resolveEntries: (entries: string[]) => Promise<T[]>,
|
|
264
|
+
applyResolvedEntry: (target: ResolveTargetResultEntry, entry: T) => void,
|
|
265
|
+
) => {
|
|
266
|
+
if (pending.length === 0) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const resolved = await resolveEntries(pending.map((entry) => entry.query));
|
|
271
|
+
resolved.forEach((entry, idx) => {
|
|
272
|
+
const target = results[pending[idx]?.index ?? -1];
|
|
273
|
+
if (!target) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
applyResolvedEntry(target, entry);
|
|
277
|
+
});
|
|
278
|
+
} catch (err) {
|
|
279
|
+
runtime.error?.(`msteams resolve failed: ${String(err)}`);
|
|
280
|
+
markPendingLookupFailed(pending);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
251
283
|
|
|
252
284
|
if (kind === "user") {
|
|
253
|
-
const pending:
|
|
285
|
+
const pending: PendingTargetEntry[] = [];
|
|
254
286
|
results.forEach((entry, index) => {
|
|
255
287
|
const trimmed = entry.input.trim();
|
|
256
288
|
if (!trimmed) {
|
|
@@ -266,37 +298,21 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
|
|
266
298
|
pending.push({ input: entry.input, query: cleaned, index });
|
|
267
299
|
});
|
|
268
300
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
target.resolved = entry.resolved;
|
|
281
|
-
target.id = entry.id;
|
|
282
|
-
target.name = entry.name;
|
|
283
|
-
target.note = entry.note;
|
|
284
|
-
});
|
|
285
|
-
} catch (err) {
|
|
286
|
-
runtime.error?.(`msteams resolve failed: ${String(err)}`);
|
|
287
|
-
pending.forEach(({ index }) => {
|
|
288
|
-
const entry = results[index];
|
|
289
|
-
if (entry) {
|
|
290
|
-
entry.note = "lookup failed";
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
}
|
|
301
|
+
await resolvePending(
|
|
302
|
+
pending,
|
|
303
|
+
(entries) => resolveMSTeamsUserAllowlist({ cfg, entries }),
|
|
304
|
+
(target, entry) => {
|
|
305
|
+
target.resolved = entry.resolved;
|
|
306
|
+
target.id = entry.id;
|
|
307
|
+
target.name = entry.name;
|
|
308
|
+
target.note = entry.note;
|
|
309
|
+
},
|
|
310
|
+
);
|
|
295
311
|
|
|
296
312
|
return results;
|
|
297
313
|
}
|
|
298
314
|
|
|
299
|
-
const pending:
|
|
315
|
+
const pending: PendingTargetEntry[] = [];
|
|
300
316
|
results.forEach((entry, index) => {
|
|
301
317
|
const trimmed = entry.input.trim();
|
|
302
318
|
if (!trimmed) {
|
|
@@ -319,48 +335,32 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
|
|
319
335
|
pending.push({ input: entry.input, query, index });
|
|
320
336
|
});
|
|
321
337
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
target.note = "team id";
|
|
349
|
-
}
|
|
350
|
-
if (entry.note) {
|
|
351
|
-
target.note = entry.note;
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
} catch (err) {
|
|
355
|
-
runtime.error?.(`msteams resolve failed: ${String(err)}`);
|
|
356
|
-
pending.forEach(({ index }) => {
|
|
357
|
-
const entry = results[index];
|
|
358
|
-
if (entry) {
|
|
359
|
-
entry.note = "lookup failed";
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
338
|
+
await resolvePending(
|
|
339
|
+
pending,
|
|
340
|
+
(entries) => resolveMSTeamsChannelAllowlist({ cfg, entries }),
|
|
341
|
+
(target, entry) => {
|
|
342
|
+
if (!entry.resolved || !entry.teamId) {
|
|
343
|
+
target.resolved = false;
|
|
344
|
+
target.note = entry.note;
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
target.resolved = true;
|
|
348
|
+
if (entry.channelId) {
|
|
349
|
+
target.id = `${entry.teamId}/${entry.channelId}`;
|
|
350
|
+
target.name =
|
|
351
|
+
entry.channelName && entry.teamName
|
|
352
|
+
? `${entry.teamName}/${entry.channelName}`
|
|
353
|
+
: (entry.channelName ?? entry.teamName);
|
|
354
|
+
} else {
|
|
355
|
+
target.id = entry.teamId;
|
|
356
|
+
target.name = entry.teamName;
|
|
357
|
+
target.note = "team id";
|
|
358
|
+
}
|
|
359
|
+
if (entry.note) {
|
|
360
|
+
target.note = entry.note;
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
);
|
|
364
364
|
|
|
365
365
|
return results;
|
|
366
366
|
},
|
|
@@ -425,23 +425,17 @@ export const msteamsPlugin: ChannelPlugin<ResolvedMSTeamsAccount> = {
|
|
|
425
425
|
outbound: msteamsOutbound,
|
|
426
426
|
status: {
|
|
427
427
|
defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID, { port: null }),
|
|
428
|
-
buildChannelSummary: ({ snapshot }) =>
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
lastProbeAt: snapshot.lastProbeAt ?? null,
|
|
433
|
-
}),
|
|
428
|
+
buildChannelSummary: ({ snapshot }) =>
|
|
429
|
+
buildProbeChannelStatusSummary(snapshot, {
|
|
430
|
+
port: snapshot.port ?? null,
|
|
431
|
+
}),
|
|
434
432
|
probeAccount: async ({ cfg }) => await probeMSTeams(cfg.channels?.msteams),
|
|
435
433
|
buildAccountSnapshot: ({ account, runtime, probe }) => ({
|
|
436
434
|
accountId: account.accountId,
|
|
437
435
|
enabled: account.enabled,
|
|
438
436
|
configured: account.configured,
|
|
439
|
-
|
|
440
|
-
lastStartAt: runtime?.lastStartAt ?? null,
|
|
441
|
-
lastStopAt: runtime?.lastStopAt ?? null,
|
|
442
|
-
lastError: runtime?.lastError ?? null,
|
|
437
|
+
...buildRuntimeAccountStatusSnapshot({ runtime, probe }),
|
|
443
438
|
port: runtime?.port ?? null,
|
|
444
|
-
probe,
|
|
445
439
|
}),
|
|
446
440
|
},
|
|
447
441
|
gateway: {
|
package/src/directory-live.ts
CHANGED
package/src/file-lock.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { withFileLock } from "openclaw/plugin-sdk";
|
|
1
|
+
export { withFileLock } from "openclaw/plugin-sdk/msteams";
|
package/src/graph.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MSTeamsConfig } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { MSTeamsConfig } from "openclaw/plugin-sdk/msteams";
|
|
2
2
|
import { GRAPH_ROOT } from "./attachments/shared.js";
|
|
3
3
|
import { loadMSTeamsSdkWithAuth } from "./sdk.js";
|
|
4
4
|
import { readAccessToken } from "./token-response.js";
|
package/src/media-helpers.ts
CHANGED
package/src/messenger.test.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { SILENT_REPLY_TOKEN, type PluginRuntime } from "openclaw/plugin-sdk";
|
|
4
|
+
import { SILENT_REPLY_TOKEN, type PluginRuntime } from "openclaw/plugin-sdk/msteams";
|
|
5
5
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
6
|
import { createPluginRuntimeMock } from "../../test-utils/plugin-runtime-mock.js";
|
|
7
7
|
import type { StoredConversationReference } from "./conversation-store.js";
|
|
@@ -72,6 +72,17 @@ const createRecordedSendActivity = (
|
|
|
72
72
|
};
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
+
const REVOCATION_ERROR = "Cannot perform 'set' on a proxy that has been revoked";
|
|
76
|
+
|
|
77
|
+
const createFallbackAdapter = (proactiveSent: string[]): MSTeamsAdapter => ({
|
|
78
|
+
continueConversation: async (_appId, _reference, logic) => {
|
|
79
|
+
await logic({
|
|
80
|
+
sendActivity: createRecordedSendActivity(proactiveSent),
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
process: async () => {},
|
|
84
|
+
});
|
|
85
|
+
|
|
75
86
|
describe("msteams messenger", () => {
|
|
76
87
|
beforeEach(() => {
|
|
77
88
|
setMSTeamsRuntime(runtimeStub);
|
|
@@ -297,18 +308,11 @@ describe("msteams messenger", () => {
|
|
|
297
308
|
|
|
298
309
|
const ctx = {
|
|
299
310
|
sendActivity: async () => {
|
|
300
|
-
throw new TypeError(
|
|
311
|
+
throw new TypeError(REVOCATION_ERROR);
|
|
301
312
|
},
|
|
302
313
|
};
|
|
303
314
|
|
|
304
|
-
const adapter
|
|
305
|
-
continueConversation: async (_appId, _reference, logic) => {
|
|
306
|
-
await logic({
|
|
307
|
-
sendActivity: createRecordedSendActivity(proactiveSent),
|
|
308
|
-
});
|
|
309
|
-
},
|
|
310
|
-
process: async () => {},
|
|
311
|
-
};
|
|
315
|
+
const adapter = createFallbackAdapter(proactiveSent);
|
|
312
316
|
|
|
313
317
|
const ids = await sendMSTeamsMessages({
|
|
314
318
|
replyStyle: "thread",
|
|
@@ -338,18 +342,11 @@ describe("msteams messenger", () => {
|
|
|
338
342
|
threadSent.push(content);
|
|
339
343
|
return { id: `id:${content}` };
|
|
340
344
|
}
|
|
341
|
-
throw new TypeError(
|
|
345
|
+
throw new TypeError(REVOCATION_ERROR);
|
|
342
346
|
},
|
|
343
347
|
};
|
|
344
348
|
|
|
345
|
-
const adapter
|
|
346
|
-
continueConversation: async (_appId, _reference, logic) => {
|
|
347
|
-
await logic({
|
|
348
|
-
sendActivity: createRecordedSendActivity(proactiveSent),
|
|
349
|
-
});
|
|
350
|
-
},
|
|
351
|
-
process: async () => {},
|
|
352
|
-
};
|
|
349
|
+
const adapter = createFallbackAdapter(proactiveSent);
|
|
353
350
|
|
|
354
351
|
const ids = await sendMSTeamsMessages({
|
|
355
352
|
replyStyle: "thread",
|
package/src/messenger.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type ReplyPayload,
|
|
8
8
|
SILENT_REPLY_TOKEN,
|
|
9
9
|
sleep,
|
|
10
|
-
} from "openclaw/plugin-sdk";
|
|
10
|
+
} from "openclaw/plugin-sdk/msteams";
|
|
11
11
|
import type { MSTeamsAccessTokenProvider } from "./attachments/types.js";
|
|
12
12
|
import type { StoredConversationReference } from "./conversation-store.js";
|
|
13
13
|
import { classifyMSTeamsSendError } from "./errors.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { OpenClawConfig, PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { OpenClawConfig, PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk/msteams";
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
import type { MSTeamsMessageHandlerDeps } from "../monitor-handler.js";
|
|
4
4
|
import { setMSTeamsRuntime } from "../runtime.js";
|
|
5
5
|
import { createMSTeamsMessageHandler } from "./message-handler.js";
|
|
6
6
|
|
|
7
7
|
describe("msteams monitor handler authz", () => {
|
|
8
|
-
|
|
8
|
+
function createDeps(cfg: OpenClawConfig) {
|
|
9
9
|
const readAllowFromStore = vi.fn(async () => ["attacker-aad"]);
|
|
10
10
|
setMSTeamsRuntime({
|
|
11
11
|
logging: { shouldLogVerbose: () => false },
|
|
@@ -35,16 +35,7 @@ describe("msteams monitor handler authz", () => {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const deps: MSTeamsMessageHandlerDeps = {
|
|
38
|
-
cfg
|
|
39
|
-
channels: {
|
|
40
|
-
msteams: {
|
|
41
|
-
dmPolicy: "pairing",
|
|
42
|
-
allowFrom: [],
|
|
43
|
-
groupPolicy: "allowlist",
|
|
44
|
-
groupAllowFrom: [],
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
} as OpenClawConfig,
|
|
38
|
+
cfg,
|
|
48
39
|
runtime: { error: vi.fn() } as unknown as RuntimeEnv,
|
|
49
40
|
appId: "test-app",
|
|
50
41
|
adapter: {} as MSTeamsMessageHandlerDeps["adapter"],
|
|
@@ -65,6 +56,21 @@ describe("msteams monitor handler authz", () => {
|
|
|
65
56
|
} as unknown as MSTeamsMessageHandlerDeps["log"],
|
|
66
57
|
};
|
|
67
58
|
|
|
59
|
+
return { conversationStore, deps, readAllowFromStore };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
it("does not treat DM pairing-store entries as group allowlist entries", async () => {
|
|
63
|
+
const { conversationStore, deps, readAllowFromStore } = createDeps({
|
|
64
|
+
channels: {
|
|
65
|
+
msteams: {
|
|
66
|
+
dmPolicy: "pairing",
|
|
67
|
+
allowFrom: [],
|
|
68
|
+
groupPolicy: "allowlist",
|
|
69
|
+
groupAllowFrom: [],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
} as OpenClawConfig);
|
|
73
|
+
|
|
68
74
|
const handler = createMSTeamsMessageHandler(deps);
|
|
69
75
|
await handler({
|
|
70
76
|
activity: {
|
|
@@ -96,4 +102,54 @@ describe("msteams monitor handler authz", () => {
|
|
|
96
102
|
});
|
|
97
103
|
expect(conversationStore.upsert).not.toHaveBeenCalled();
|
|
98
104
|
});
|
|
105
|
+
|
|
106
|
+
it("does not widen sender auth when only a teams route allowlist is configured", async () => {
|
|
107
|
+
const { conversationStore, deps } = createDeps({
|
|
108
|
+
channels: {
|
|
109
|
+
msteams: {
|
|
110
|
+
dmPolicy: "pairing",
|
|
111
|
+
allowFrom: [],
|
|
112
|
+
groupPolicy: "allowlist",
|
|
113
|
+
groupAllowFrom: [],
|
|
114
|
+
teams: {
|
|
115
|
+
team123: {
|
|
116
|
+
channels: {
|
|
117
|
+
"19:group@thread.tacv2": { requireMention: false },
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
} as OpenClawConfig);
|
|
124
|
+
|
|
125
|
+
const handler = createMSTeamsMessageHandler(deps);
|
|
126
|
+
await handler({
|
|
127
|
+
activity: {
|
|
128
|
+
id: "msg-1",
|
|
129
|
+
type: "message",
|
|
130
|
+
text: "hello",
|
|
131
|
+
from: {
|
|
132
|
+
id: "attacker-id",
|
|
133
|
+
aadObjectId: "attacker-aad",
|
|
134
|
+
name: "Attacker",
|
|
135
|
+
},
|
|
136
|
+
recipient: {
|
|
137
|
+
id: "bot-id",
|
|
138
|
+
name: "Bot",
|
|
139
|
+
},
|
|
140
|
+
conversation: {
|
|
141
|
+
id: "19:group@thread.tacv2",
|
|
142
|
+
conversationType: "groupChat",
|
|
143
|
+
},
|
|
144
|
+
channelData: {
|
|
145
|
+
team: { id: "team123", name: "Team 123" },
|
|
146
|
+
channel: { name: "General" },
|
|
147
|
+
},
|
|
148
|
+
attachments: [],
|
|
149
|
+
},
|
|
150
|
+
sendActivity: vi.fn(async () => undefined),
|
|
151
|
+
} as unknown as Parameters<typeof handler>[0]);
|
|
152
|
+
|
|
153
|
+
expect(conversationStore.upsert).not.toHaveBeenCalled();
|
|
154
|
+
});
|
|
99
155
|
});
|