std/sandbox
Sandbox and Script, which load a .trb file as a type-checked, capability-limited receiver closure.
The generated reference of std/sandbox has every public construct with its signature, its doc comment and its examples.
Only the VM runs a script. A script is always interpreted (Receiver Scripts and the Sandbox):
torb runruns a program that loads one in the VM; a native binarytorb buildcompiled links the script host - the front end and the VM, built once per toolchain - and hands it the value as text, through the derivedEncodeandDecodeof the receiver, which is thereforeEncode & Decodethere;torb build --embed-vmbuilds a native binary that runs the whole program in the VM.
std/sandbox loads .trb files as sandboxed receiver closures - the mechanism behind project.trb and every
configuration script. What a script may do is granted at the call site of Sandbox.load, never in the script or its
own project file, because a script that could grant itself capabilities would not be a sandbox. Left at the defaults, a
script has no IO, no network, no clock, no environment and no foreign functions.
Import#
use Sandbox, Script, SandboxCapabilities, SandboxError from "std/sandbox"use Sandbox from "std/sandbox"
type ServerConfig {
var port: Int = 8080
}
const script = Sandbox.load<ServerConfig>("./config.trb") {
limits steps: 1_000_000
}
print script.isOk()Declarations#
Sandbox#
native type Sandbox {
static fn load<Value>(path: String, capabilities: (var self: SandboxCapabilities) => Void = {}): Result<Script<Value>, SandboxError>
static fn loadText<Value>(text: String, name: String, capabilities: (var self: SandboxCapabilities) => Void = {}): Result<Script<Value>, SandboxError>
}Type checks path against Value and answers a Script, ready to run against a Value of the caller's own. What is
wrong with the file (syntax, types, a module the script may not import) is reported here; what goes wrong while it runs
is reported by Script.apply instead. The trailing block grants capabilities beyond the defaults.
The path is relative to the directory the program runs in. A literal path names a file the checker checked against the
type argument with the program, which carries that script. Any other path - one the program computes - is read, checked
and lowered when the program asks for it, by the torb that runs it, and costs a check of the program the first time;
Value is then a type without type arguments. A file that is nowhere or does not check is the SandboxError of
load, with the line of the first error, and so is an import of the script that the grant does not name, with the line
of the use.
loadText is load for a script the program holds as text, which it fetched through a Storage (readText) or
built itself: text is checked against Value with the same grants, limits and errors, and name is only what a
SandboxError calls it - the line of an error counts the lines of text. Nothing is read from or written to a file,
the same text loaded twice is the same script whatever it is called, and std/sandbox knows no Storage: the program
fetches the text and hands it over. Value is a type without type arguments, as for a computed path, and a native
binary runs it through the script host it links, like load.
Script#
type Script<Value> {
fn apply(var value: Value): Result<Void, SandboxError>
}A loaded script, ready to run against a Value of the caller's own. It is not a closure, because its body runs inside
the sandbox and can still fail there - a step, memory or time limit, or a panic. This is the one panic in the language
that is recoverable, because the sandbox interprets the script and the script has a heap of its own.
SandboxCapabilities#
type SandboxCapabilities {
protected var moduleNames: List<String> = []
protected var readOnlyRoots: List<String> = []
protected var readWriteRoots: List<String> = []
protected var variablePatterns: List<String> = []
protected var connectPatterns: List<String> = []
protected var listenPatterns: List<String> = []
protected var stepLimit: Int = 1_000_000
protected var memoryLimit: Int = 64_000_000
protected var timeLimit: Int = 2000
protected var workerLimit: Int = 1
var fn modules(...names: String)
var fn files(readOnly: String = "", readWrite: String = "")
var fn network(connect: String = "", listen: String = "")
var fn environment(...patterns: String)
var fn limits(steps: Int = 1_000_000, memory: ByteSize = 64.megabytes(), time: Duration = 2.seconds(), workers: Int = 1)
}modules names additional parts of the standard library the script may use. files names the file system roots the
script may reach; a side left out stays closed. environment names the environment variable patterns the script may
read. network names a host:port pattern the script may resolve and connect to, and one it may listen on or bind
(network connect: "api.example.test:443", listen: "127.0.0.1:8080"); each call adds one per side, a side left out
stays closed, and the script also needs modules "std/network". The host is a name, *. and a name for every name
below it, *, localhost or an address (IPv6 in brackets, "[::1]:8080"), the port a number or *; a listen
pattern names an address, * or localhost. Anything outside a pattern - a resolve, connect, listen, UDP bind or
datagram, or the system's name servers - stops the script with a SandboxError, and a malformed pattern fails the
load (NETWORK.md, section 10). limits guards against a runaway script (loop {}) - workers is the most workers its tasks may run on at once,
and the VM runs a script's tasks on the thread of its sandbox, so it never uses more than one - and memory is a
ByteSize of std/number (64.megabytes(), 16.mebibytes()), which needs no import.
SandboxError#
type SandboxError with Show, Error {
line: Int
message: String
fn show(): String
}What went wrong loading a script: a syntax or type error against the receiver type, or a capability it does not have.
line is 0 when the problem is not about one place in the script, such as the file not being readable at all.
Related#
- std/project -
Project, the receiver typeproject.trbis loaded against. - std/os -
Environment, gated bySandboxCapabilities.environment. - std/network - the sockets and the resolver, gated by
SandboxCapabilities.network. - The standard library - the other packages.