Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sandbox CLI #302

Merged
merged 1 commit into from
Nov 17, 2024
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
42 changes: 42 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion packages/sandbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ Run untrusted code from programming languages inside a WebAssembly sandbox.

This is an unreleased proof of concept.

## Quickstart
## Quickstart CLI

`src/main.ts` is a CLI program that runs files using Runno.

```
$ deno --allow-net --allow-read src/main.ts python test.py
Hello, World!
```

_Note: Currently network access is required to fetch the WASM binaries from runno.dev_

Supported runtimes are: `python`, `ruby`, `quickjs`, `php-cgi`, `sqlite`, `clang`, and `clangpp`.

## Quickstart API

The simplest use is to run some code in a supported language:

Expand Down
1 change: 1 addition & 0 deletions packages/sandbox/deno.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"imports": {
"@cliffy/command": "jsr:@cliffy/[email protected]",
"@runno/wasi": "npm:@runno/wasi@^0.7.0",
"@std/tar": "jsr:@std/tar@^0.1.3"
},
Expand Down
3 changes: 2 additions & 1 deletion packages/sandbox/lib/main.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { runCode, runFS } from "./runtime.ts";
import { fetchWASIFS } from "./helpers.ts";

export { runCode, runFS };
export { runCode, runFS, fetchWASIFS };
5 changes: 3 additions & 2 deletions packages/sandbox/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@runno/sandbox",
"version": "0.7.0",
"description": "A sandbox for running code server-side in JavaScript environments",
"description": "Run untrusted code from programming languages inside a WebAssembly sandbox.",
"keywords": [
"sandbox",
"python",
Expand All @@ -28,7 +28,8 @@
"url": "git+https://github.com/taybenlor/runno.git"
},
"scripts": {
"test": "deno test --no-check --allow-net"
"test": "deno test --no-check --allow-net",
"cli": "deno --allow-net --allow-read src/main.ts"
},
"bugs": {
"url": "https://github.com/taybenlor/runno/issues"
Expand Down
123 changes: 79 additions & 44 deletions packages/sandbox/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,81 @@
import { runCode, runFS } from "../lib/main.ts";
import { WASIFS } from "@runno/wasi";

const codeResult = await runCode(
"python",
`
print("Hello, World!");
import { runFS } from "../lib/runtime.ts";
import { Command } from "@cliffy/command";
import { Runtime } from "../lib/types.ts";
import { fetchWASIFS } from "../lib/main.ts";

function isRuntime(runtime: string): runtime is Runtime {
return [
"python",
"ruby",
"quickjs",
"php-cgi",
"clang",
"clangpp",
"sqlite",
].includes(runtime);
}

const command = new Command()
.name("runno")
.version("0.7.0")
.description(
`A CLI for running code in a sandbox environment, powered by Runno & WASI.
Supports python, ruby, quickjs, php-cgi, clang, and clangpp.
Entry is a path to a file, which will be added on top of the base filesystem and used as the entrypoint.
`
);

console.log("Run Code Result:", codeResult);

const fsResult = await runFS("python", "/program", {
"/program": {
path: "/program",
content: `
from package import say_hello
say_hello()

print('------')

import os
print("/package contains", os.listdir('/package'))
`,
mode: "string",
timestamps: {
access: new Date(),
modification: new Date(),
change: new Date(),
},
},
"/package/__init__.py": {
path: "/package/__init__.py",
content: `
def say_hello():
print("Hello from package")
`,
mode: "string",
timestamps: {
access: new Date(),
modification: new Date(),
change: new Date(),
},
},
});

console.log("Run FS Result:", fsResult);
)
.arguments("<runtime:string> <entry:string>")
.option(
"-f, --filesystem <filesystem:string>",
"A tgz file to use as the base filesystem"
)
.action(
async (options: { filesystem?: string }, ...args: [string, string]) => {
const [runtimeString, entry] = args;
if (!isRuntime(runtimeString)) {
throw new Error(`Unsupported runtime: ${runtimeString}`);
}
const runtime: Runtime = runtimeString;

// TODO: Use filesystem helpers
const entryName = entry.split("/").pop() ?? entry;
let fs: WASIFS = {
[`/${entryName}`]: {
path: `/${entryName}`,
content: await Deno.readFile(entry),
mode: "binary",
timestamps: {
access: new Date(),
modification: new Date(),
change: new Date(),
},
},
};

if (options.filesystem) {
const baseFS = fetchWASIFS(options.filesystem);
fs = { ...baseFS, ...fs };
}

const result = await runFS(runtime, entryName, fs);

switch (result.resultType) {
case "complete":
console.error(result.stderr);
console.log(result.stdout);
break;
case "crash":
console.error(result.error);
Deno.exit(1);
break;
case "terminated":
console.error("Terminated");
Deno.exit(1);
break;
}
}
);

await command.parse(Deno.args);
Loading