Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/bash-mcp/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
2 changes: 1 addition & 1 deletion packages/bash-types/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/bash-wasm/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
38 changes: 17 additions & 21 deletions packages/bash-wasm/sandboxes/js/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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 {}
}

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions packages/bash-wasm/sandboxes/python/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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="<ast>", mode="exec"), local_env)
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion packages/bash/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
Loading