Module: Pikuri::Code::Bash::Sandbox

Defined in:
lib/pikuri/code/bash/sandbox.rb

Overview

Filesystem-sandbox seam for the bash tool. A sandbox responds to #wrap(argv) → Array<String>, transforming the +timeout … bash -c + argv run would spawn into the argv actually spawned: NONE returns it unchanged (the default), Bubblewrap prepends bwrap + bind/isolation flags, FullFsNoNet is Bubblewrap's inverse.

Distinct from Workspace, deliberately: Workspace is "what the LLM observes via Read/Write/Edit/Grep/Glob"; Sandbox is "what the executed subprocess sees." They overlap on project + toolchain dirs but diverge on the OS-runtime baseline (Bubblewrap::ETC_BASELINE — TLS certs, DNS, tz, hosts): the LLM has no need to Read /etc/resolv.conf, the curl subprocess does. Separate objects keep each allowlist with its owner.

The full two-sandbox design — each posture's threat model, the overlay/concurrency reasoning, and which to pick — is in pikuri-code/DESIGN.md.

Posture predicates

A sandbox also answers two questions about itself, which is how Pikuri::Code::Bash computes its Tool::TrifectaLegs — asking the object rather than reading a flag out of the argv, because the argv is exactly where that reading goes wrong:

  • #egress? — can the wrapped command reach a network sink?
  • #confined_to_workspace? — does it see only the workspace?

Both are conservative at the identity element: NONE answers +true+/+false+ respectively, so a host that subclasses one of these (the Bubblewrap header invites it) inherits an answer that is wrong only in the safe direction. A sandbox that could ever degrade to a networked run rather than raising must answer egress? == true, and a severed network namespace alone is not evidence of a severed leg — a reachable session bus spawns the fetch outside every namespace (see FullFsNoNet::SESSION_IPC_MASKS).

Defined Under Namespace

Modules: NONE Classes: Bubblewrap, FullFsNoNet

Constant Summary collapse

BWRAP_BINARY =

The +bwrap+(1) binary, resolved on PATH.

'bwrap'

Class Method Summary collapse

Class Method Details

.probe(*flags) ⇒ Pikuri::Subprocess::Result

Run a one-shot bwrap probe and return the finished process: spawns bwrap <flags> --die-with-parent /bin/true at / and waits.

Sandbox.probe('--bind', '/', '/', '--unshare-net').status.success?

flags are the isolation each sandbox promises (+--unshare-net+, an overlay mount, …) — deliberately not defaulted, because the probe's whole job is to prove that exact isolation works on this host (see pikuri-code/DESIGN.md on why the two probes aren't interchangeable). Propagates Errno::ENOENT when bwrap is absent; each caller rescues it to raise its own install hint.

Parameters:

  • flags (Array<String>)

    isolation flags under test.

Returns:

  • (Pikuri::Subprocess::Result)

    query .status.success? / .status.exitstatus.

Raises:

  • (Errno::ENOENT)

    if bwrap isn't on PATH.



66
67
68
69
70
# File 'lib/pikuri/code/bash/sandbox.rb', line 66

def self.probe(*flags)
  Pikuri::Subprocess.spawn(
    BWRAP_BINARY, *flags, '--die-with-parent', '/bin/true', chdir: '/'
  ).wait
end