Compile and run untrusted Erlang-shaped guest programs.
The public API is four functions and one callback module:
program/1compiles an immutable source value into aHyperlang.Program. The manifest, the binding MFA set, the export set and the atom universe are fixed here and enter the program hash.program/2returns a program cached under a caller-owned key and calls the loader only on a miss.run/4runs one declared export with exactly the authority in its spec.load/1loads a program into the code pool ahead of its first use.Hyperlang.Actoris theGenServercallback module that runs a program's OTP callbacks (GenServer.start(Hyperlang.Actor, {spec, program, arg})). Every callback goes throughrun/4.
Errors are sanitized maps whose :category comes from a closed taxonomy;
see doc/SECURITY_SPECIFICATION.md.
Summary
Functions
Load an immutable program value into the code pool ahead of its first use.
Compile an immutable, closed-world source value.
Return a program cached under a caller-owned key, compiling the loader's source value on a miss.
Run a declared export using only the authority present in spec.
Types
Functions
@spec load(Hyperlang.Program.t()) :: :ok | {:error, term()}
Load an immutable program value into the code pool ahead of its first use.
Loading is optional: run/4 and a Hyperlang.Actor load a program that
is not loaded. A host calls load/1 to pay the compile and load cost
at a time of its choosing (for example at boot, outside a request). The
loaded code is not pinned; the pool may reclaim it later, and the next use
loads it again.
Returns :ok, or {:error, error} with a sanitized error map (for
example category: :code_pool when every slot of the program's window is
pinned or still running).
@spec program(binary() | map()) :: {:ok, Hyperlang.Program.t()} | {:error, errors()}
Compile an immutable, closed-world source value.
Source maps use %{entry: "name.erl", files: %{"name.erl" => source}} and
may carry a compiler manifest under :manifest. A binary is the compact
single-source form.
@spec program(term(), (-> binary() | map() | {:ok, binary() | map()} | {:error, term()})) :: {:ok, Hyperlang.Program.t()} | {:error, errors()}
Return a program cached under a caller-owned key, compiling the loader's source value on a miss.
@spec run(map(), Hyperlang.Program.t(), atom() | binary(), list()) :: {:ok, term(), %{ stdout: [binary()], reductions: non_neg_integer(), wall_us: non_neg_integer() }} | {:error, term()}
Run a declared export using only the authority present in spec.
spec is %{bindings: %{name => {module, state}}, policy: map} plus an
optional syscall host door. bindings must name exactly the bindings the
program's manifest declares, with the same modules. export is :entry
(the manifest result root, called with hd(args)), an atom, or an
"name/arity" export id.
Success returns {:ok, value, meta} where meta is
%{stdout: [binary], reductions: non_neg_integer, wall_us: non_neg_integer}:
the sanitized guest stdout chunks in order, the reductions the guest call
consumed in its own process, and the wall time of the call in
microseconds. Failure returns {:error, error} with a sanitized error map.