Class: Kobako::Sandbox

Inherits:
Object
  • Object
show all
Defined in:
lib/kobako/sandbox.rb,
lib/kobako/sandbox/output_buffer.rb,
lib/kobako/sandbox/outcome_decoder.rb

Overview

Kobako::Sandbox — the user-facing entry point for executing guest mruby scripts inside a wasmtime-hosted Wasm module (SPEC.md B-01).

The Sandbox owns the Kobako::Wasm::Instance, the per-instance Registry (which itself owns the per-run HandleTable), and bounded stdout / stderr capture buffers. The underlying wasmtime Engine and compiled Module are cached at process scope by the native ext and never surface to Ruby —constructing many Sandboxes amortises both costs automatically.

Buffer overflow policy (SPEC.md B-04): once an append would push the cumulative byte count past the per-channel ‘*_limit`, the OutputBuffer truncates — it stores a prefix that fits under the cap and appends a [truncated] marker on the next read. Truncation does NOT raise. The marker constant lives on Kobako::Sandbox::OutputBuffer::OUTPUT_TRUNCATION_MARKER.

Defined Under Namespace

Modules: OutcomeDecoder Classes: OutputBuffer

Constant Summary collapse

DEFAULT_OUTPUT_LIMIT =

Default per-channel capture ceiling: 1 MiB (SPEC.md B-01 footnote).

1 << 20

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wasm_path: nil, stdout_limit: nil, stderr_limit: nil) ⇒ Sandbox

Build a fresh Sandbox.

wasm_path is the absolute path to the Guest Binary; defaults to the gem-bundled data/kobako.wasm. stdout_limit and stderr_limit cap the per-run byte ceiling for each capture channel (default 1 MiB).



56
57
58
59
60
61
62
63
64
65
# File 'lib/kobako/sandbox.rb', line 56

def initialize(wasm_path: nil, stdout_limit: nil, stderr_limit: nil)
  @wasm_path = wasm_path || Kobako::Wasm.default_path
  @stdout_limit = stdout_limit || DEFAULT_OUTPUT_LIMIT
  @stderr_limit = stderr_limit || DEFAULT_OUTPUT_LIMIT
  @instance = Kobako::Wasm::Instance.from_path(@wasm_path)
  @stdout_buffer = OutputBuffer.new(@stdout_limit)
  @stderr_buffer = OutputBuffer.new(@stderr_limit)
  @services = Kobako::Registry.new
  @instance.set_registry(@services)
end

Instance Attribute Details

#instanceObject (readonly)

Returns the value of attribute instance.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def instance
  @instance
end

#servicesObject (readonly)

Returns the value of attribute services.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def services
  @services
end

#stderr_bufferObject (readonly)

Returns the value of attribute stderr_buffer.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def stderr_buffer
  @stderr_buffer
end

#stderr_limitObject (readonly)

Returns the value of attribute stderr_limit.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def stderr_limit
  @stderr_limit
end

#stdout_bufferObject (readonly)

Returns the value of attribute stdout_buffer.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def stdout_buffer
  @stdout_buffer
end

#stdout_limitObject (readonly)

Returns the value of attribute stdout_limit.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def stdout_limit
  @stdout_limit
end

#wasm_pathObject (readonly)

Returns the value of attribute wasm_path.



31
32
33
# File 'lib/kobako/sandbox.rb', line 31

def wasm_path
  @wasm_path
end

Instance Method Details

#define(name) ⇒ Object

Declare or retrieve the Service Group named name on this Sandbox (SPEC.md B-07, B-09, B-10). name must be a Symbol or String in constant form. Returns the Kobako::Registry::ServiceGroup.

Raises ArgumentError when called after #run, or when name does not match the constant-name pattern.



74
75
76
# File 'lib/kobako/sandbox.rb', line 74

def define(name)
  @services.define(name)
end

#run(source) ⇒ Object

Execute a guest mruby script (SPEC.md B-02 / B-03). source is the mruby source code as a UTF-8 String. Returns the deserialized last expression of the script.

Source delivery uses the WASI stdin two-frame protocol (SPEC.md ABI Signatures): Frame 1 carries the msgpack-encoded preamble (Service Group registry snapshot) and Frame 2 carries the user script UTF-8 bytes. Each frame is prefixed by a 4-byte big-endian u32 length.

Raises Kobako::TrapError on a Wasm trap or wire-violation fallback; Kobako::SandboxError when the guest ran to completion but failed; Kobako::ServiceError on an unrescued Service capability failure.

Raises:



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/kobako/sandbox.rb', line 92

def run(source)
  raise SandboxError, "source must be a String, got #{source.class}" unless source.is_a?(String)

  @services.seal!
  reset_run_state!
  preamble = @services.guest_preamble
  @instance.setup_wasi_pipes(@stdout_limit, @stderr_limit, preamble, source.b)

  invoke_guest_run
  drain_wasi_output
  outcome_bytes = read_outcome_bytes
  OutcomeDecoder.decode(outcome_bytes)
end

#stderrObject

Returns the complete byte content guest wrote to stderr during the most recent #run as a UTF-8 String, or an empty String before any #run call. SPEC.md B-04: may contain a [truncated] marker when the cap was hit.



47
48
49
# File 'lib/kobako/sandbox.rb', line 47

def stderr
  @stderr_buffer.to_s
end

#stdoutObject

Returns the complete byte content guest wrote to stdout during the most recent #run as a UTF-8 String, or an empty String before any #run call. SPEC.md B-04: may contain a [truncated] marker when the cap was hit.



39
40
41
# File 'lib/kobako/sandbox.rb', line 39

def stdout
  @stdout_buffer.to_s
end