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/root_disk.rb,
lib/microsandbox/exec_handle.rb,
lib/microsandbox/exec_output.rb,
lib/microsandbox/backend_info.rb,
lib/microsandbox/modification.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, RootDisk, Rule Classes: AgentClient, AgentFrame, AgentStream, BackendInfo, Error, ExecEvent, ExecHandle, ExecOutput, ExecStdin, ExitStatus, FS, FsEntry, FsMetadata, FsReadStream, FsWriteSink, Image, ImageDetail, ImageInfo, ImagePruneReport, InvalidConfigError, LogEntry, LogStream, Metrics, MetricsStream, ModificationPlan, NetworkPolicy, PingResult, PullSession, Sandbox, SandboxHandle, SandboxPage, SandboxStopResult, SftpClient, Snapshot, SnapshotInfo, SnapshotVerifyReport, SshClient, SshOps, SshOutput, SshServer, TouchResult, UnsupportedError, 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.15.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.14"

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:



257
258
259
# File 'lib/microsandbox.rb', line 257

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



269
270
271
272
# File 'lib/microsandbox.rb', line 269

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

.default_backend_infoBackendInfo

Secret-safe description of the active default backend (runtime v0.6.9). Like default_backend_kind, the first call freezes ambient env/profile resolution for the process. The API key is never included.

Returns:



250
251
252
# File 'lib/microsandbox.rb', line 250

def default_backend_info
  BackendInfo.new(Native.default_backend_info)
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.



242
243
244
# File 'lib/microsandbox.rb', line 242

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 a freshly installed gem gets a working runtime without a manual install step.

Runs at most once per process. When the companion microsandbox-rb-binaries gem supplies the runtime (it was activated at load time and its msb is what the resolver now returns from runtime_path), nothing is downloaded or touched in ~/.microsandbox — the bundled binaries are already the matching version. Opt out of the download 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)


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/microsandbox.rb', line 130

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
  # The binaries gem won the resolver: its vendored msb (and the libkrunfw
  # beside it) are exactly the version this gem was built for, so there is
  # nothing to verify or download. (If `MSB_PATH` overrides it, the user owns
  # the runtime and we fall through to the existing behaviour.)
  if bundled_runtime_active?
    @runtime_ready = true
    return
  end
  # 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, " \
         "or install the microsandbox-rb-binaries gem to ship it with your bundle)..."
  end
  install
  @runtime_ready = true
  nil
end

.installnil

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

This gem is SDK-only: nothing is provisioned at build/install time. The runtime comes from the companion microsandbox-rb-binaries gem when it is installed (see ensure_runtime!); otherwise it is fetched into ~/.microsandbox on first use. 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. Not needed — and not used — when the binaries gem supplies the runtime.

Returns:

  • (nil)


75
76
77
78
# File 'lib/microsandbox.rb', line 75

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



100
101
102
# File 'lib/microsandbox.rb', line 100

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)


192
193
194
# File 'lib/microsandbox.rb', line 192

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



164
165
166
# File 'lib/microsandbox.rb', line 164

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=.

The companion microsandbox-rb-binaries gem claims this same slot when require "microsandbox" activates it, so with that gem installed this setter is a no-op — use MSB_PATH to override a bundled runtime.

Parameters:

  • path (String)


178
179
180
181
182
183
184
# File 'lib/microsandbox.rb', line 178

def runtime_path=(path)
  if @bundled_msb_path && path.to_s != @bundled_msb_path
    warn "[microsandbox] runtime_path= ignored: the microsandbox-rb-binaries gem already " \
         "claimed the set-once SDK slot (#{@bundled_msb_path}); set MSB_PATH to override it"
  end
  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"



60
61
62
# File 'lib/microsandbox.rb', line 60

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_BACKENDMSB_PROFILE~/.microsandbox/config.json) is resolved lazily on first use. Since runtime v0.6.9 a bare MSB_API_KEY no longer selects the cloud — cloud intent must be explicit via MSB_BACKEND=cloud (paired with MSB_API_URL/MSB_API_KEY), a cloud profile, or this method; invalid cloud config raises InvalidConfigError instead of falling back to local. 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)


211
212
213
# File 'lib/microsandbox.rb', line 211

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)


89
90
91
92
93
94
95
96
97
# File 'lib/microsandbox.rb', line 89

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



51
52
53
# File 'lib/microsandbox.rb', line 51

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



231
232
233
234
235
236
237
238
# File 'lib/microsandbox.rb', line 231

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