Module: Rigor::Plugin::Box
- Defined in:
- lib/rigor/plugin/box.rb
Overview
ADR-39 slice 5 — the isolation boundary for target-library invocation. When Rigor is launched with
RUBY_BOX=1 (opt-in; the launcher re-execs only when a project opts in), a target library is loaded and
called inside a Ruby::Box so its core-class monkey-patches and gem version cannot contaminate Rigor's
main space. Ruby::Box is not a security sandbox (the gem's code still runs in-process) — it is the
contamination boundary the rule needs, which is sufficient because the rule only ever invokes a
declared, trusted, pure target library.
Disabled by default. Box.enabled? is false unless the experimental Ruby::Box feature is active, so
every consumer keeps a non-box path and the default behaviour (loading the trusted library into the main
space, per slices 2/4) is unchanged. The box only ever holds the trusted, project-agnostic target
libraries (inflection rules, the Rack status table); per-project / exact-version boxes are a later slice.
Class Method Summary collapse
-
.enabled? ⇒ Boolean
True only when the experimental
Ruby::Boxfeature is present and active (the process was started withRUBY_BOX=1). -
.eval(code) ⇒ Object
Evaluates
codeinside the shared box and returns the result across the box boundary. -
.eval_require(feature) ⇒ Object
The gem-resolving fallback:
Ruby::Box#requireresolves against the raw$LOAD_PATHonly (it calls the C-level require directly), so a target library installed as a gem is reachable only through the box's own RubyGems — theKernel#requireinside the box. -
.require_feature(feature) ⇒ Object
Requires
featureinto the shared box exactly once. -
.shared ⇒ Object
The process-shared box for trusted, project-agnostic target libraries.
Class Method Details
.enabled? ⇒ Boolean
True only when the experimental Ruby::Box feature is present and active (the process was started with
RUBY_BOX=1). Any error answers false so a consumer silently keeps its non-box path.
21 22 23 24 25 |
# File 'lib/rigor/plugin/box.rb', line 21 def enabled? defined?(::Ruby::Box) && ::Ruby::Box.respond_to?(:enabled?) && ::Ruby::Box.enabled? rescue StandardError false end |
.eval(code) ⇒ Object
Evaluates code inside the shared box and returns the result across the box boundary. The caller MUST
build code safely — interpolate value arguments through String#inspect (which round-trips as a safe
Ruby literal) and only ever interpolate method names from a fixed allow-list, never free user input.
64 65 66 |
# File 'lib/rigor/plugin/box.rb', line 64 def eval(code) shared.eval(code) end |
.eval_require(feature) ⇒ Object
The gem-resolving fallback: Ruby::Box#require resolves against the raw $LOAD_PATH only (it
calls the C-level require directly), so a target library installed as a gem is reachable only
through the box's own RubyGems — the Kernel#require inside the box. feature is a fixed,
plugin-declared name rendered via String#inspect (a safe Ruby literal), so the eval carries no
free input. Returns false when the box cannot load the feature either way (the caller declines).
54 55 56 57 58 59 |
# File 'lib/rigor/plugin/box.rb', line 54 def eval_require(feature) shared.eval("require #{feature.inspect}") # require "active_support/inflector" true rescue ::StandardError, ::ScriptError false end |
.require_feature(feature) ⇒ Object
Requires feature into the shared box exactly once. Returns true when the feature is available in the
box, false when it could not be loaded (the caller then declines — never falls back to loading into the
main space, which would defeat the boundary).
The rescue is ::-qualified and covers ::ScriptError, matching Isolation::Process.run_worker_loop:
a failed box require raises ::LoadError — a ScriptError, not a StandardError — and a plain
rescue StandardError lets it escape and abort the whole run instead of the clean decline.
39 40 41 42 43 44 45 46 47 |
# File 'lib/rigor/plugin/box.rb', line 39 def require_feature(feature) @required ||= {} return @required[feature] if @required.key?(feature) shared.require(feature) @required[feature] = true rescue ::StandardError, ::ScriptError @required[feature] = eval_require(feature) end |
.shared ⇒ Object
The process-shared box for trusted, project-agnostic target libraries. Built lazily on first use.
28 29 30 |
# File 'lib/rigor/plugin/box.rb', line 28 def shared @shared ||= ::Ruby::Box.new end |