


























11/** Tests sandbox media staging for SCP remote-path inputs. */
2+import { EventEmitter } from "node:events";
23import fs from "node:fs/promises";
34import { basename, join } from "node:path";
45import { afterEach, describe, expect, it, vi } from "vitest";
@@ -151,4 +152,115 @@ describe("stageSandboxMedia scp remote paths", () => {
151152}
152153});
153154});
155+156+it("rewrites remote iMessage attachment metadata to the staged local cache path", async () => {
157+await withSandboxMediaTempHome("openclaw-triggers-", async (home) => {
158+const { cfg, workspaceDir, sessionKey } = createRemoteStageParams(home);
159+const remotePath = "/Users/demo/Library/Messages/Attachments/ab/cd/photo.jpg";
160+const { ctx, sessionCtx } = createRemoteContexts(remotePath);
161+ctx.MediaPaths = [remotePath];
162+sessionCtx.MediaPaths = [remotePath];
163+childProcessMocks.spawn.mockImplementation((_command, argsUnknown) => {
164+const args = argsUnknown as string[];
165+const localPath = args[args.length - 1];
166+const child = new EventEmitter() as EventEmitter & {
167+stderr: EventEmitter & { setEncoding: (_encoding: string) => void };
168+};
169+child.stderr = Object.assign(new EventEmitter(), {
170+setEncoding: () => undefined,
171+});
172+queueMicrotask(() => {
173+void fs.writeFile(localPath, "staged-image-bytes").then(() => {
174+child.emit("exit", 0);
175+});
176+});
177+return child;
178+});
179+180+const result = await stageSandboxMedia({
181+ ctx,
182+ sessionCtx,
183+ cfg,
184+ sessionKey,
185+ workspaceDir,
186+});
187+188+const stagedPath = join(
189+CONFIG_DIR,
190+"media",
191+"remote-cache",
192+slugifySessionKey(sessionKey),
193+basename(remotePath),
194+);
195+expect(result.staged.get(remotePath)).toBe(stagedPath);
196+expect(ctx.MediaPath).toBe(stagedPath);
197+expect(ctx.MediaPaths).toEqual([stagedPath]);
198+expect(ctx.MediaUrl).toBe(stagedPath);
199+expect(sessionCtx.MediaPath).toBe(stagedPath);
200+expect(sessionCtx.MediaPaths).toEqual([stagedPath]);
201+expect(sessionCtx.MediaUrl).toBe(stagedPath);
202+expect(await fs.readFile(stagedPath, "utf8")).toBe("staged-image-bytes");
203+await fs.rm(join(CONFIG_DIR, "media", "remote-cache", slugifySessionKey(sessionKey)), {
204+recursive: true,
205+force: true,
206+});
207+});
208+});
209+210+it("uses absolute remote cache paths in cache mode even when sandbox staging is available", async () => {
211+await withSandboxMediaTempHome("openclaw-triggers-", async (home) => {
212+const { cfg, workspaceDir, sessionKey } = createRemoteStageParams(home);
213+const sandboxWorkspace = join(home, "sandbox-workspace");
214+vi.mocked(sandboxMocks.ensureSandboxWorkspaceForSession).mockResolvedValue({
215+workspaceDir: sandboxWorkspace,
216+workspaceAccess: "workspace-write",
217+});
218+const remotePath = "/Users/demo/Library/Messages/Attachments/ab/cd/photo.jpg";
219+const { ctx, sessionCtx } = createRemoteContexts(remotePath);
220+ctx.MediaPaths = [remotePath];
221+sessionCtx.MediaPaths = [remotePath];
222+childProcessMocks.spawn.mockImplementation((_command, argsUnknown) => {
223+const args = argsUnknown as string[];
224+const localPath = args[args.length - 1];
225+const child = new EventEmitter() as EventEmitter & {
226+stderr: EventEmitter & { setEncoding: (_encoding: string) => void };
227+};
228+child.stderr = Object.assign(new EventEmitter(), {
229+setEncoding: () => undefined,
230+});
231+queueMicrotask(() => {
232+void fs.writeFile(localPath, "staged-image-bytes").then(() => {
233+child.emit("exit", 0);
234+});
235+});
236+return child;
237+});
238+239+const result = await stageSandboxMedia({
240+ ctx,
241+ sessionCtx,
242+ cfg,
243+ sessionKey,
244+ workspaceDir,
245+remoteMediaMode: "cache",
246+});
247+248+const stagedPath = join(
249+CONFIG_DIR,
250+"media",
251+"remote-cache",
252+slugifySessionKey(sessionKey),
253+basename(remotePath),
254+);
255+expect(result.staged.get(remotePath)).toBe(stagedPath);
256+expect(ctx.MediaPath).toBe(stagedPath);
257+expect(ctx.MediaPaths).toEqual([stagedPath]);
258+await expectPathMissing(join(sandboxWorkspace, "media", "inbound", basename(remotePath)));
259+expect(await fs.readFile(stagedPath, "utf8")).toBe("staged-image-bytes");
260+await fs.rm(join(CONFIG_DIR, "media", "remote-cache", slugifySessionKey(sessionKey)), {
261+recursive: true,
262+force: true,
263+});
264+});
265+});
154266});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。