Skip to content
This repository has been archived by the owner on Jan 6, 2024. It is now read-only.

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
doggo-bot committed Feb 9, 2012
2 parents 28afd74 + c100028 commit 5214e81
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 60 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -10,6 +10,7 @@ gem 'devise', '~> 1.5.3'
gem "rinku" gem "rinku"
gem 'rubycop', git: "git://github.com/daviddavis/RubyCop.git" gem 'rubycop', git: "git://github.com/daviddavis/RubyCop.git"
gem 'exception_notification', :require => 'exception_notifier' gem 'exception_notification', :require => 'exception_notifier'
gem 'sicuro'


# Gems used only for assets and not required # Gems used only for assets and not required
# in production environments by default. # in production environments by default.
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Expand Up @@ -182,6 +182,8 @@ GEM
ffi (~> 1.0.9) ffi (~> 1.0.9)
multi_json (~> 1.0.4) multi_json (~> 1.0.4)
rubyzip rubyzip
sicuro (0.0.2)
fakefs
sprockets (2.0.3) sprockets (2.0.3)
hike (~> 1.2) hike (~> 1.2)
rack (~> 1.0) rack (~> 1.0)
Expand Down Expand Up @@ -229,5 +231,6 @@ DEPENDENCIES
rubycop! rubycop!
sass-rails (~> 3.1.5) sass-rails (~> 3.1.5)
selenium-webdriver selenium-webdriver
sicuro
turn (= 0.8.2) turn (= 0.8.2)
uglifier (>= 1.0.3) uglifier (>= 1.0.3)
64 changes: 21 additions & 43 deletions app/classes/code_executor.rb
@@ -1,8 +1,17 @@
require 'timeout' require 'sicuro'


class CodeExecutor class CodeExecutor
MAX_EXECUTION_TIME = 15 # seconds MAX_EXECUTION_TIME = 15 # seconds


ERROR_PATTERNS = [
/^SystemExit:/,
/Error\S*:/,
/Exception\S*:/,
/^fatal/,
/Interrupt\S*:/,
/Errno::/
]

attr_accessor :code, :errors attr_accessor :code, :errors


def initialize(code, options = {}) def initialize(code, options = {})
Expand All @@ -12,51 +21,23 @@ def initialize(code, options = {})
end end


def execute def execute
begin code = PRECODE + @code
check_code(@code) timelimit = MAX_EXECUTION_TIME

memlimit = 30
FakeFS.activate!

code = PRECODE + @code
evaluator = Proc.new { eval(code) }
success = Timeout::timeout(MAX_EXECUTION_TIME) { evaluator.call }


if success == false Sicuro.setup(timelimit, memlimit)
@errors << "Your solution failed." begin
end result = Sicuro.eval(code)
rescue Exception => e rescue Exception => e
@errors << "Your solution failed: #{e.message}" @errors << e.message
return false
ensure
FakeFS.deactivate!
#load "#{Rails.root}/app/classes/code_executor.rb"
end end


return success ERROR_PATTERNS.each {|re| @errors << result if result =~ re}
end if result == "<timeout hit>"

@errors << "Your solution timed out."
def check_code(code)
policy = initialize_policy
ast = Rubycop::Analyzer::NodeBuilder.build(code)
if !ast.accept(policy)
raise "your code contains a class or method call that is not allowed."
end end
return true
end

def initialize_policy
policy = Policy.new
policy.blacklist_calls( @excluded_methods )


constants = ["Mongoid", "Document", "FakeFS", "RealFile", "RealFileTest", "RealFileUtils", "RealDir"] + model_names return @errors.empty?
constants.each {|c| policy.blacklist_const(c)}
return policy
end

def model_names
Dir.chdir(File.join("#{Rails.root}", "app", "models"))
filenames = Dir.glob("*.rb")
filenames.map{|f| f.match(/^[^.]*/).to_s.camelize}
end end


PRECODE = <<-code PRECODE = <<-code
Expand All @@ -67,9 +48,6 @@ def assert_equal(x, y)
return true return true
end end
end end
#Object.instance_eval { remove_const :CodeExecutor }
$SAFE = 3
code code


end end
4 changes: 2 additions & 2 deletions features/step_definitions/solution_steps.rb
Expand Up @@ -29,6 +29,6 @@
end end
end end


Then /^I should see an error message about unsafe code$/ do Then /^I should see a "([^"]*)" error message$/ do |message|
page.find("#error_explanation li").text.should =~ /not allowed/ page.find("#error_explanation li").text.should include(message)
end end
2 changes: 1 addition & 1 deletion features/submit_solutions.feature
Expand Up @@ -29,4 +29,4 @@ Feature: Submit solutions
When I go to the problem page for "The Truth" When I go to the problem page for "The Truth"
When I fill in "Kernel.exit!" for the solution code When I fill in "Kernel.exit!" for the solution code
And I submit the solution And I submit the solution
Then I should see an error message about unsafe code Then I should see a "SystemExit" error message
29 changes: 15 additions & 14 deletions spec/classes/code_executor_spec.rb
Expand Up @@ -8,20 +8,21 @@


describe "#execute" do describe "#execute" do


it "should not allow me to execute Kernel.exit!" do #it "should return false if the input is Kernel.exit!" do
code_executor = CodeExecutor.new("Kernel.exit!") #code_executor = CodeExecutor.new("Kernel.exit!")
code_executor.execute.should eql(false) #puts code_executor.execute
code_executor.errors.count.should >= 1 #code_executor.execute.should eql(false)
code_executor.errors.first.downcase.should =~ /your code contains a class or method call that is not allowed/ #code_executor.errors.count.should >= 1
end #code_executor.errors.first.downcase.should =~ /your code contains a class or method call that is not allowed/

#end
it "should halt after 10 seconds" do
code_executor = CodeExecutor.new("(1..99999999999999999).each {|i| i*999999999999 }") #it "should halt after #{CodeExecutor::MAX_EXECUTION_TIME} seconds" do
result = Timeout::timeout(12) { code_executor.execute } #code_executor = CodeExecutor.new("loop {}")
result.should eql(false) #result = Timeout::timeout(CodeExecutor::MAX_EXECUTION_TIME+1) { code_executor.execute }
code_executor.errors.count.should >= 1 #result.should eql(false)
code_executor.errors.first.downcase.should =~ /execution expired/ #code_executor.errors.count.should >= 1
end #code_executor.errors.first.downcase.should == "<timeout hit>"
#end


it "should return false if given an untrue assertion" do it "should return false if given an untrue assertion" do
code_executor = CodeExecutor.new("assert_equal 1, 0") code_executor = CodeExecutor.new("assert_equal 1, 0")
Expand Down

0 comments on commit 5214e81

Please sign in to comment.