Class: RubyLLM::Toolbox::Sandbox::SandboxExec

Inherits:
Base
  • Object
show all
Defined in:
lib/ruby_llm/toolbox/sandbox/sandbox_exec.rb

Overview

macOS host-process sandbox via sandbox-exec (Seatbelt). No daemon, no image: it runs the host’s interpreters under a Seatbelt profile that denies by default, blocks all network, allows reading the system, and permits writes only to temp directories. Memory/CPU caps are applied as rlimits.

sandbox-exec is deprecated by Apple but remains present and functional on current macOS. As with bubblewrap, the filesystem is readable (read-only for writes) inside the sandbox; use Docker for full read-confidentiality.

Constant Summary collapse

BINARY =
"/usr/bin/sandbox-exec"
DEFAULT_PROFILE =
<<~SBPL
  (version 1)
  (deny default)
  (allow process-fork)
  (allow process-exec)
  (allow signal (target self))
  (allow sysctl-read)
  (allow mach-lookup)
  (allow file-read*)
  (allow file-write*
    (subpath "/tmp")
    (subpath "/private/tmp")
    (subpath "/private/var/tmp")
    (subpath "/private/var/folders")
    (literal "/dev/null")
    (literal "/dev/zero")
    (literal "/dev/random")
    (literal "/dev/urandom")
    (literal "/dev/dtracehelper"))
  (deny network*)
SBPL
Unavailable =
Sandbox::Unavailable

Instance Attribute Summary

Attributes inherited from Base

#config

Instance Method Summary collapse

Methods inherited from Base

#initialize, #name

Constructor Details

This class inherits a constructor from RubyLLM::Toolbox::Sandbox::Base

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


43
44
45
46
47
# File 'lib/ruby_llm/toolbox/sandbox/sandbox_exec.rb', line 43

def available?
  return false unless Sandbox.macos?

  File.executable?(BINARY)
end

#command(command_argv, image: nil) ⇒ Object



62
63
64
# File 'lib/ruby_llm/toolbox/sandbox/sandbox_exec.rb', line 62

def command(command_argv, image: nil)
  ["sandbox-exec", "-p", profile, *command_argv]
end

#profileObject



66
67
68
69
# File 'lib/ruby_llm/toolbox/sandbox/sandbox_exec.rb', line 66

def profile
  prof = config.sandbox_seatbelt_profile
  prof && !prof.to_s.strip.empty? ? prof.to_s : DEFAULT_PROFILE
end

#run(command_argv, stdin: nil, image: nil) ⇒ Object

Raises:



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ruby_llm/toolbox/sandbox/sandbox_exec.rb', line 49

def run(command_argv, stdin: nil, image: nil)
  raise Unavailable, "sandbox-exec is not available on this host" unless available?

  ProcessRunner.capture(
    command(command_argv, image: image),
    env: sandbox_env,
    stdin: stdin,
    timeout: config.command_timeout,
    unsetenv_others: true,
    rlimits: spawn_rlimits
  )
end