microsandbox-rb 0.13.0 → 0.15.0

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.
data/lib/microsandbox.rb CHANGED
@@ -64,12 +64,13 @@ module Microsandbox
64
64
  # Download and install the `msb` runtime + `libkrunfw` into
65
65
  # `~/.microsandbox` (idempotent).
66
66
  #
67
- # When the gem is built from source, the native extension provisions the
68
- # runtime at build time, so this is usually a no-op. Precompiled platform
69
- # gems (which skip the local Rust build) do NOT provision it that way, so the
70
- # runtime is fetched on first use — see {ensure_runtime!}. Call this
71
- # explicitly to provision ahead of time (e.g. while baking a container
72
- # image) so the first {Sandbox.create} doesn't pay the download.
67
+ # This gem is SDK-only: nothing is provisioned at build/install time. The
68
+ # runtime comes from the companion `microsandbox-rb-binaries` gem when it is
69
+ # installed (see {ensure_runtime!}); otherwise it is fetched into
70
+ # `~/.microsandbox` on first use. Call this explicitly to provision ahead of
71
+ # time (e.g. while baking a container image) so the first {Sandbox.create}
72
+ # doesn't pay the download. Not needed — and not used — when the binaries
73
+ # gem supplies the runtime.
73
74
  # @return [nil]
74
75
  def install
75
76
  Native.install
@@ -102,10 +103,14 @@ module Microsandbox
102
103
 
103
104
  # Ensure the `msb` runtime + `libkrunfw` are present *and version-matched*,
104
105
  # provisioning them on first use if not. Called automatically by
105
- # {Sandbox.create}/{Sandbox.start} so precompiled-gem users (who never ran the
106
- # source build) get a working runtime without a manual {install} step.
106
+ # {Sandbox.create}/{Sandbox.start} so a freshly installed gem gets a working
107
+ # runtime without a manual {install} step.
107
108
  #
108
- # Runs at most once per process. Opt out by setting
109
+ # Runs at most once per process. When the companion `microsandbox-rb-binaries`
110
+ # gem supplies the runtime (it was activated at load time and its `msb` is
111
+ # what the resolver now returns from {runtime_path}), nothing is downloaded
112
+ # or touched in `~/.microsandbox` — the bundled binaries are already the
113
+ # matching version. Opt out of the download by setting
109
114
  # `MICROSANDBOX_NO_AUTO_INSTALL` (e.g. air-gapped hosts that provision the
110
115
  # runtime out of band); the runtime is then left untouched and a missing or
111
116
  # stale one surfaces at the operation itself.
@@ -129,6 +134,14 @@ module Microsandbox
129
134
  # uses the same lazy env/profile/config ladder every operation already
130
135
  # consults, so this adds no work for local hosts (the common case).
131
136
  return if default_backend_kind == :cloud
137
+ # The binaries gem won the resolver: its vendored msb (and the libkrunfw
138
+ # beside it) are exactly the version this gem was built for, so there is
139
+ # nothing to verify or download. (If `MSB_PATH` overrides it, the user owns
140
+ # the runtime and we fall through to the existing behaviour.)
141
+ if bundled_runtime_active?
142
+ @runtime_ready = true
143
+ return
144
+ end
132
145
  # Opted out: the caller manages the runtime out of band, so don't fetch,
133
146
  # verify, or repair it here. Memoize the decision (the env var is stable for
134
147
  # the process); the operation resolves `msb` itself and surfaces any problem.
@@ -139,7 +152,8 @@ module Microsandbox
139
152
 
140
153
  unless installed?
141
154
  warn "[microsandbox] runtime (msb + libkrunfw) not found; " \
142
- "downloading to ~/.microsandbox (set MICROSANDBOX_NO_AUTO_INSTALL to skip)..."
155
+ "downloading to ~/.microsandbox (set MICROSANDBOX_NO_AUTO_INSTALL to skip, " \
156
+ "or install the microsandbox-rb-binaries gem to ship it with your bundle)..."
143
157
  end
144
158
  install
145
159
  @runtime_ready = true
@@ -155,9 +169,17 @@ module Microsandbox
155
169
  # resolver, below only the `MSB_PATH` environment variable). Process-level
156
170
  # and set-once: a second call is silently ignored, and the `MSB_PATH`
157
171
  # environment variable still wins. Mirrors {libkrunfw_path=}.
172
+ #
173
+ # The companion `microsandbox-rb-binaries` gem claims this same slot when
174
+ # `require "microsandbox"` activates it, so with that gem installed this
175
+ # setter is a no-op — use `MSB_PATH` to override a bundled runtime.
158
176
  # @param path [String]
159
177
  # @return [void]
160
178
  def runtime_path=(path)
179
+ if @bundled_msb_path && path.to_s != @bundled_msb_path
180
+ warn "[microsandbox] runtime_path= ignored: the microsandbox-rb-binaries gem already " \
181
+ "claimed the set-once SDK slot (#{@bundled_msb_path}); set MSB_PATH to override it"
182
+ end
161
183
  Native.set_runtime_msb_path(path.to_s)
162
184
  end
163
185
 
@@ -257,5 +279,101 @@ module Microsandbox
257
279
  v = ENV["MICROSANDBOX_NO_AUTO_INSTALL"]
258
280
  !v.nil? && !v.empty? && !%w[0 false no].include?(v.downcase)
259
281
  end
282
+
283
+ # Wire the companion `microsandbox-rb-binaries` gem into the core resolver.
284
+ # Runs once, at `require "microsandbox"` time (like the Node SDK, which pushes
285
+ # its platform package's msb into the same set-once SDK slot at module load)
286
+ # so every entry point that spawns msb — not just {Sandbox.create} — sees it.
287
+ #
288
+ # The gem is optional and has no dependency edge to this one (cloud-only
289
+ # users skip the ~50 MB download; RubyGems has no optional dependencies), so
290
+ # discovery is by require: absent → nothing happens and the resolver's lower
291
+ # tiers (`~/.microsandbox`, then `PATH`) plus the first-use download take
292
+ # over. Present but built for a different upstream runtime → warn and skip
293
+ # it rather than hand the core a mismatched msb (a stale runtime passes an
294
+ # exists-check and then fails every create on a wire-protocol mismatch).
295
+ # Only `MSB_PATH` (env) outranks the slot claimed here.
296
+ #
297
+ # Never raises: a broken companion gem must not take `require "microsandbox"`
298
+ # down with it.
299
+ # @return [String, nil] the activated msb path
300
+ def activate_bundled_runtime!
301
+ @bundled_msb_path = nil
302
+ begin
303
+ # Pin the lockstep version when RubyGems (not Bundler) picks the gem, so
304
+ # a newer/older companion left around doesn't get activated over the
305
+ # matching one. Under Bundler the Gemfile already decides; a companion
306
+ # that isn't in the bundle raises here and `require` then fails below.
307
+ gem "microsandbox-rb-binaries", "= #{VERSION}"
308
+ rescue Gem::LoadError
309
+ # Not installed at this version — `require` settles it.
310
+ end
311
+ begin
312
+ require "microsandbox/binaries"
313
+ rescue LoadError
314
+ return nil
315
+ end
316
+ # A bare require activates the newest gem of ANY name that ships this
317
+ # feature path; only accept the companion gem itself, this gem's own tree
318
+ # (a source checkout, where Bundler's path gem spans the whole repo and so
319
+ # owns binaries/lib too), or a plain load path (RUBYLIB/-I) no gem owns.
320
+ owner = bundled_runtime_owner
321
+ if owner && !TRUSTED_BINARIES_OWNERS.include?(owner)
322
+ warn "[microsandbox] ignoring microsandbox/binaries provided by the #{owner} gem " \
323
+ "(only microsandbox-rb-binaries is trusted for the bundled runtime)"
324
+ return nil
325
+ end
326
+ # Lockstep gate on BOTH constants. The runtime tag is what the wire
327
+ # protocol depends on; the gem version is the documented contract
328
+ # ("install both at the same version") and also covers this file's own
329
+ # API/packaging — the `gem "…", "= VERSION"` pin above is best-effort (it
330
+ # raises under Bundler whenever the bundle picked any other version, and
331
+ # that is swallowed), so it cannot be what enforces it.
332
+ unless Binaries::VERSION == VERSION && Binaries::RUNTIME_VERSION == RUNTIME_VERSION
333
+ warn "[microsandbox] ignoring microsandbox-rb-binaries #{Binaries::VERSION} " \
334
+ "(runtime #{Binaries::RUNTIME_VERSION}): microsandbox-rb #{VERSION} " \
335
+ "(runtime #{RUNTIME_VERSION}) needs the companion gem at the same version. " \
336
+ "Install both gems at the same version; falling back to ~/.microsandbox."
337
+ return nil
338
+ end
339
+ msb = Binaries.msb_path
340
+ unless msb && Binaries.libkrunfw_path
341
+ warn "[microsandbox] microsandbox-rb-binaries #{Binaries::VERSION} is installed but " \
342
+ "carries no runtime under #{Binaries.root}; falling back to ~/.microsandbox."
343
+ return nil
344
+ end
345
+ Native.set_runtime_msb_path(msb)
346
+ @bundled_msb_path = msb
347
+ rescue StandardError, ScriptError => e
348
+ # ScriptError too: a corrupt or newer-syntax binaries.rb raises
349
+ # SyntaxError (not a StandardError) out of `require`, and the optional
350
+ # companion must never take `require "microsandbox"` down with it.
351
+ warn "[microsandbox] could not activate microsandbox-rb-binaries: #{e.class}: #{e.message}"
352
+ nil
353
+ end
354
+
355
+ # Gems allowed to provide `microsandbox/binaries` (see activate_bundled_runtime!).
356
+ TRUSTED_BINARIES_OWNERS = %w[microsandbox-rb-binaries microsandbox-rb].freeze
357
+ private_constant :TRUSTED_BINARIES_OWNERS
358
+
359
+ # Name of the loaded gem whose files define Microsandbox::Binaries, or nil
360
+ # when it came from a bare load path.
361
+ def bundled_runtime_owner
362
+ source = Binaries.method(:msb_path).source_location&.first
363
+ return nil unless source
364
+ spec = Gem.loaded_specs.values.find { |s| source.start_with?(File.join(s.full_gem_path, "")) }
365
+ spec&.name
366
+ end
367
+
368
+ # Whether the binaries gem's msb is what the resolver actually returns — i.e.
369
+ # it was activated and nothing higher in the ladder (`MSB_PATH`) overrides it.
370
+ def bundled_runtime_active?
371
+ return false unless @bundled_msb_path
372
+ runtime_path == @bundled_msb_path
373
+ rescue Microsandbox::Error
374
+ false
375
+ end
260
376
  end
377
+
378
+ send(:activate_bundled_runtime!)
261
379
  end
data/sig/microsandbox.rbs CHANGED
@@ -653,8 +653,9 @@ module Microsandbox
653
653
 
654
654
  class SshOps
655
655
  def initialize: (untyped native) -> void
656
- def open_client: (?user: String, ?term: String?, ?sftp: bool) ?{ (SshClient) -> untyped } -> untyped
656
+ def open_client: (?user: String, ?term: String?, ?sftp: bool,
657
+ ?inactivity_timeout: Numeric?) ?{ (SshClient) -> untyped } -> untyped
657
658
  def prepare_server: (?host_key_path: String?, ?authorized_keys_path: String?,
658
- ?user: String?, ?sftp: bool) -> SshServer
659
+ ?user: String?, ?sftp: bool, ?inactivity_timeout: Numeric?) -> SshServer
659
660
  end
660
661
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: microsandbox-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ya-luotao