
























@@ -1,4 +1,13 @@
1-import { describe, expect, it } from "vitest";
1+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2+import type { OpenClawConfig } from "../../config/config.js";
3+import {
4+getActivePluginRegistry,
5+resetPluginRuntimeStateForTest,
6+setActivePluginRegistry,
7+} from "../../plugins/runtime.js";
8+import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
9+import { resolveCommandAuthorization } from "../command-auth.js";
10+import type { MsgContext } from "../templating.js";
211import {
312COMMAND,
413COMMAND_KILL,
@@ -7,8 +16,51 @@ import {
716resolveSubagentsAction,
817stopWithText,
918} from "./commands-subagents-dispatch.js";
19+import { handleSubagentsCommand } from "./commands-subagents.js";
1020import type { HandleCommandsParams } from "./commands-types.js";
112122+const handleSubagentsSpawnActionMock = vi.hoisted(() =>
23+vi.fn(async () => ({ shouldContinue: false, reply: { text: "spawned" } })),
24+);
25+const listControlledSubagentRunsMock = vi.hoisted(() => vi.fn(() => []));
26+27+vi.mock("./commands-subagents/action-spawn.js", () => ({
28+handleSubagentsSpawnAction: handleSubagentsSpawnActionMock,
29+}));
30+31+vi.mock("./commands-subagents-control.runtime.js", () => ({
32+listControlledSubagentRuns: listControlledSubagentRunsMock,
33+}));
34+35+const formatAllowFrom = ({ allowFrom }: { allowFrom: Array<string | number> }) =>
36+allowFrom.map((entry) => String(entry).trim()).filter(Boolean);
37+38+let previousPluginRegistry: ReturnType<typeof getActivePluginRegistry>;
39+40+function registerOwnerEnforcingTelegramPlugin() {
41+setActivePluginRegistry(
42+createTestRegistry([
43+{
44+pluginId: "telegram",
45+plugin: {
46+ ...createOutboundTestPlugin({
47+id: "telegram",
48+outbound: { deliveryMode: "direct" },
49+}),
50+commands: { enforceOwnerForCommands: true },
51+config: {
52+listAccountIds: () => ["default"],
53+resolveAccount: () => ({}),
54+resolveAllowFrom: () => ["*"],
55+ formatAllowFrom,
56+},
57+},
58+source: "test",
59+},
60+]),
61+);
62+}
63+1264function buildParams(
1365commandBody: string,
1466ctxOverrides?: Record<string, unknown>,
@@ -57,6 +109,19 @@ function buildParams(
57109}
5811059111describe("subagents command dispatch", () => {
112+beforeEach(() => {
113+previousPluginRegistry = getActivePluginRegistry();
114+vi.clearAllMocks();
115+});
116+117+afterEach(() => {
118+if (previousPluginRegistry) {
119+setActivePluginRegistry(previousPluginRegistry);
120+} else {
121+resetPluginRuntimeStateForTest();
122+}
123+});
124+60125it("prefers native command target session keys", () => {
61126const params = buildParams("/subagents list", {
62127CommandSource: "native",
@@ -112,4 +177,46 @@ describe("subagents command dispatch", () => {
112177reply: { text: "hello" },
113178});
114179});
180+181+it("rejects native spawn commands from non-owner senders when the plugin enforces owner-only commands", async () => {
182+registerOwnerEnforcingTelegramPlugin();
183+const cfg = {
184+commands: { allowFrom: { "*": ["*"] } },
185+channels: { telegram: { allowFrom: ["*"] } },
186+} as OpenClawConfig;
187+const ctx = {
188+Provider: "telegram",
189+Surface: "telegram",
190+ChatType: "group",
191+From: "telegram:999",
192+SenderId: "999",
193+CommandSource: "native",
194+SessionKey: "agent:main:telegram:slash-session",
195+CommandTargetSessionKey: "agent:main:telegram:target",
196+} as MsgContext;
197+const auth = resolveCommandAuthorization({
198+ ctx,
199+ cfg,
200+commandAuthorized: true,
201+});
202+const params = buildParams(
203+"/subagents spawn beta do the thing",
204+ctx as unknown as Record<string, unknown>,
205+);
206+params.cfg = cfg;
207+params.command.senderId = auth.senderId;
208+params.command.senderIsOwner = auth.senderIsOwner;
209+params.command.isAuthorizedSender = auth.isAuthorizedSender;
210+params.command.ownerList = auth.ownerList;
211+params.command.from = auth.from;
212+params.command.to = auth.to;
213+214+const result = await handleSubagentsCommand(params, true);
215+216+expect(auth.senderIsOwner).toBe(false);
217+expect(auth.isAuthorizedSender).toBe(false);
218+expect(result).toEqual({ shouldContinue: false });
219+expect(listControlledSubagentRunsMock).not.toHaveBeenCalled();
220+expect(handleSubagentsSpawnActionMock).not.toHaveBeenCalled();
221+});
115222});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。