基本的に、メソッドまたはクラスを定義する信頼されていないコードを実行し、それに対して信頼されていない rspec 仕様を実行するプログラムを作成したいと考えています。
Ruby のサンドボックス化について少し調べましたが、rubyconfのこのビデオは特に役に立ちました。いくつかのソリューションを検討した結果、最も役立つと思われる 2 つのソリューションは、基本的にコードの静的分析を行う rubycop とjrubyサンドボックス(どちらも上記のビデオで説明されています) です。私の直感では、jruby サンドボックスの方がおそらく安全だと思いますが、間違っている可能性もあります。
これは私がやりたいことの完全に危険な例です:
code = <<-RUBY
class Person
def hey
"hey!"
end
end
RUBY
spec = <<-RUBY
describe Person do
let(:person) { Person.new }
it "says hey" do
person.hey.should == "hey!"
end
end
RUBY
# code and spec will be from user input (unsafe)
eval code
require 'rspec/autorun'
eval spec
どちらも問題なく動作しますが、コードは明らかにサンドボックス化する必要があります。天才が提出するまでに数分かかるかsystem("rm -rf /*")
、fork while fork
それと同じくらい危険です。
jrubyサンドボックスでいろいろ試してみた...
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.activate! # lock it down
sand.eval code
puts sand.eval spec
そのコードは次の例外をスローします。
Sandbox::SandboxException: NoMethodError: undefined method `require' for #<RSpec::Core::Configuration:0x7c3cfaab>
これは、サンドボックスがロックダウンされた後、RSpec が何かを要求しようとするためです。
そこで、空の を呼び出して、サンドボックスがロックダウンされる前に RSpec に何かを要求させようとしましたdescribe
。
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.eval("describe("") { }")
sand.activate! # lock it down
sand.eval code
sand.eval spec
そして、私はこれを取得します:
Sandbox::SandboxException: NameError: uninitialized constant RSpec
これは基本的RSpec
に、サンドボックスに存在しないことを意味します。sand.eval("require 'rspec/autorun'")
true を返すことと、前の例が実際に機能したこと (RSpec のオートローダーが実行を開始したこと) を考えると、これは奇妙です。
ただし、gem とこの特定のサンドボックスに問題がある可能性があります。#require
サンドボックス オブジェクトは、本質的に にバインドされているメソッド を実際にサポートしているKernel.require
ため、gem をロードできません。
このサンドボックスを使用することは、rspec では実際には不可能なように見え始めています。主な問題は、実際にサンドボックスにロードしようとすることです。私もこのようなことを試しました:
require 'rspec'
sand.ref(RSpec) # open access to local rspec
しかし、それは何も持っていませんでした。
だから、私の質問は2つあります: