self-managed evaluation · 10 minutes

Run one request first.
Then choose your wall.

This page sends one authenticated request to a daemon on your own machine. It uses the wasm provider (the backend that runs the code), which runs JavaScript on an engine compiled to WebAssembly (a portable bytecode that runs inside a host program), inside the daemon itself. That shows how a caller is set up and what a request and its result look like. It gives no isolation fit for hostile code.

For code your customers write, in production, choose a stronger isolation tier (how strong the wall around a run is). Docker with gVisor, a layer that handles the container's requests to the kernel itself, reaches the kernel tier once the daemon has confirmed gVisor's runtime, runsc, at startup. E2B and Docker Cloud Sandboxes are hosted services that run each request in its own small virtual machine, the vm tier.

1. Create a caller

From the repository root, create a credential for the program that will call the daemon. The token is printed once, to stdout; the file keeps only a SHA-256 hash of it.

TOKEN="$(go run ./cmd/plimsoll-clients create \
  -file clients.json -id tutorial -token-stdout)"

2. Start the daemon on loopback

With SANDBOX_PROVIDER unset nothing runs; setting it to wasm opts in. PLIMSOLL_ADDR makes the daemon listen on this machine only, because the default, :8746, listens on every network interface. The clients file turns authentication on, and it fails closed: a request it cannot verify is refused.

SANDBOX_PROVIDER=wasm \
PLIMSOLL_ADDR=127.0.0.1:8746 \
PLIMSOLL_CLIENTS_FILE=clients.json \
go run ./cmd/plimsolld

Expect multi-client auth enabled clients=1 and a plimsolld listening line with auth=true.

3. Run one bounded snippet

In the shell that holds TOKEN (not the one running the daemon), send one Run request with the token in the Authorization header. The request has a few outer fields and one payload. The outer fields state the protocol number this client speaks (so a daemon on a different version refuses instead of misreading the request), the floor (the weakest isolation tier this request accepts) and the timeout. The payload is the JavaScript to run.

curl -sS \
  http://127.0.0.1:8746/plimsoll.v1.SandboxService/Run \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary '{"protocol":2,"timeoutMs":1000,"minimumIsolation":"process","javascript":{"code":"console.log(6 * 7)"}}'

4. Read the receipt

The response says what happened: the provider, the isolation tier the run actually got, how long it took, a run record (the daemon's statement of what was sent, what came back and where it ran, shortened here to {…}), the engine it ran on, named by a hash of its content, and the output, inside a result of the same kind as the payload.

{"sandbox":"wasm", "isolation":"process", "durationMs":"292", "record":{…}, "environment":"quickjs-wasm:sha256:…", "javascript":{"stdout":"NDIK"}}

Output travels as raw bytes, so the JSON form carries it base64-encoded: NDIK is 42 and a newline. Decode it with printf %s NDIK | base64 -d. The Go, Python and TypeScript clients decode it for you and check the record; curl does neither. A zero exit code is left out of the JSON.

Four other answers you should be able to tell apart:

{"sandbox":"wasm", "isolation":"process", "durationMs":"283", "record":{…}, "environment":"quickjs-wasm:sha256:…", "javascript":{"stdout":"cGFydGlhbAo=", "stderr":"RXJyb3I6IGJvb20K...", "exitCode":1}}
{"code":"failed_precondition","message":"sandbox isolation requirement not met: provider isolation process is below requested minimum kernel"}
{"code":"unauthenticated","message":"invalid or expired token"}
{"code":"unimplemented","message":"this daemon serves protocol 2 and the request states 3; nothing ran"}

The first is HTTP 200 with a non-zero exitCode: the program ran and failed, which is a normal result, and both output streams are there to read. The second is what "minimumIsolation":"kernel" gets from this daemon: a typed refusal before anything started, so no code ran. The third is a wrong or missing token, refused before the request body was read. The fourth is a request whose protocol is not the daemon's. Requests are encoded with protobuf, a message format whose readers silently drop fields they do not know, so without the number a daemon older than a new safety field would run the code without it. With the number, that daemon refuses before it reads the payload. A request with no number at all gets invalid_argument.

This test runs WebAssembly inside the plimsolld process. It is useful for learning the API, but it is no operating-system or virtual machine wall.
Definitions and references links are labeled