

























@@ -1,71 +1,75 @@
11import { describe, expect, it } from "vitest";
2-import type { ChannelPlugin } from "../channels/plugins/types.js";
32import type { OpenClawConfig } from "../config/config.js";
3+import { stubAuditChannelPlugin } from "./audit-channel-test-helpers.js";
44import { collectChannelSecurityFindings } from "./audit-channel.js";
5566function stubSlackPlugin(params: {
77resolveAccount: (cfg: OpenClawConfig, accountId: string | null | undefined) => unknown;
88inspectAccount?: (cfg: OpenClawConfig, accountId: string | null | undefined) => unknown;
99isConfigured?: (account: unknown, cfg: OpenClawConfig) => boolean;
10-}): ChannelPlugin {
11-return {
10+}) {
11+return stubAuditChannelPlugin({
1212id: "slack",
13-meta: {
14-id: "slack",
15-label: "Slack",
16-selectionLabel: "Slack",
17-docsPath: "/docs/testing",
18-blurb: "test stub",
19-},
20-capabilities: {
21-chatTypes: ["direct", "group"],
22-},
13+label: "Slack",
2314commands: {
2415nativeCommandsAutoEnabled: false,
2516nativeSkillsAutoEnabled: false,
2617},
27-security: {
28-collectAuditFindings: async ({ account }) => {
29-const config =
30-(account as { config?: { slashCommand?: { enabled?: boolean }; allowFrom?: unknown } })
31-.config ?? {};
32-const slashCommandEnabled = config.slashCommand?.enabled === true;
33-const allowFrom =
34-Array.isArray(config.allowFrom) && config.allowFrom.length > 0 ? config.allowFrom : [];
35-if (!slashCommandEnabled || allowFrom.length > 0) {
36-return [];
37-}
38-return [
39-{
40-checkId: "channels.slack.commands.slash.no_allowlists",
41-severity: "warn" as const,
42-title: "Slack slash commands have no allowlists",
43-detail: "test stub",
44-},
45-];
46-},
18+collectAuditFindings: async ({ account }) => {
19+const config =
20+(account as { config?: { slashCommand?: { enabled?: boolean }; allowFrom?: unknown } })
21+.config ?? {};
22+const slashCommandEnabled = config.slashCommand?.enabled === true;
23+const allowFrom =
24+Array.isArray(config.allowFrom) && config.allowFrom.length > 0 ? config.allowFrom : [];
25+if (!slashCommandEnabled || allowFrom.length > 0) {
26+return [];
27+}
28+return [
29+{
30+checkId: "channels.slack.commands.slash.no_allowlists",
31+severity: "warn" as const,
32+title: "Slack slash commands have no allowlists",
33+detail: "test stub",
34+},
35+];
4736},
48-config: {
49-listAccountIds: () => ["default"],
50-inspectAccount:
51-params.inspectAccount ??
52-((cfg, accountId) => {
53-const resolvedAccountId =
54-typeof accountId === "string" && accountId ? accountId : "default";
55-const account = params.resolveAccount(cfg, resolvedAccountId) as
56-| { config?: Record<string, unknown> }
57-| undefined;
58-return {
59-accountId: resolvedAccountId,
60-enabled: true,
61-configured: true,
62-config: account?.config ?? {},
63-};
64-}),
65-resolveAccount: (cfg, accountId) => params.resolveAccount(cfg, accountId),
66-isEnabled: () => true,
67-isConfigured: (account, cfg) => params.isConfigured?.(account, cfg) ?? true,
37+ ...params,
38+});
39+}
40+41+function makeSlackHttpConfig(): OpenClawConfig {
42+return {
43+channels: {
44+slack: {
45+enabled: true,
46+mode: "http",
47+groupPolicy: "open",
48+slashCommand: { enabled: true },
49+},
6850},
51+} as OpenClawConfig;
52+}
53+54+function makeSlackInspection(
55+channel: unknown,
56+overrides: {
57+enabled?: boolean;
58+configured?: boolean;
59+botTokenStatus?: string;
60+signingSecretStatus?: string;
61+},
62+) {
63+return {
64+accountId: "default",
65+enabled: overrides.enabled ?? true,
66+configured: overrides.configured ?? true,
67+mode: "http",
68+botTokenSource: "config",
69+botTokenStatus: overrides.botTokenStatus ?? "configured_unavailable",
70+signingSecretSource: "config",
71+signingSecretStatus: overrides.signingSecretStatus ?? "configured_unavailable",
72+config: channel,
6973};
7074}
7175@@ -74,109 +78,42 @@ describe("security audit channel source-config fallback slack", () => {
7478const cases = [
7579{
7680name: "slack resolved inspection only exposes signingSecret status",
77-sourceConfig: {
78-channels: {
79-slack: {
80-enabled: true,
81-mode: "http",
82-groupPolicy: "open",
83-slashCommand: { enabled: true },
84-},
85-},
86-} as OpenClawConfig,
87-resolvedConfig: {
88-channels: {
89-slack: {
90-enabled: true,
91-mode: "http",
92-groupPolicy: "open",
93-slashCommand: { enabled: true },
94-},
95-},
96-} as OpenClawConfig,
81+sourceConfig: makeSlackHttpConfig(),
82+resolvedConfig: makeSlackHttpConfig(),
9783plugin: (sourceConfig: OpenClawConfig) =>
9884stubSlackPlugin({
9985inspectAccount: (cfg) => {
10086const channel = cfg.channels?.slack ?? {};
10187if (cfg === sourceConfig) {
102-return {
103-accountId: "default",
88+return makeSlackInspection(channel, {
10489enabled: false,
105-configured: true,
106-mode: "http",
107-botTokenSource: "config",
108-botTokenStatus: "configured_unavailable",
109-signingSecretSource: "config",
110-signingSecretStatus: "configured_unavailable",
111-config: channel,
112-};
90+});
11391}
114-return {
115-accountId: "default",
116-enabled: true,
117-configured: true,
118-mode: "http",
119-botTokenSource: "config",
92+return makeSlackInspection(channel, {
12093botTokenStatus: "available",
121-signingSecretSource: "config",
12294signingSecretStatus: "available",
123-config: channel,
124-};
95+});
12596},
12697resolveAccount: (cfg) => ({ config: cfg.channels?.slack ?? {} }),
12798isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
12899}),
129100},
130101{
131102name: "slack source config still wins when resolved inspection is unconfigured",
132-sourceConfig: {
133-channels: {
134-slack: {
135-enabled: true,
136-mode: "http",
137-groupPolicy: "open",
138-slashCommand: { enabled: true },
139-},
140-},
141-} as OpenClawConfig,
142-resolvedConfig: {
143-channels: {
144-slack: {
145-enabled: true,
146-mode: "http",
147-groupPolicy: "open",
148-slashCommand: { enabled: true },
149-},
150-},
151-} as OpenClawConfig,
103+sourceConfig: makeSlackHttpConfig(),
104+resolvedConfig: makeSlackHttpConfig(),
152105plugin: (sourceConfig: OpenClawConfig) =>
153106stubSlackPlugin({
154107inspectAccount: (cfg) => {
155108const channel = cfg.channels?.slack ?? {};
156109if (cfg === sourceConfig) {
157-return {
158-accountId: "default",
159-enabled: true,
160-configured: true,
161-mode: "http",
162-botTokenSource: "config",
163-botTokenStatus: "configured_unavailable",
164-signingSecretSource: "config",
165-signingSecretStatus: "configured_unavailable",
166-config: channel,
167-};
110+return makeSlackInspection(channel, {});
168111}
169-return {
170-accountId: "default",
171-enabled: true,
112+return makeSlackInspection(channel, {
172113configured: false,
173-mode: "http",
174-botTokenSource: "config",
175114botTokenStatus: "available",
176-signingSecretSource: "config",
177115signingSecretStatus: "missing",
178-config: channel,
179-};
116+});
180117},
181118resolveAccount: (cfg) => ({ config: cfg.channels?.slack ?? {} }),
182119isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。