diff --git a/package.json b/package.json index 04a9d43..f3bc7d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "capsulerun-bash-monorepo", - "version": "0.1.3", + "version": "0.1.4", "private": true, "description": "Sandboxed bash for untrusted command execution", "license": "Apache-2.0", diff --git a/packages/bash-mcp/package.json b/packages/bash-mcp/package.json index 2d56705..6c2fd1b 100644 --- a/packages/bash-mcp/package.json +++ b/packages/bash-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@capsule-run/bash-mcp", - "version": "0.1.3", + "version": "0.1.4", "description": "MCP server exposing sandboxed bash for untrusted command execution", "type": "module", "bin": { diff --git a/packages/bash-types/package.json b/packages/bash-types/package.json index 577b643..ac082cd 100644 --- a/packages/bash-types/package.json +++ b/packages/bash-types/package.json @@ -1,6 +1,6 @@ { "name": "@capsule-run/bash-types", - "version": "0.1.3", + "version": "0.1.4", "description": "", "type": "module", "homepage": "https://github.com/capsulerun/bash", diff --git a/packages/bash-wasm/package.json b/packages/bash-wasm/package.json index f74219c..fa93a3e 100644 --- a/packages/bash-wasm/package.json +++ b/packages/bash-wasm/package.json @@ -1,6 +1,6 @@ { "name": "@capsule-run/bash-wasm", - "version": "0.1.3", + "version": "0.1.4", "description": "Sandboxed bash for untrusted command execution", "type": "module", "homepage": "https://github.com/capsulerun/bash", diff --git a/packages/bash-wasm/sandboxes/js/sandbox.ts b/packages/bash-wasm/sandboxes/js/sandbox.ts index 8dc4a6b..c3aa0da 100644 --- a/packages/bash-wasm/sandboxes/js/sandbox.ts +++ b/packages/bash-wasm/sandboxes/js/sandbox.ts @@ -5,15 +5,11 @@ import fsPromises from 'fs/promises'; import type { State } from '@capsule-run/bash-types'; -function wasmRelative(cwd: string, filePath: string): string { - return path.resolve(cwd, filePath).replace(/^\//, ''); -} - function resolveNodeModule(fromPath: string, id: string): string | null { let dir = path.dirname('/' + fromPath); while (true) { - const base = wasmRelative('/', path.join(dir, 'node_modules', id)); + const base = path.resolve(dir, 'node_modules', id); const candidates = [base, base + '.js', base + '/index.js']; const pkgJson = base + '/package.json'; @@ -22,7 +18,7 @@ function resolveNodeModule(fromPath: string, id: string): string | null { try { const pkg = JSON.parse(fs.readFileSync(pkgJson, 'utf-8') as string); const main = pkg.main || 'index.js'; - candidates.unshift(wasmRelative('/', path.join(dir, 'node_modules', id, main))); + candidates.unshift(path.resolve(dir, 'node_modules', id, main)); } catch {} } @@ -51,7 +47,7 @@ const makeRequire = (fromPath: string) => (id: string) => { depPath = resolved; } else { - const base = wasmRelative('/', path.resolve('/' + path.dirname(fromPath), id)); + const base = path.resolve(path.dirname(fromPath), id); depPath = fs.existsSync(base) ? base @@ -73,18 +69,19 @@ const executeFile = task( { name: 'executeFile', compute: 'MEDIUM', ram: '512MB', allowedHosts: ['*'] }, async (state: State, filePath: string, args: string[]) => { const capturedOutput: string[] = []; - const relPath = wasmRelative(state.cwd, filePath); + const absolutePath = path.resolve(state.cwd, filePath); process.chdir(state.cwd); Object.defineProperty(process, 'argv', { - value: ['node', relPath, ...args], + value: ['node', absolutePath, ...args], writable: true, configurable: true, }); - const capture = (...logArgs: any[]) => + const capture = (...logArgs: any[]): void => { capturedOutput.push(logArgs.map((a) => String(a)).join(' ')); + }; const originalLog = console.log; const originalError = console.error; @@ -94,20 +91,18 @@ const executeFile = task( console.warn = capture; try { - const code = fs.readFileSync(relPath, 'utf-8') as string; + const code = fs.readFileSync(absolutePath, 'utf-8') as string; const mod = { exports: {} as any }; - const customRequire = makeRequire(relPath); + const customRequire = makeRequire(absolutePath); const fn = new Function('module', 'exports', 'require', '__filename', '__dirname', code); - fn(mod, mod.exports, customRequire, relPath, path.dirname(relPath)); + fn(mod, mod.exports, customRequire, absolutePath, path.dirname(absolutePath)); const output = capturedOutput.join('\n'); - if (output) { - return Object.keys(mod.exports).length > 0 - ? output + '\n' + JSON.stringify(mod.exports) - : output; - } - return mod.exports; + + if (output) return output; + + return Object.keys(mod.exports).length > 0 ? mod.exports : null; } finally { console.log = originalLog; console.error = originalError; @@ -122,8 +117,9 @@ const executeCode = task( process.chdir(state.cwd); const capturedOutput: string[] = []; - const capture = (...args: any[]) => + const capture = (...args: any[]): void => { capturedOutput.push(args.map((arg) => String(arg)).join(' ')); + }; const originalLog = console.log; const originalError = console.error; @@ -132,7 +128,7 @@ const executeCode = task( console.error = capture; console.warn = capture; - const require = makeRequire(wasmRelative(state.cwd, '.')); + const require = makeRequire(state.cwd); try { let result; diff --git a/packages/bash-wasm/sandboxes/python/sandbox.py b/packages/bash-wasm/sandboxes/python/sandbox.py index 113307c..4902a80 100644 --- a/packages/bash-wasm/sandboxes/python/sandbox.py +++ b/packages/bash-wasm/sandboxes/python/sandbox.py @@ -74,7 +74,7 @@ def execute_file(state: str, file_path: str, args: list[str]): pass if output: - return output.rstrip("\n") + "\n" + json.dumps(public_result) if public_result else output.rstrip("\n") + return output.rstrip("\n") return public_result if public_result else None @@ -100,8 +100,10 @@ def execute_code(state: str, code: str): old_stdout = sys.stdout sys.stdout = captured_output + last_was_expr = isinstance(last_node, ast.Expr) + try: - if isinstance(last_node, ast.Expr): + if last_was_expr: tree.body.pop() if tree.body: exec(compile(tree, filename="", mode="exec"), local_env) @@ -128,7 +130,7 @@ def execute_code(state: str, code: str): pass if output: - if public_vars: + if not last_was_expr and public_vars: return output.rstrip("\n") + "\n" + json.dumps(public_vars) if result is not None: return output.rstrip("\n") + "\n" + str(result) diff --git a/packages/bash/package.json b/packages/bash/package.json index 6d4f4d7..6230c5f 100644 --- a/packages/bash/package.json +++ b/packages/bash/package.json @@ -1,6 +1,6 @@ { "name": "@capsule-run/bash", - "version": "0.1.3", + "version": "0.1.4", "description": "Sandboxed bash for untrusted command executions", "type": "module", "homepage": "https://github.com/capsulerun/bash",