microsandbox-rb 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Microsandbox
4
+ # A named persistent volume, from {Volume.create} / {Volume.get} / {Volume.list}.
5
+ #
6
+ # `path` is populated when returned from {Volume.create}; the storage stats
7
+ # (`kind`, `used_bytes`, …) are populated when returned from {Volume.get}/{Volume.list}.
8
+ class VolumeInfo
9
+ attr_reader :name, :path, :quota_mib, :used_bytes, :capacity_bytes,
10
+ :disk_format, :disk_fstype, :labels
11
+
12
+ def initialize(data)
13
+ @name = data["name"]
14
+ @path = data["path"]
15
+ @kind = data["kind"]
16
+ @quota_mib = data["quota_mib"]
17
+ @used_bytes = data["used_bytes"]
18
+ @capacity_bytes = data["capacity_bytes"]
19
+ @disk_format = data["disk_format"]
20
+ @disk_fstype = data["disk_fstype"]
21
+ @labels = data["labels"] || {}
22
+ @created_at_ms = data["created_at_ms"]
23
+ end
24
+
25
+ # @return [Symbol, nil] :directory or :disk
26
+ def kind
27
+ @kind&.to_sym
28
+ end
29
+
30
+ # @return [Time, nil]
31
+ def created_at
32
+ @created_at_ms && Time.at(@created_at_ms / 1000.0)
33
+ end
34
+
35
+ def inspect
36
+ "#<Microsandbox::VolumeInfo name=#{@name.inspect}#{@kind ? " kind=#{@kind}" : ""}>"
37
+ end
38
+ end
39
+
40
+ # Management of named persistent volumes. Mount them into a sandbox via
41
+ # `Sandbox.create(..., volumes: { "/data" => { named: "my-vol" } })`.
42
+ class Volume
43
+ class << self
44
+ # Create a named volume.
45
+ # @param name [String]
46
+ # @param kind ["dir", "disk"] storage kind (default "dir")
47
+ # @param size_mib [Integer, nil] required for kind "disk"
48
+ # @param quota_mib [Integer, nil] optional quota
49
+ # @param labels [Hash, nil]
50
+ # @return [VolumeInfo]
51
+ def create(name, kind: "dir", size_mib: nil, quota_mib: nil, labels: nil)
52
+ opts = { "kind" => kind.to_s }
53
+ opts["size_mib"] = Integer(size_mib) if size_mib
54
+ opts["quota_mib"] = Integer(quota_mib) if quota_mib
55
+ opts["labels"] = labels.each_with_object({}) { |(k, v), a| a[k.to_s] = v.to_s } if labels
56
+ VolumeInfo.new(Native::Volume.create(name.to_s, opts))
57
+ end
58
+
59
+ # Metadata for a volume.
60
+ # @return [VolumeInfo]
61
+ def get(name)
62
+ VolumeInfo.new(Native::Volume.get(name.to_s))
63
+ end
64
+
65
+ # All volumes.
66
+ # @return [Array<VolumeInfo>]
67
+ def list
68
+ Native::Volume.list.map { |info| VolumeInfo.new(info) }
69
+ end
70
+
71
+ # Remove a volume.
72
+ # @return [nil]
73
+ def remove(name)
74
+ Native::Volume.remove(name.to_s)
75
+ nil
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "microsandbox/version"
4
+
5
+ # Load the compiled native extension. Precompiled platform gems ship a
6
+ # version-specific subdirectory (e.g. lib/microsandbox/3.4/microsandbox_rb.bundle);
7
+ # fall back to the flat path used by source builds.
8
+ begin
9
+ ruby_version = RbConfig::CONFIG["ruby_version"].to_s
10
+ require_relative "microsandbox/#{ruby_version}/microsandbox_rb"
11
+ rescue LoadError
12
+ require_relative "microsandbox/microsandbox_rb"
13
+ end
14
+
15
+ require_relative "microsandbox/errors"
16
+ require_relative "microsandbox/exec_output"
17
+ require_relative "microsandbox/exec_handle"
18
+ require_relative "microsandbox/fs"
19
+ require_relative "microsandbox/metrics"
20
+ require_relative "microsandbox/log_entry"
21
+ require_relative "microsandbox/streams"
22
+ require_relative "microsandbox/image"
23
+ require_relative "microsandbox/volume"
24
+ require_relative "microsandbox/snapshot"
25
+ require_relative "microsandbox/sandbox"
26
+
27
+ # Microsandbox — lightweight microVM sandboxes for Ruby.
28
+ #
29
+ # The runtime is embedded directly in the process via a Rust native extension;
30
+ # there is no daemon to install and no server to connect to. Creating a sandbox
31
+ # spawns a real microVM as a child process.
32
+ #
33
+ # @example
34
+ # Microsandbox::Sandbox.create("hello", image: "python") do |sb|
35
+ # puts sb.exec("python", ["-c", "print('Hello, World!')"]).stdout
36
+ # end
37
+ module Microsandbox
38
+ class << self
39
+ # @return [String] the gem version
40
+ def version
41
+ VERSION
42
+ end
43
+
44
+ # Download and install the `msb` runtime + `libkrunfw` into
45
+ # `~/.microsandbox` (idempotent). Usually unnecessary: the native
46
+ # extension provisions the runtime at build time.
47
+ # @return [nil]
48
+ def install
49
+ Native.install
50
+ nil
51
+ end
52
+
53
+ # @return [Boolean] whether the runtime is installed and resolvable
54
+ def installed?
55
+ Native.installed?
56
+ end
57
+
58
+ # @return [String] the resolved path to the `msb` runtime binary
59
+ def runtime_path
60
+ Native.resolved_msb_path
61
+ end
62
+
63
+ # Override the `msb` runtime path (highest-priority SDK tier of the
64
+ # resolver, below only the `MSB_PATH` environment variable).
65
+ # @param path [String]
66
+ # @return [void]
67
+ def runtime_path=(path)
68
+ Native.set_runtime_msb_path(path.to_s)
69
+ end
70
+
71
+ # Latest resource-usage snapshot for every running sandbox, keyed by name.
72
+ # Mirrors the official `all_sandbox_metrics`/`allSandboxMetrics` helpers.
73
+ # @return [Hash{String => Metrics}]
74
+ def all_sandbox_metrics
75
+ Native.all_sandbox_metrics.transform_values { |m| Metrics.new(m) }
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,5 @@
1
+ # The microsandbox core crate uses Rust edition 2024 and pulls in dependencies
2
+ # (e.g. smoltcp) that require a recent compiler. Stable >= 1.91 is the minimum
3
+ # supported Rust version (MSRV) for building this gem from source.
4
+ [toolchain]
5
+ channel = "stable"
@@ -0,0 +1,321 @@
1
+ # Type signatures for the public microsandbox Ruby API.
2
+
3
+ module Microsandbox
4
+ VERSION: String
5
+
6
+ def self.version: () -> String
7
+ def self.install: () -> nil
8
+ def self.installed?: () -> bool
9
+ def self.runtime_path: () -> String
10
+ def self.runtime_path=: (String path) -> void
11
+ def self.all_sandbox_metrics: () -> Hash[String, Metrics]
12
+
13
+ class Error < StandardError
14
+ def self.code: () -> String
15
+ def code: () -> String
16
+ end
17
+
18
+ class InvalidConfigError < Error end
19
+ class SandboxNotFoundError < Error end
20
+ class SandboxNotRunningError < Error end
21
+ class SandboxAlreadyExistsError < Error end
22
+ class SandboxStillRunningError < Error end
23
+ class ExecTimeoutError < Error end
24
+ class ExecFailedError < Error end
25
+ class FilesystemError < Error end
26
+ class PathNotFoundError < Error end
27
+ class VolumeNotFoundError < Error end
28
+ class VolumeAlreadyExistsError < Error end
29
+ class ImageNotFoundError < Error end
30
+ class ImageInUseError < Error end
31
+ class ImagePullFailedError < Error end
32
+ class NetworkPolicyError < Error end
33
+ class SecretViolationError < Error end
34
+ class TlsError < Error end
35
+ class IoError < Error end
36
+ class MetricsDisabledError < Error end
37
+ class MetricsUnavailableError < Error end
38
+ class UnsupportedOperationError < Error end
39
+
40
+ class ExecOutput
41
+ def initialize: (Hash[String, untyped] data) -> void
42
+ def exit_code: () -> Integer
43
+ def success?: () -> bool
44
+ def failure?: () -> bool
45
+ def stdout: () -> String
46
+ def stderr: () -> String
47
+ def stdout_bytes: () -> String
48
+ def stderr_bytes: () -> String
49
+ def to_s: () -> String
50
+ end
51
+
52
+ class FsEntry
53
+ def path: () -> String
54
+ def name: () -> String
55
+ def type: () -> Symbol
56
+ def size: () -> Integer
57
+ def mode: () -> Integer
58
+ def modified: () -> Time?
59
+ def file?: () -> bool
60
+ def directory?: () -> bool
61
+ def symlink?: () -> bool
62
+ end
63
+
64
+ class FsMetadata
65
+ def type: () -> Symbol
66
+ def size: () -> Integer
67
+ def mode: () -> Integer
68
+ def readonly?: () -> bool
69
+ def file?: () -> bool
70
+ def directory?: () -> bool
71
+ def symlink?: () -> bool
72
+ def modified: () -> Time?
73
+ def created: () -> Time?
74
+ end
75
+
76
+ class FS
77
+ def read: (String path) -> String
78
+ def read_text: (String path) -> String
79
+ def write: (String path, String data) -> nil
80
+ def list: (String path) -> Array[FsEntry]
81
+ def mkdir: (String path) -> nil
82
+ def remove: (String path) -> nil
83
+ def remove_dir: (String path) -> nil
84
+ def copy: (String src, String dst) -> nil
85
+ def rename: (String src, String dst) -> nil
86
+ def exists?: (String path) -> bool
87
+ def stat: (String path) -> FsMetadata
88
+ def copy_from_host: (String host_path, String guest_path) -> nil
89
+ def copy_to_host: (String guest_path, String host_path) -> nil
90
+ end
91
+
92
+ class Metrics
93
+ def cpu_percent: () -> Float
94
+ def vcpu_time_ns: () -> Integer
95
+ def memory_bytes: () -> Integer
96
+ def memory_available_bytes: () -> Integer?
97
+ def memory_host_resident_bytes: () -> Integer?
98
+ def memory_limit_bytes: () -> Integer
99
+ def disk_read_bytes: () -> Integer
100
+ def disk_write_bytes: () -> Integer
101
+ def net_rx_bytes: () -> Integer
102
+ def net_tx_bytes: () -> Integer
103
+ def uptime_secs: () -> Float
104
+ def timestamp: () -> Time
105
+ end
106
+
107
+ class LogEntry
108
+ def source: () -> Symbol
109
+ def session_id: () -> Integer?
110
+ def cursor: () -> String
111
+ def data: () -> String
112
+ def text: () -> String
113
+ def timestamp: () -> Time
114
+ end
115
+
116
+ class SandboxInfo
117
+ def name: () -> String
118
+ def status: () -> Symbol
119
+ def running?: () -> bool
120
+ def stopped?: () -> bool
121
+ def created_at: () -> Time?
122
+ def updated_at: () -> Time?
123
+ end
124
+
125
+ class SandboxStopResult
126
+ def name: () -> String
127
+ def status: () -> Symbol
128
+ def exit_code: () -> Integer?
129
+ def signal: () -> Integer?
130
+ def source: () -> String?
131
+ def stopped?: () -> bool
132
+ def crashed?: () -> bool
133
+ def observed_at: () -> Time
134
+ end
135
+
136
+ class Sandbox
137
+ def self.create: (String name, ?image: String?, ?cpus: Integer?, ?memory: Integer?,
138
+ ?env: Hash[untyped, untyped]?, ?workdir: String?, ?shell: String?,
139
+ ?user: String?, ?hostname: String?, ?labels: Hash[untyped, untyped]?,
140
+ ?scripts: Hash[untyped, untyped]?, ?entrypoint: Array[String]?,
141
+ ?ports: Hash[untyped, untyped]?, ?ports_udp: Hash[untyped, untyped]?,
142
+ ?volumes: Hash[untyped, untyped]?, ?network: untyped?, ?from_snapshot: String?,
143
+ ?log_level: (String | Symbol)?, ?quiet_logs: bool, ?security: (String | Symbol)?,
144
+ ?oci_upper_size: Integer?, ?max_duration: Integer?, ?idle_timeout: Integer?,
145
+ ?rlimits: Hash[untyped, untyped]?, ?pull_policy: (String | Symbol)?,
146
+ ?secrets: Array[Hash[untyped, untyped]]?, ?detached: bool,
147
+ ?replace: bool, ?replace_with_timeout: Numeric?)
148
+ ?{ (Sandbox) -> untyped } -> untyped
149
+ def self.start: (String name, ?detached: bool) -> Sandbox
150
+ def self.get: (String name) -> SandboxInfo
151
+ def self.list: () -> Array[SandboxInfo]
152
+ def self.list_with: (?labels: Hash[untyped, untyped]) -> Array[SandboxInfo]
153
+ def self.remove: (String name) -> nil
154
+
155
+ def name: () -> String
156
+ def exec: (String command, ?Array[String] args, ?cwd: String?, ?user: String?,
157
+ ?env: Hash[untyped, untyped]?, ?timeout: Numeric?, ?tty: bool, ?stdin: String?,
158
+ ?rlimits: Hash[untyped, untyped]?) -> ExecOutput
159
+ def shell: (String script, ?cwd: String?, ?user: String?, ?env: Hash[untyped, untyped]?,
160
+ ?timeout: Numeric?, ?tty: bool, ?stdin: String?, ?rlimits: Hash[untyped, untyped]?) -> ExecOutput
161
+ def exec_stream: (String command, ?Array[String] args, ?cwd: String?, ?user: String?,
162
+ ?env: Hash[untyped, untyped]?, ?timeout: Numeric?, ?tty: bool, ?stdin: String?,
163
+ ?rlimits: Hash[untyped, untyped]?) -> ExecHandle
164
+ def shell_stream: (String script, ?cwd: String?, ?user: String?, ?env: Hash[untyped, untyped]?,
165
+ ?timeout: Numeric?, ?tty: bool, ?stdin: String?, ?rlimits: Hash[untyped, untyped]?) -> ExecHandle
166
+ def fs: () -> FS
167
+ def metrics: () -> Metrics
168
+ def logs: (?tail: Integer?, ?since_ms: Numeric?, ?until_ms: Numeric?,
169
+ ?sources: Array[String | Symbol]?) -> Array[LogEntry]
170
+ def metrics_stream: (?interval: Numeric) -> MetricsStream
171
+ def log_stream: (?sources: Array[String | Symbol]?, ?since_ms: Numeric?,
172
+ ?from_cursor: String?, ?until_ms: Numeric?, ?follow: bool) -> LogStream
173
+ def stop: (?timeout: Numeric?) -> nil
174
+ def kill: (?timeout: Numeric?) -> nil
175
+ def request_stop: () -> nil
176
+ def request_kill: () -> nil
177
+ def request_drain: () -> nil
178
+ def wait_until_stopped: () -> SandboxStopResult
179
+ def owns_lifecycle?: () -> bool
180
+ def detach: () -> nil
181
+ end
182
+
183
+ class LogStream
184
+ include Enumerable[LogEntry]
185
+ def each: () { (LogEntry) -> void } -> self
186
+ | () -> Enumerator[LogEntry, self]
187
+ end
188
+
189
+ class MetricsStream
190
+ include Enumerable[Metrics]
191
+ def each: () { (Metrics) -> void } -> self
192
+ | () -> Enumerator[Metrics, self]
193
+ end
194
+
195
+ class ExecEvent
196
+ def type: () -> Symbol
197
+ def pid: () -> Integer?
198
+ def code: () -> Integer?
199
+ def data: () -> String?
200
+ def text: () -> String?
201
+ def started?: () -> bool
202
+ def stdout?: () -> bool
203
+ def stderr?: () -> bool
204
+ def exited?: () -> bool
205
+ def failed?: () -> bool
206
+ def stdin_error?: () -> bool
207
+ end
208
+
209
+ class ExitStatus
210
+ def exit_code: () -> Integer
211
+ def success?: () -> bool
212
+ def failure?: () -> bool
213
+ end
214
+
215
+ class ExecStdin
216
+ def write: (untyped data) -> self
217
+ def close: () -> nil
218
+ end
219
+
220
+ class ExecHandle
221
+ include Enumerable[ExecEvent]
222
+ def id: () -> String
223
+ def each: () { (ExecEvent) -> void } -> self
224
+ | () -> Enumerator[ExecEvent, self]
225
+ def wait: () -> ExitStatus
226
+ def collect: () -> ExecOutput
227
+ def signal: (Integer sig) -> nil
228
+ def kill: () -> nil
229
+ def resize: (Integer rows, Integer cols) -> nil
230
+ def stdin: () -> ExecStdin?
231
+ end
232
+
233
+ class ImageInfo
234
+ def reference: () -> String
235
+ def size_bytes: () -> Integer?
236
+ def manifest_digest: () -> String?
237
+ def architecture: () -> String?
238
+ def os: () -> String?
239
+ def layer_count: () -> Integer
240
+ def created_at: () -> Time?
241
+ def last_used_at: () -> Time?
242
+ end
243
+
244
+ class ImageDetail
245
+ def handle: () -> ImageInfo
246
+ def config: () -> Hash[String, untyped]?
247
+ def layers: () -> Array[Hash[String, untyped]]
248
+ def reference: () -> String
249
+ end
250
+
251
+ class ImagePruneReport
252
+ def image_refs_removed: () -> Integer
253
+ def manifests_removed: () -> Integer
254
+ def layers_removed: () -> Integer
255
+ def fsmeta_removed: () -> Integer
256
+ def vmdk_removed: () -> Integer
257
+ def bytes_reclaimed: () -> Integer?
258
+ end
259
+
260
+ class Image
261
+ def self.list: () -> Array[ImageInfo]
262
+ def self.get: (String reference) -> ImageInfo
263
+ def self.inspect: (?String? reference) -> (ImageDetail | String)
264
+ def self.remove: (String reference, ?force: bool) -> nil
265
+ def self.prune: () -> ImagePruneReport
266
+ end
267
+
268
+ class VolumeInfo
269
+ def name: () -> String
270
+ def path: () -> String?
271
+ def kind: () -> Symbol?
272
+ def quota_mib: () -> Integer?
273
+ def used_bytes: () -> Integer?
274
+ def capacity_bytes: () -> Integer?
275
+ def disk_format: () -> String?
276
+ def disk_fstype: () -> String?
277
+ def labels: () -> Hash[String, String]
278
+ def created_at: () -> Time?
279
+ end
280
+
281
+ class Volume
282
+ def self.create: (String name, ?kind: String, ?size_mib: Integer?, ?quota_mib: Integer?,
283
+ ?labels: Hash[untyped, untyped]?) -> VolumeInfo
284
+ def self.get: (String name) -> VolumeInfo
285
+ def self.list: () -> Array[VolumeInfo]
286
+ def self.remove: (String name) -> nil
287
+ end
288
+
289
+ class SnapshotInfo
290
+ def digest: () -> String
291
+ def path: () -> String
292
+ def name: () -> String?
293
+ def parent_digest: () -> String?
294
+ def image_ref: () -> String?
295
+ def size_bytes: () -> Integer?
296
+ def format: () -> Symbol?
297
+ def created_at: () -> Time?
298
+ end
299
+
300
+ class SnapshotVerifyReport
301
+ def digest: () -> String
302
+ def path: () -> String
303
+ def status: () -> Symbol
304
+ def algorithm: () -> String?
305
+ def content_digest: () -> String?
306
+ def verified?: () -> bool
307
+ def not_recorded?: () -> bool
308
+ end
309
+
310
+ class Snapshot
311
+ def self.create: (String source_sandbox, ?name: String?, ?path: String?,
312
+ ?labels: Hash[untyped, untyped]?, ?force: bool, ?record_integrity: bool) -> SnapshotInfo
313
+ def self.get: (String name_or_digest) -> SnapshotInfo
314
+ def self.list: () -> Array[SnapshotInfo]
315
+ def self.remove: (String name_or_path, ?force: bool) -> nil
316
+ def self.verify: (String name_or_path) -> SnapshotVerifyReport
317
+ def self.export: (String name_or_path, String out_path, ?with_parents: bool,
318
+ ?with_image: bool, ?plain_tar: bool) -> nil
319
+ def self.import: (String archive_path, ?dest: String?) -> SnapshotInfo
320
+ end
321
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: microsandbox-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.7
5
+ platform: ruby
6
+ authors:
7
+ - ya-luotao
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rb_sys
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.9.91
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.9.91
26
+ description: |
27
+ The microsandbox-rb gem provides native bindings to the microsandbox runtime via
28
+ a Rust extension (magnus). It spins up real microVMs (not containers) in under
29
+ 100ms, runs standard OCI (Docker) images, and gives you full control over
30
+ command execution, the guest filesystem, networking, volumes, snapshots, SSH,
31
+ and secrets — all from an idiomatic, synchronous Ruby API. No daemon, no server
32
+ to connect to: the runtime is embedded directly in your process.
33
+ email:
34
+ - luotao@hey.com
35
+ executables: []
36
+ extensions:
37
+ - ext/microsandbox/extconf.rb
38
+ extra_rdoc_files: []
39
+ files:
40
+ - CHANGELOG.md
41
+ - Cargo.lock
42
+ - Cargo.toml
43
+ - DESIGN.md
44
+ - LICENSE
45
+ - README.md
46
+ - ext/microsandbox/Cargo.toml
47
+ - ext/microsandbox/extconf.rb
48
+ - ext/microsandbox/src/conv.rs
49
+ - ext/microsandbox/src/error.rs
50
+ - ext/microsandbox/src/exec.rs
51
+ - ext/microsandbox/src/image.rs
52
+ - ext/microsandbox/src/lib.rs
53
+ - ext/microsandbox/src/runtime.rs
54
+ - ext/microsandbox/src/sandbox.rs
55
+ - ext/microsandbox/src/snapshot.rs
56
+ - ext/microsandbox/src/stream.rs
57
+ - ext/microsandbox/src/volume.rs
58
+ - lib/microsandbox.rb
59
+ - lib/microsandbox/errors.rb
60
+ - lib/microsandbox/exec_handle.rb
61
+ - lib/microsandbox/exec_output.rb
62
+ - lib/microsandbox/fs.rb
63
+ - lib/microsandbox/image.rb
64
+ - lib/microsandbox/log_entry.rb
65
+ - lib/microsandbox/metrics.rb
66
+ - lib/microsandbox/sandbox.rb
67
+ - lib/microsandbox/snapshot.rb
68
+ - lib/microsandbox/streams.rb
69
+ - lib/microsandbox/version.rb
70
+ - lib/microsandbox/volume.rb
71
+ - rust-toolchain.toml
72
+ - sig/microsandbox.rbs
73
+ homepage: https://github.com/ya-luotao/microsandbox-rb
74
+ licenses:
75
+ - Apache-2.0
76
+ metadata:
77
+ homepage_uri: https://github.com/ya-luotao/microsandbox-rb
78
+ source_code_uri: https://github.com/ya-luotao/microsandbox-rb
79
+ documentation_uri: https://github.com/ya-luotao/microsandbox-rb#readme
80
+ changelog_uri: https://github.com/ya-luotao/microsandbox-rb/blob/main/CHANGELOG.md
81
+ rubygems_mfa_required: 'true'
82
+ cargo_crate_name: microsandbox_rb
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 3.1.0
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 3.3.11
96
+ requirements: []
97
+ rubygems_version: 3.6.9
98
+ specification_version: 4
99
+ summary: Lightweight microVM sandboxes for Ruby — run AI agents and untrusted code
100
+ with hardware-level isolation.
101
+ test_files: []