Sandbox's Init and Import #
mfp: This makes me think that the point of sandbox is not as much allowing access to stuff you cannot use with higher $SAFE levels as offering a clean environment. Am I right? In both cases, being able to specify which stuff is to be imported could be useful.
Starting with an example:
box = Sandbox.new(:init => [:load], :import => [:YAML, :File]) box.eval("require 'rubygems'")
This is conceptual, it doesn’t yet work all the way. The init
option loads a portion of Ruby’s core into the sandbox. It doesn’t actually load a shared lib or anything. It just allows access to some C methods (or hacked versions of them) built into the Sandbox extension.
So :init => [:load]
is kind of like when Init_load
from eval.c gets call. That call gives you load
and require
and $LOADED_FEATURES
and the like. There should only be five or so of these init modules. From there you can remove_method
anything you don’t want around.
The :import
will copy classes from the main Ruby interpreter into the Sandbox. This is a deep copy which will recursively import modules, classes, singleton classes and methods until we hit Object
or anything the sandbox already has. Oh and then instance variables get marshalled. I gotta remember to do that.
I wouldn’t recommend this approach for restricted sandboxes and I will probably disable it for the most restrictive subclass. In those cases you’ll want to just pass in a string to be eval’d. That gives only one object reference as a hook to the outside and it’s trapped in C.
FlashHater
Cool, we can do namespace tricks without losing our libs. BTW , can I pass blocks to eval?
why
No. I’m not sure if that will work yet. I think it will try to use the SCOPE struct created when the block is parsed.
MenTaLguY
Hmm. So what if I just want to import a sub-hierarchy? Like, just
GreatMouse::Detective
rather than all ofGreatMouse
?Justin
This sounds more and more like the best route for doing a sensible class browser and “intellisense” for Ruby. I know its scoffed on by most, but for anyone who has programmed with intellisense, its hard to give up. But the only way to really know what methods are avaiable to a given object at any time in Ruby is to run the code.
Sandbox + some traps to ensure files aren’t written, sockets aren’t opened, etc. sounds like the perfect way to run some code, inspect it for methods, and provide those resuults to a class browser/intellisense engine.
why
MenTaLguY: If you want to do that, then I’ll probably have like an
:import_only
option for that.Justin: I’m not sure how you’d keep the sandbox current with what you’re typing, but I hope that’ll one day be the case.
MenTaLguY
Hmm, okay, so you can do e.g.
:import_only => ["GreatMouse::Detective"]
, but then what’s the difference between:import_only => ["YAML"]
and:import => ["YAML"]
?Additionally, I think the ability to import to a different place in the Sandbox would be keen. For example, being able to introduce
MyApp::Sandboxed::Spleen
to Mr. Snadbox asMyApp::Spleen
.MenTaLguY
Ah, maybe
:import_only
doesn’t recursively import child modules? Although that wasn’t what I had in mind, it does sound useful.why
Actually, there are two directions to the recursion, MenTaL. The ancestry of the class and the containers of the class. See, if I import
GreatMouse::Detective
and assumeGreatMouse
is a module, things’ll get all messed up if the realGreatMouse
ever happens to come along and it turns out to be a subclassedOpenStruct
or something.But what I may do is have the new
GreatMouse
descend from some kind ofTemporaryModule
. Then when the realGreatMouse
finally arrives, swap in the correct class and everything. Yeah, that will probably be sufficient.