

















@@ -7,6 +7,14 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
77import { OPENCLAW_CLI_ENV_VALUE } from "../infra/openclaw-exec-env.js";
88import type { ExtensionContext } from "./sessions/index.js";
9910+declare module "../plugins/hook-types.js" {
11+interface PluginHookChannelSenderContext {
12+unionId?: string;
13+}
14+}
15+16+const CHANNEL_CONTEXT_ENV_KEY = "OPENCLAW_CHANNEL_CONTEXT";
17+1018const mocks = vi.hoisted(() => ({
1119hookRunner: undefined as
1220| {
@@ -129,6 +137,31 @@ describe("exec resolve_exec_env hook wiring", () => {
129137mocks.spawnInputs.length = 0;
130138});
131139140+it("adds only channel identity env to gateway exec subprocesses", async () => {
141+const tool = createExecTool({
142+host: "auto",
143+security: "full",
144+ask: "off",
145+channelContext: {
146+sender: { id: "ou_1", unionId: "on_1" },
147+chat: { id: "oc_1" },
148+},
149+});
150+151+await tool.execute("call-channel-env", {
152+command: "echo ok",
153+yieldMs: 120_000,
154+});
155+156+expect(JSON.parse(mocks.gatewayParams[0]?.env[CHANNEL_CONTEXT_ENV_KEY] ?? "{}")).toEqual({
157+chat: { id: "oc_1" },
158+sender: { id: "ou_1" },
159+});
160+expect(mocks.spawnInputs[0]?.env?.[CHANNEL_CONTEXT_ENV_KEY]).toBe(
161+mocks.gatewayParams[0]?.env[CHANNEL_CONTEXT_ENV_KEY],
162+);
163+});
164+132165it("merges filtered plugin env into gateway execution and approval-visible requested env", async () => {
133166installResolveExecEnvHook({
134167EXISTING: "plugin",
@@ -146,6 +179,10 @@ describe("exec resolve_exec_env hook wiring", () => {
146179sessionKey: "agent:main:telegram:chat-1",
147180messageProvider: "telegram",
148181currentChannelId: "chat-1",
182+channelContext: {
183+sender: { id: "ou_1", unionId: "on_1" },
184+chat: { id: "oc_1" },
185+},
149186});
150187await tool.execute("call-1", {
151188command: "echo ok",
@@ -164,12 +201,22 @@ describe("exec resolve_exec_env hook wiring", () => {
164201sessionKey: "agent:main:telegram:chat-1",
165202messageProvider: "telegram",
166203channelId: "chat-1",
204+channelContext: {
205+sender: { id: "ou_1", unionId: "on_1" },
206+chat: { id: "oc_1" },
207+},
167208},
168209);
169-expect(mocks.gatewayParams[0]?.requestedEnv).toEqual({
210+expect(mocks.gatewayParams[0]?.requestedEnv).toMatchObject({
170211EXISTING: "plugin",
171212PLUGIN_SAFE: "yes",
172213});
214+expect(
215+JSON.parse(mocks.gatewayParams[0]?.requestedEnv?.[CHANNEL_CONTEXT_ENV_KEY] ?? "{}"),
216+).toEqual({
217+chat: { id: "oc_1" },
218+sender: { id: "ou_1" },
219+});
173220expect(mocks.gatewayParams[0]?.env).toMatchObject({
174221EXISTING: "plugin",
175222PLUGIN_SAFE: "yes",
@@ -194,20 +241,34 @@ describe("exec resolve_exec_env hook wiring", () => {
194241security: "full",
195242ask: "off",
196243sessionKey: "agent:main:main",
244+channelContext: {
245+sender: { id: "ou_node" },
246+chat: { id: "oc_node" },
247+},
197248});
198249await tool.execute("call-node", {
199250command: "echo ok",
200251env: { REQUEST_SAFE: "request" },
201252});
202253203-expect(mocks.nodeHostParams[0]?.requestedEnv).toEqual({
254+expect(mocks.nodeHostParams[0]?.requestedEnv).toMatchObject({
204255NODE_HOST_SAFE: "yes",
205256REQUEST_SAFE: "request",
206257});
207258expect(mocks.nodeHostParams[0]?.env).toMatchObject({
208259NODE_HOST_SAFE: "yes",
209260REQUEST_SAFE: "request",
210261});
262+expect(
263+JSON.parse(mocks.nodeHostParams[0]?.requestedEnv?.[CHANNEL_CONTEXT_ENV_KEY] ?? "{}"),
264+).toEqual({
265+chat: { id: "oc_node" },
266+sender: { id: "ou_node" },
267+});
268+expect(JSON.parse(mocks.nodeHostParams[0]?.env?.[CHANNEL_CONTEXT_ENV_KEY] ?? "{}")).toEqual({
269+chat: { id: "oc_node" },
270+sender: { id: "ou_node" },
271+});
211272expect(mocks.nodeHostParams[0]?.env).not.toHaveProperty("LD_PRELOAD");
212273});
213274此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。