In-process code evaluation in sandboxed interpreters.
Puck.Sandbox.Eval provides a unified API for evaluating code snippets in
sandboxed interpreter environments. Unlike Puck.Sandbox.Runtime which
runs containers, Eval runs code in-process with memory and CPU limits.
Supported Engines
:lua- Lua 5.3 via Luerl (pure Erlang, requires{:lua, "~> 0.4.0"})
Usage
# Simple eval
{:ok, result} = Puck.Sandbox.Eval.eval(:lua, "return 1 + 2")
# With callbacks to host functions
{:ok, result} = Puck.Sandbox.Eval.eval(:lua, """
local products = search("laptop")
local cheap = {}
for _, p in ipairs(products) do
if p.price < 1000 then table.insert(cheap, p) end
end
return cheap
""", callbacks: %{
"search" => &MyApp.Products.search/1
})
# With resource limits
{:ok, result} = Puck.Sandbox.Eval.eval(:lua, code,
timeout_ms: 5_000,
max_heap_words: 1_000_000
)Safety
Code runs in a separate BEAM process with:
- CPU limits via timeout
- Memory limits via process heap limits
- No filesystem or network access (interpreter sandboxed)
- Crash isolation (pure Erlang, no NIF)
The only risk is user-provided callbacks.
Summary
Types
@type code() :: String.t()
@type engine() :: :lua
@type eval_opts() :: [ callbacks: %{required(String.t()) => function()}, timeout_ms: pos_integer(), max_heap_words: pos_integer() ]
Functions
Checks if an engine is available.
Examples
true = Puck.Sandbox.Eval.engine_available?(:lua)
false = Puck.Sandbox.Eval.engine_available?(:python)
Returns the list of available eval engines.
Examples
[:lua] = Puck.Sandbox.Eval.engines()
Evaluates code in the specified sandboxed interpreter.
Engines
:lua- Lua 5.3 (requires{:lua, "~> 0.4.0"})
Options
:callbacks- Map of callback names to functions:timeout_ms- Execution timeout in ms (default: 5_000):max_heap_words- Memory limit in words (default: 1_000_000, ~8MB)
Examples
{:ok, 3} = Puck.Sandbox.Eval.eval(:lua, "return 1 + 2")
{:ok, result} = Puck.Sandbox.Eval.eval(:lua, """
return double(21)
""", callbacks: %{"double" => fn x -> x * 2 end})
{:error, :timeout} = Puck.Sandbox.Eval.eval(:lua, "while true do end", timeout_ms: 100)
Like eval/3 but raises on error.
Examples
42 = Puck.Sandbox.Eval.eval!(:lua, "return 42")