Module: Microsandbox

Defined in:
lib/microsandbox.rb,
lib/microsandbox/fs.rb,
lib/microsandbox/ssh.rb,
lib/microsandbox/agent.rb,
lib/microsandbox/image.rb,
lib/microsandbox/patch.rb,
lib/microsandbox/errors.rb,
lib/microsandbox/volume.rb,
lib/microsandbox/metrics.rb,
lib/microsandbox/network.rb,
lib/microsandbox/sandbox.rb,
lib/microsandbox/streams.rb,
lib/microsandbox/version.rb,
lib/microsandbox/snapshot.rb,
lib/microsandbox/log_entry.rb,
lib/microsandbox/exec_handle.rb,
lib/microsandbox/exec_output.rb,
sig/microsandbox.rbs

Overview

Microsandbox — lightweight microVM sandboxes for Ruby.

The runtime is embedded directly in the process via a Rust native extension; there is no daemon to install and no server to connect to. Creating a sandbox spawns a real microVM as a child process.

Examples:

Microsandbox::Sandbox.create("hello", image: "python") do |sb|
  puts sb.exec("python", ["-c", "print('Hello, World!')"]).stdout
end

Defined Under Namespace

Modules: Destination, Patch, Rule Classes: AgentClient, AgentFrame, AgentStream, Error, ExecEvent, ExecHandle, ExecOutput, ExecStdin, ExitStatus, FS, FsEntry, FsMetadata, FsReadStream, FsWriteSink, Image, ImageDetail, ImageInfo, ImagePruneReport, InvalidConfigError, LogEntry, LogStream, Metrics, MetricsStream, NetworkPolicy, PullSession, Sandbox, SandboxHandle, SandboxStopResult, SftpClient, Snapshot, SnapshotInfo, SnapshotVerifyReport, SshClient, SshOps, SshOutput, SshServer, Volume, VolumeFs, VolumeInfo

Constant Summary collapse

SandboxInfo =
Deprecated.

since v0.5.8. Microsandbox::Sandbox.get/Microsandbox::Sandbox.list now return a controllable SandboxHandle; this constant remains as an alias so code that referenced the old read-only metadata type by name (e.g. is_a? checks) still resolves. Note it is now the same class as SandboxHandle, whose constructor takes a native handle, not the metadata Hash the old SandboxInfo.new accepted — construct via Microsandbox::Sandbox.get/Microsandbox::Sandbox.list.

SandboxHandle
VERSION =

Gem version. Versioned independently of the upstream microsandbox runtime it embeds: the gem follows its own semver (while 0.x, breaking changes bump the minor and fixes bump the patch), so the number does NOT track the upstream tag one-to-one. Consult RUNTIME_VERSION for the wrapped runtime, and the Versioning section of the README for the full gem-to-runtime map. Must equal the native ext's Cargo crate version (Native.version), enforced by spec/unit/version_spec.rb.

Returns:

  • (String)
"0.9.0"
RUNTIME_VERSION =

The upstream microsandbox runtime release this gem build embeds — the tag pinned on the microsandbox/microsandbox-network git deps in ext/microsandbox/Cargo.toml. Exposed at runtime as runtime_version. spec/unit/version_spec.rb asserts it stays in sync with the Cargo tag so it can't silently drift out of date.

Returns:

  • (String)
"v0.6.1"

Class Method Summary collapse

Class Method Details

.all_sandbox_metricsHash{String => Metrics}

Latest resource-usage snapshot for every running sandbox, keyed by name. Mirrors the official all_sandbox_metrics/allSandboxMetrics helpers.

Returns:



220
221
222
# File 'lib/microsandbox.rb', line 220

def all_sandbox_metrics
  Native.all_sandbox_metrics.transform_values { |m| Metrics.new(m) }
end

.coerce_write_bytes(data) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Coerce write data to a binary-safe String, or raise. Centralizes the contract every #write shares (FS/SftpClient/VolumeFs/ExecStdin/ FsWriteSink): accept a String and reject anything else loudly, instead of silently writing its to_s form (e.g. a StringIO's inspect or "42").

Parameters:

  • data (Object)

Returns:

  • (String)

Raises:

  • (TypeError)

    unless data is a String



232
233
234
235
# File 'lib/microsandbox.rb', line 232

def coerce_write_bytes(data)
  String.try_convert(data) or
    raise TypeError, "data must be a String (got #{data.class})"
end

.default_backend_kindSymbol

Returns the active default backend kind, :local or :cloud. The first call resolves the env/profile/config ladder.

Returns:

  • (Symbol)

    the active default backend kind, :local or :cloud. The first call resolves the env/profile/config ladder.



213
214
215
# File 'lib/microsandbox.rb', line 213

def default_backend_kind
  Native.default_backend_kind.to_sym
end

.ensure_runtime!nil

Ensure the msb runtime + libkrunfw are present and version-matched, provisioning them on first use if not. Called automatically by Microsandbox::Sandbox.create/Microsandbox::Sandbox.start so precompiled-gem users (who never ran the source build) get a working runtime without a manual install step.

Runs at most once per process. Opt out by setting MICROSANDBOX_NO_AUTO_INSTALL (e.g. air-gapped hosts that provision the runtime out of band); the runtime is then left untouched and a missing or stale one surfaces at the operation itself.

NOTE: this delegates to install even when installed? is already true, rather than short-circuiting on presence. installed? (upstream verify_installation) only confirms the msb/libkrunfw files exist, not that their version matches the runtime this gem build links. install is idempotent and version-correcting: it runs a cheap msb --version and re-downloads ONLY when the binary is absent or its version differs, then no-ops. A presence-only short-circuit would let a stale msb left in ~/.microsandbox by an older gem pass, then fail every Microsandbox::Sandbox.create on a host↔guest wire-protocol mismatch (e.g. a v0.5.8 msb rejecting the --config-fd flag the v0.5.10 runtime passes). Keep the install call on this path — do not "optimize" it back to skip-when-present.

Returns:

  • (nil)


122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/microsandbox.rb', line 122

def ensure_runtime!
  return if @runtime_ready
  # A cloud backend has no local msb/libkrunfw runtime to provision: skip the
  # presence check and the first-use download entirely. Resolving the kind
  # uses the same lazy env/profile/config ladder every operation already
  # consults, so this adds no work for local hosts (the common case).
  return if default_backend_kind == :cloud
  # Opted out: the caller manages the runtime out of band, so don't fetch,
  # verify, or repair it here. Memoize the decision (the env var is stable for
  # the process); the operation resolves `msb` itself and surfaces any problem.
  if auto_install_disabled?
    @runtime_ready = true
    return
  end

  unless installed?
    warn "[microsandbox] runtime (msb + libkrunfw) not found; " \
         "downloading to ~/.microsandbox (set MICROSANDBOX_NO_AUTO_INSTALL to skip)..."
  end
  install
  @runtime_ready = true
  nil
end

.installnil

Download and install the msb runtime + libkrunfw into ~/.microsandbox (idempotent).

When the gem is built from source, the native extension provisions the runtime at build time, so this is usually a no-op. Precompiled platform gems (which skip the local Rust build) do NOT provision it that way, so the runtime is fetched on first use — see ensure_runtime!. Call this explicitly to provision ahead of time (e.g. while baking a container image) so the first Microsandbox::Sandbox.create doesn't pay the download.

Returns:

  • (nil)


71
72
73
74
# File 'lib/microsandbox.rb', line 71

def install
  Native.install
  nil
end

.installed?Boolean

Returns whether the runtime is installed and resolvable.

Returns:

  • (Boolean)

    whether the runtime is installed and resolvable



96
97
98
# File 'lib/microsandbox.rb', line 96

def installed?
  Native.installed?
end

.libkrunfw_path=(path) ⇒ void

This method returns an undefined value.

Override the libkrunfw shared-library path (SDK tier of the resolver, below the MSB_LIBKRUNFW_PATH environment variable). Process-level and set-once: a second call is silently ignored, and the env var still wins. Mirrors runtime_path= for libkrunfw.

Parameters:

  • path (String)


167
168
169
# File 'lib/microsandbox.rb', line 167

def libkrunfw_path=(path)
  Native.set_runtime_libkrunfw_path(path.to_s)
end

.runtime_pathString

Returns the resolved path to the msb runtime binary.

Returns:

  • (String)

    the resolved path to the msb runtime binary



147
148
149
# File 'lib/microsandbox.rb', line 147

def runtime_path
  Native.resolved_msb_path
end

.runtime_path=(path) ⇒ void

This method returns an undefined value.

Override the msb runtime path (highest-priority SDK tier of the resolver, below only the MSB_PATH environment variable). Process-level and set-once: a second call is silently ignored, and the MSB_PATH environment variable still wins. Mirrors libkrunfw_path=.

Parameters:

  • path (String)


157
158
159
# File 'lib/microsandbox.rb', line 157

def runtime_path=(path)
  Native.set_runtime_msb_path(path.to_s)
end

.runtime_versionString

The upstream microsandbox runtime release this gem build embeds (the git tag pinned in ext/microsandbox/Cargo.toml). The gem's own version is versioned independently of this, so consult this to learn which runtime is wrapped. See the Versioning section of the README for the full map.

Returns:

  • (String)

    e.g. "v0.5.8"



57
58
59
# File 'lib/microsandbox.rb', line 57

def runtime_version
  RUNTIME_VERSION
end

.set_default_backend(kind, url: nil, api_key: nil, profile: nil) ⇒ void

This method returns an undefined value.

Install a process-wide default backend (v0.5.8 backend routing). Without a call to this, operations use a local libkrun backend; the env/profile ladder (MSB_BACKEND, MSB_API_URL+MSB_API_KEY, MSB_PROFILE, ~/.microsandbox/config.json) is resolved lazily on first use. Call once at startup, before any sandbox operations.

Parameters:

  • kind ("local", "cloud", Symbol)

    backend kind

  • url (String, nil) (defaults to: nil)

    cloud control-plane URL (cloud, unless profile:)

  • api_key (String, nil) (defaults to: nil)

    cloud API key (cloud, unless profile:)

  • profile (String, nil) (defaults to: nil)

    named profile from ~/.microsandbox/config.json

  • url: (String, nil) (defaults to: nil)
  • api_key: (String, nil) (defaults to: nil)
  • profile: (String, nil) (defaults to: nil)


182
183
184
# File 'lib/microsandbox.rb', line 182

def set_default_backend(kind, url: nil, api_key: nil, profile: nil)
  Native.set_default_backend(kind.to_s, url&.to_s, api_key&.to_s, profile&.to_s)
end

.setup(base_dir: nil, version: nil, force: false, skip_verify: false) ⇒ nil

Customizable install via the core Setup builder. Like install but with control over where and what to install — mirrors the Node Setup builder.

Parameters:

  • base_dir (String, nil) (defaults to: nil)

    install root (default ~/.microsandbox)

  • version (String, nil) (defaults to: nil)

    pin the runtime version to download

  • force (Boolean) (defaults to: false)

    re-download even if binaries already exist — the way to repair a corrupt/incomplete ~/.microsandbox

  • skip_verify (Boolean) (defaults to: false)

    skip the post-install verification step

  • base_dir: (String, nil) (defaults to: nil)
  • version: (String, nil) (defaults to: nil)
  • force: (Boolean) (defaults to: false)
  • skip_verify: (Boolean) (defaults to: false)

Returns:

  • (nil)


85
86
87
88
89
90
91
92
93
# File 'lib/microsandbox.rb', line 85

def setup(base_dir: nil, version: nil, force: false, skip_verify: false)
  opts = {}
  opts["base_dir"] = base_dir.to_s if base_dir
  opts["version"] = version.to_s if version
  opts["force"] = true if force
  opts["skip_verify"] = true if skip_verify
  Native.setup(opts)
  nil
end

.versionString

Returns the gem version.

Returns:

  • (String)

    the gem version



48
49
50
# File 'lib/microsandbox.rb', line 48

def version
  VERSION
end

.with_backend(kind, url: nil, api_key: nil, profile: nil) { ... } ⇒ Object

Run the given block with a temporary default backend, restoring the previous one afterward (even on error). NOTE: the swap is process-wide while the block runs, not fiber/thread-local — concurrent threads observe the temporary backend. It is also NOT safe to call from multiple threads at once: two interleaved with_backend calls can restore each other's saved backend out of order and leave a temporary backend installed permanently. Use it only when no other thread is changing the backend, and avoid calling set_default_backend inside the block (the restore on exit would overwrite that change). Mirrors the official SDKs' scoped-backend helper.

Parameters:

  • kind ("local", "cloud", Symbol)
  • url (String, nil) (defaults to: nil)
  • api_key (String, nil) (defaults to: nil)
  • profile (String, nil) (defaults to: nil)

Yields:

  • with the temporary backend installed

Returns:

  • (Object)

    the block's return value



202
203
204
205
206
207
208
209
# File 'lib/microsandbox.rb', line 202

def with_backend(kind, url: nil, api_key: nil, profile: nil)
  token = Native.push_default_backend(kind.to_s, url&.to_s, api_key&.to_s, profile&.to_s)
  begin
    yield
  ensure
    Native.pop_default_backend(token)
  end
end