I have come to a point when I need to have a good sandbox to run untrusted ruby code in. The good news, I told myself, is it's been done before. But hey, not many people need a sandbox, not many people need a sandbox in ruby, and not many people need a sandbox in ruby that has access to some gems.
Lemme give you a bit of an overview on what's been done:
- MRI Ruby has $SAFE and taint. Well, I think taint is everywhere, but $SAFE is only in MRI. Which is ok, because honestly, $SAFE sucks.
- _why (who disappeared somewhat before my time) made the freaky freaky sandbox. So, that was cool. It was also a long time ago, and is not maintained anymore. Oh, and it was apparently very hackish, going into Ruby internals a lot.
- Then there was something called "javasand", which I haven't looked into much... because:
- The peepz who did try ruby and Rails for Zombies came along and recycled all that into jruby_sandbox.
And life is now good. Want a ruby sandbox? Run JRuby, use that gem. Bliss.
Wait, wait— not so fast. I still need to have access to some gems and libraries from within the sandbox.
And that's a problem because, in the sandbox, or so I was told, only Kernel#require exists. No RubyGems. Darn. I got stuck there for a while. But then (forgive the cliché) it hit:
Ruby 1.9 has baked-right-in rubygems support.
So, after setting the
JRUBY_OPTS=--1.9 config, here's how you do things:
require "sandbox" sand = Sandbox::Safe.new sand.eval <<-RUBY require "bundler" Bundler.require :sandbox RUBY sand.activate! sand.eval "# untrusted code"
I use my Gemfile to the most I can, so the relevant section looks like this:
group :sandbox do platforms :jruby do gem 'typhoeus' gem 'kramdown' gem 'nokogiri' # ... end end
And everything just works peachy.