|
5 | 5 | createSandbox, |
6 | 6 | createSandboxFsBridge, |
7 | 7 | createSeededSandboxFsBridge, |
| 8 | + getDockerScript, |
8 | 9 | getScriptsFromCalls, |
9 | 10 | installFsBridgeTestHarness, |
10 | 11 | mockedExecDockerRaw, |
@@ -140,6 +141,35 @@ describe("sandbox fs bridge shell compatibility", () => { |
140 | 141 | expect(scripts.some((script) => script.includes("os.replace("))).toBe(true); |
141 | 142 | }); |
142 | 143 |
|
| 144 | + it("surfaces actionable guidance when sandbox python3 is missing", async () => { |
| 145 | + const bridge = createSandboxFsBridge({ sandbox: createSandbox() }); |
| 146 | + const baseImpl = mockedExecDockerRaw.getMockImplementation(); |
| 147 | + mockedExecDockerRaw.mockImplementation(async (...callArgs) => { |
| 148 | + const args = callArgs[0] as string[]; |
| 149 | + if (getDockerScript(args).includes("operation = sys.argv[1]")) { |
| 150 | + const message = "moltbot-sandbox-fs: 2: python3: not found"; |
| 151 | + const err = Object.assign(new Error(message), { |
| 152 | + code: 127, |
| 153 | + stdout: Buffer.alloc(0), |
| 154 | + stderr: Buffer.from(message), |
| 155 | + }); |
| 156 | + throw err; |
| 157 | + } |
| 158 | + if (baseImpl) { |
| 159 | + return await baseImpl(...callArgs); |
| 160 | + } |
| 161 | + return { |
| 162 | + stdout: Buffer.alloc(0), |
| 163 | + stderr: Buffer.alloc(0), |
| 164 | + code: 0, |
| 165 | + }; |
| 166 | + }); |
| 167 | + |
| 168 | + await expect(bridge.writeFile({ filePath: "b.txt", data: "hello" })).rejects.toThrow( |
| 169 | + /requires `python3` inside the sandbox container/i, |
| 170 | + ); |
| 171 | + }); |
| 172 | + |
143 | 173 | it("routes mkdirp, remove, and rename through the pinned mutation helper", async () => { |
144 | 174 | await withTempDir("openclaw-fs-bridge-shell-write-", async (stateDir) => { |
145 | 175 | const { bridge } = await createSeededSandboxFsBridge(stateDir, { |
|
0 commit comments