Puck.Sandbox.Eval.Lua (Puck v0.2.11)

Copy Markdown View Source

Execute Lua code in a sandboxed environment.

Uses tv-labs/lua (Luerl), a pure Erlang Lua implementation. Provides:

  • CPU limits via timeout
  • Memory limits via process heap limits
  • Host callbacks for safe interaction with your application
  • Complete crash isolation (pure Erlang, no NIF)

Usage

# Simple eval
{:ok, result} = Puck.Sandbox.Eval.Lua.eval("return 1 + 2")
# => {:ok, 3}

# With callbacks
{:ok, result} = Puck.Sandbox.Eval.Lua.eval("""
  local products = search_products("laptop")
  local cheap = {}
  for _, p in ipairs(products) do
    if p.price < 1000 then table.insert(cheap, p) end
  end
  return cheap
""", callbacks: %{
  "search_products" => &MyApp.Products.search/1
})

# With resource limits
{:ok, result} = Puck.Sandbox.Eval.Lua.eval(code,
  callbacks: %{...},
  timeout_ms: 5_000,
  max_heap_words: 1_000_000
)

Requirements

Requires the lua package: {:lua, "~> 0.4.0"}

Options

  • :callbacks - Map of callback names to functions (e.g., %{"name" => &Mod.fun/1})
  • :timeout_ms - Execution timeout in ms (default: 5_000)
  • :max_heap_words - Memory limit in words (default: 1_000_000, ~8MB on 64-bit)

Safety

Luerl sandboxes by default, blocking:

  • io module (file I/O)
  • os.execute, os.exit, os.getenv, os.remove, os.rename, os.tmpname
  • load, loadfile, loadstring, dofile, require
  • package module

The only risk is user-provided callbacks.

Summary

Functions

Evaluates Lua code in a sandboxed environment.

Returns a Zoi schema for the ExecuteCode struct.

Functions

eval(code, opts \\ [])

Evaluates Lua code in a sandboxed environment.

Returns {:ok, result} on success or {:error, reason} on failure.

Examples

{:ok, 3} = Puck.Sandbox.Eval.Lua.eval("return 1 + 2")

{:ok, result} = Puck.Sandbox.Eval.Lua.eval("""
  local x = 0
  for i = 1, 100 do x = x + i end
  return x
""")
# => {:ok, 5050}

{:error, :timeout} = Puck.Sandbox.Eval.Lua.eval("while true do end", timeout_ms: 100)

eval!(code, opts \\ [])

Like eval/2 but raises Puck.Sandbox.Eval.Lua.Error on failure.

Examples

3 = Puck.Sandbox.Eval.Lua.eval!("return 1 + 2")

schema(func_spec)

Returns a Zoi schema for the ExecuteCode struct.

The schema includes guidance in the code field description to help LLMs generate valid Lua code (e.g., always use return to return values).

Arguments

  • func_spec - A Zoi schema describing the available callback functions. The LLM will see this schema and understand what functions it can call.

Example

@func_spec Zoi.object(%{
  name: Zoi.enum(["double", "search"]),
  description: Zoi.string()
}, strict: true, coerce: true)

schema = Zoi.union([
  Puck.Sandbox.Eval.Lua.schema(@func_spec),
  Zoi.struct(Done, %{type: Zoi.literal("done"), message: Zoi.string()}, coerce: true)
])

# Pattern match on the struct:
case action do
  %Puck.Sandbox.Eval.Lua.ExecuteCode{code: code} ->
    Puck.Sandbox.Eval.eval(:lua, code, callbacks: callbacks)
  %Done{message: msg} ->
    {:ok, msg}
end