From ff92e5650a896f149b642346abf176032ccefd58 Mon Sep 17 00:00:00 2001 From: Ozgur Polat Date: Thu, 29 Jan 2026 22:35:09 +0100 Subject: [PATCH] fix(sandbox): include containerWorkdir in sandboxInfo for rw access (#4171) --- CHANGELOG.md | 1 + ...ed-runner.buildembeddedsandboxinfo.test.ts | 70 +++++++++++++++++++ src/agents/pi-embedded-runner/sandbox-info.ts | 11 ++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5909c9899..e7bddf37c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Status: beta. ### Fixes - Discord: restore username directory lookup in target resolution. (#3131) Thanks @bonald. +- Sandbox: include containerWorkdir in sandboxInfo for rw access so agents see correct Docker mount paths. Fixes #4171. - Agents: align MiniMax base URL test expectation with default provider config. (#3131) Thanks @bonald. - Agents: prevent retries on oversized image errors and surface size limits. (#2871) Thanks @Suksham-sharma. - Agents: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94. diff --git a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts index 5cc37fc03..a1fc7e868 100644 --- a/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts +++ b/src/agents/pi-embedded-runner.buildembeddedsandboxinfo.test.ts @@ -143,6 +143,76 @@ describe("buildEmbeddedSandboxInfo", () => { hostBrowserAllowed: true, }); }); + it("includes containerWorkdir as agentWorkspaceMount for rw access", () => { + const sandbox = { + enabled: true, + sessionKey: "session:test", + workspaceDir: "/tmp/moltbot-sandbox", + agentWorkspaceDir: "/tmp/moltbot-workspace", + workspaceAccess: "rw", + containerName: "moltbot-sbx-test", + containerWorkdir: "/workspace", + docker: { + image: "moltbot-sandbox:bookworm-slim", + containerPrefix: "moltbot-sbx-", + workdir: "/workspace", + readOnlyRoot: true, + tmpfs: ["/tmp"], + network: "none", + user: "1000:1000", + capDrop: ["ALL"], + env: { LANG: "C.UTF-8" }, + }, + tools: { + allow: ["exec"], + deny: ["browser"], + }, + browserAllowHostControl: false, + } satisfies SandboxContext; + + expect(buildEmbeddedSandboxInfo(sandbox)).toEqual({ + enabled: true, + workspaceDir: "/tmp/moltbot-sandbox", + workspaceAccess: "rw", + agentWorkspaceMount: "/workspace", + hostBrowserAllowed: false, + }); + }); + it("includes /agent as agentWorkspaceMount for ro access", () => { + const sandbox = { + enabled: true, + sessionKey: "session:test", + workspaceDir: "/tmp/moltbot-sandbox", + agentWorkspaceDir: "/tmp/moltbot-workspace", + workspaceAccess: "ro", + containerName: "moltbot-sbx-test", + containerWorkdir: "/workspace", + docker: { + image: "moltbot-sandbox:bookworm-slim", + containerPrefix: "moltbot-sbx-", + workdir: "/workspace", + readOnlyRoot: true, + tmpfs: ["/tmp"], + network: "none", + user: "1000:1000", + capDrop: ["ALL"], + env: { LANG: "C.UTF-8" }, + }, + tools: { + allow: ["exec"], + deny: ["browser"], + }, + browserAllowHostControl: false, + } satisfies SandboxContext; + + expect(buildEmbeddedSandboxInfo(sandbox)).toEqual({ + enabled: true, + workspaceDir: "/tmp/moltbot-sandbox", + workspaceAccess: "ro", + agentWorkspaceMount: "/agent", + hostBrowserAllowed: false, + }); + }); it("includes elevated info when allowed", () => { const sandbox = { enabled: true, diff --git a/src/agents/pi-embedded-runner/sandbox-info.ts b/src/agents/pi-embedded-runner/sandbox-info.ts index a72797c9c..8032aba4b 100644 --- a/src/agents/pi-embedded-runner/sandbox-info.ts +++ b/src/agents/pi-embedded-runner/sandbox-info.ts @@ -8,11 +8,20 @@ export function buildEmbeddedSandboxInfo( ): EmbeddedSandboxInfo | undefined { if (!sandbox?.enabled) return undefined; const elevatedAllowed = Boolean(execElevated?.enabled && execElevated.allowed); + // For rw access, the agent workspace is mounted at containerWorkdir (typically /workspace). + // For ro access, the agent workspace is mounted read-only at /agent. + // For none access, there is no agent workspace mount. + const agentWorkspaceMount = + sandbox.workspaceAccess === "rw" + ? sandbox.containerWorkdir + : sandbox.workspaceAccess === "ro" + ? "/agent" + : undefined; return { enabled: true, workspaceDir: sandbox.workspaceDir, workspaceAccess: sandbox.workspaceAccess, - agentWorkspaceMount: sandbox.workspaceAccess === "ro" ? "/agent" : undefined, + agentWorkspaceMount, browserBridgeUrl: sandbox.browser?.bridgeUrl, browserNoVncUrl: sandbox.browser?.noVncUrl, hostBrowserAllowed: sandbox.browserAllowHostControl,