Legion.Sandbox.Lua (Legion v0.5.0)

View Source

Sandboxed Lua evaluation via lua - a Lua 5.3 VM written in pure Elixir. The default Legion.Sandbox.

Unlike Legion.Sandbox.Elixir, which must deny-list its way around the entire Elixir surface, Lua code simply has no way to reach the host BEAM: the only bridges out of the VM are the tool functions registered by this module. That makes it the safer sandbox for less trusted code.

  • Tools - each tool module becomes a global Lua table named after the module's last segment; every public function of a Legion.Tool module is callable as ShortName.fun(...). Other listed modules (sub-agents, extra allowed modules) get a reference-only table: usable where a tool expects a module, but exposing no functions. Arguments are decoded to Elixir values (Lua tables become maps, or lists when array-shaped) and results are encoded back (tuples become arrays, structs become tables of fields, atoms become strings).
  • Bindings - the user-defined globals, as a list of {name, value} pairs of plain Elixir data (tables become maps, or lists when array-shaped). Globals persist across executions that share bindings; local variables, functions, and metatables do not.
  • Blocked - io, file, os.execute/exit/getenv/..., require, load, print, and debug are sandboxed and raise when called.
  • Timeout and resource limits - evaluation runs through Legion.Sandbox.Runner, same as Legion.Sandbox.Elixir. The VM additionally refuses to build any single string larger than half the memory budget, before allocating it.

Examples

iex> {:ok, {4, _}} = Legion.Sandbox.Lua.execute("return 2 + 2", 5_000)

iex> {:ok, {nil, [{"x", 40}]}} = Legion.Sandbox.Lua.execute("x = 40", 5_000)
iex> {:ok, {42, _}} = Legion.Sandbox.Lua.execute("return x + 2", 5_000, [], [{"x", 40}])

iex> {:error, message} = Legion.Sandbox.Lua.execute("os.getenv('HOME')", 5_000)
iex> message =~ "sandboxed"
true

Summary

Functions

execute(code, timeout_ms, tools \\ [], bindings \\ [], limits \\ [])

Evaluates Lua code in a sandboxed process.

timeout_ms controls the maximum execution time (:infinity to disable). tools are Elixir modules bridged in as global Lua tables. limits bound the evaluating process - see Legion.Sandbox.Runner.run/3.

Returns {:ok, {result, bindings}} where result is the chunk's return value (nil when it returns nothing) and bindings holds the user-defined globals to pass to subsequent calls, or {:error, reason}.