From 42d6cf66d3508ece23822cd693c141dc0b35ea19 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 27 May 2026 03:08:41 +0100 Subject: [PATCH] fix(media): require staged sandbox media refs --- src/agents/sandbox-media-paths.test.ts | 24 ++++++++++++++++++++++++ src/agents/sandbox-media-paths.ts | 9 +++++++++ 2 files changed, 33 insertions(+) diff --git a/src/agents/sandbox-media-paths.test.ts b/src/agents/sandbox-media-paths.test.ts index 90e678f07b7..ae766f98473 100644 --- a/src/agents/sandbox-media-paths.test.ts +++ b/src/agents/sandbox-media-paths.test.ts @@ -49,18 +49,24 @@ describe("createSandboxBridgeReadFile", () => { relativePath: filePath, containerPath: `/sandbox/${filePath}`, })); + const stat = vi.fn(async () => ({ type: "file", size: 1, mtimeMs: 1 })); const resolved = await resolveSandboxedBridgeMediaPath({ sandbox: { root: "/tmp/sandbox-root", bridge: { resolvePath, + stat, } as unknown as SandboxFsBridge, }, mediaPath: "media://inbound/photo.png", inboundFallbackDir: "media/inbound", }); + expect(stat).toHaveBeenCalledWith({ + filePath: "media/inbound/photo.png", + cwd: "/tmp/sandbox-root", + }); expect(resolvePath).toHaveBeenCalledWith({ filePath: "media/inbound/photo.png", cwd: "/tmp/sandbox-root", @@ -70,4 +76,22 @@ describe("createSandboxBridgeReadFile", () => { rewrittenFrom: "media://inbound/photo.png", }); }); + + it("rejects missing staged inbound media URIs before direct sandbox resolution", async () => { + const resolvePath = vi.fn(); + await expect( + resolveSandboxedBridgeMediaPath({ + sandbox: { + root: "/tmp/sandbox-root", + bridge: { + resolvePath, + stat: vi.fn(async () => null), + } as unknown as SandboxFsBridge, + }, + mediaPath: "media://inbound/missing.png", + inboundFallbackDir: "media/inbound", + }), + ).rejects.toThrow("Sandbox media reference is not staged: media://inbound/missing.png"); + expect(resolvePath).not.toHaveBeenCalled(); + }); }); diff --git a/src/agents/sandbox-media-paths.ts b/src/agents/sandbox-media-paths.ts index 3fbc95553d1..479691e9543 100644 --- a/src/agents/sandbox-media-paths.ts +++ b/src/agents/sandbox-media-paths.ts @@ -31,6 +31,15 @@ export async function resolveSandboxedBridgeMediaPath(params: { : { resolved: params.mediaPath }; const filePath = normalizeFileUrl(mediaPathInfo.resolved); const rewrittenFrom = mediaPathInfo.rewrittenFrom; + if (rewrittenFrom) { + const stat = await params.sandbox.bridge.stat({ + filePath, + cwd: params.sandbox.root, + }); + if (!stat) { + throw new Error(`Sandbox media reference is not staged: ${rewrittenFrom}`); + } + } const enforceWorkspaceBoundary = async (hostPath: string) => { if (!params.sandbox.workspaceOnly) { return;