safe_ruby 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 425c072f463f6327df204384704f8ae03a7492dd
4
- data.tar.gz: 8fdd2f48678c45f09a9525e689dce7c7f2466ba4
3
+ metadata.gz: ad9f4276a328e546e667a18999ec069185672e87
4
+ data.tar.gz: 79a532fd77ae5db3be47561e1f7adcac4eea0f2f
5
5
  SHA512:
6
- metadata.gz: a55b54043be58f25ecbe306885f732895a4c98816a6e4df9f379f26d7cb14249d2b7b79dc3f3fc44624ba6b70ad75e5fbd00cf8a4a97fbc8923982fdc1535fc6
7
- data.tar.gz: c0e3ccf2fe3fc326ea06f3d9a5ca1ff255236e92a9a1f29244ccbae25dcb9aba602133116df105bd65d46f467fb403a324deede1df3419a85a5e0d7d1a902f2c
6
+ metadata.gz: 562a945aff8bbc1c005ea94fd4e070d275c8b8d6bab9e5f791a717444438f9d65b2d7a6d2272f492d07dfa95ba9a9865b75d1b8026a5bb5169d14c9c6c29eac3
7
+ data.tar.gz: 74c0f095b83446f66ecfe114592efd5589699583eb7f0a37208121f3b9c1d986693303a3193fcfe5b27d29cc27bc32cf302e1ff12603de5181e1a4155d575467
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .DS_STORE
3
+ lib/.DS_STORE
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ safe_ruby (1.0.1)
5
+ childprocess (>= 0.3.9)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ childprocess (0.7.1)
11
+ ffi (~> 1.0, >= 1.0.11)
12
+ coderay (1.1.2)
13
+ diff-lcs (1.3)
14
+ ffi (1.9.18)
15
+ method_source (0.8.2)
16
+ pry (0.10.4)
17
+ coderay (~> 1.1.0)
18
+ method_source (~> 0.8.1)
19
+ slop (~> 3.4)
20
+ rake (12.1.0)
21
+ rspec (3.6.0)
22
+ rspec-core (~> 3.6.0)
23
+ rspec-expectations (~> 3.6.0)
24
+ rspec-mocks (~> 3.6.0)
25
+ rspec-core (3.6.0)
26
+ rspec-support (~> 3.6.0)
27
+ rspec-expectations (3.6.0)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.6.0)
30
+ rspec-mocks (3.6.0)
31
+ diff-lcs (>= 1.2.0, < 2.0)
32
+ rspec-support (~> 3.6.0)
33
+ rspec-support (3.6.0)
34
+ slop (3.6.0)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ pry
41
+ rake
42
+ rspec
43
+ safe_ruby!
44
+
45
+ BUNDLED WITH
46
+ 1.15.4
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 heruku
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,41 @@
1
+ Safe Ruby
2
+ =========
3
+
4
+ Safe Ruby provides a way to run untrusted ruby code outside of the current process in a safe environment.
5
+ Creating this environment is largery based on jruby sandbox, whitelisting the methods one can use on potentially
6
+ dangerous classes. Constants are also whitelisted, eliminating some core ruby functionality such as spawning
7
+ another process.
8
+
9
+ Getting Started
10
+ ==============
11
+
12
+ Run `gem install safe_ruby` in your terminal, then `require 'safe_ruby'` in your app and you're ready to go.
13
+
14
+ Examples
15
+ ========
16
+
17
+ Evaluating ruby code
18
+
19
+ ```ruby
20
+ SafeRuby.eval('[1,2,3].map{ |n| n + 1 }') #=> [2, 3, 4]
21
+
22
+ SafeRuby.eval('system("rm *")') #=> system is unavailable
23
+
24
+ SafeRuby.eval('Kernel.abort') #=> undefined method `abort' for Kernel:Module
25
+ ```
26
+
27
+ Default timeout for evaluating is 5 seconds, but this can be specified.
28
+
29
+ ```ruby
30
+ SafeRuby.eval('loop{}') #<ChildProcess::TimeoutError: process still alive after 5 seconds>
31
+
32
+ SafeRuby.eval('loop{}', timeout: 1) #<ChildProcess::TimeoutError: process still alive after 1 seconds>
33
+ ```
34
+
35
+ This library was built for a codeacademy-style tutoring app, so checking answers is built into the SafeRuby class
36
+
37
+ ```ruby
38
+ SafeRuby.check('[1,2,3].map{ |n| n + 1 }', '[2,3,4]') #=> true
39
+ ```
40
+
41
+ In this example, the second argument(expected answer) can also be untrusted, it will be run safely.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new
7
+
8
+ desc 'Run specs'
9
+ task :default => :spec
@@ -1,7 +1,7 @@
1
- ALLOWED_CONSTANTS=
2
- [ :Object, :Module, :Class, :BasicObject, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding,
3
- :Comparable, :Enumerable, :String, :Symbol, :Exception, :SystemExit, :SignalException, :Interrupt, :StandardError, :TypeError,
4
- :ArgumentError, :IndexError, :KeyError, :RangeError, :ScriptError, :SyntaxError, :LoadError, :NotImplementedError, :NameError,
1
+ ALLOWED_CONSTANTS= [
2
+ :Object, :Module, :Class, :BasicObject, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding,
3
+ :Comparable, :Enumerable, :String, :Symbol, :Exception, :SystemExit, :SignalException, :Interrupt, :StandardError, :TypeError,
4
+ :ArgumentError, :IndexError, :KeyError, :RangeError, :ScriptError, :SyntaxError, :LoadError, :NotImplementedError, :NameError,
5
5
  :NoMethodError, :RuntimeError, :SecurityError, :NoMemoryError, :EncodingError, :SystemCallError, :Errno, :ZeroDivisionError,
6
6
  :FloatDomainError, :Numeric, :Integer, :Fixnum, :Float, :Bignum, :Array, :Hash, :Struct, :RegexpError, :Regexp,
7
7
  :MatchData, :Marshal, :Range, :IOError, :EOFError, :IO, :STDIN, :STDOUT, :STDERR, :Time, :Random,
@@ -9,4 +9,5 @@ ALLOWED_CONSTANTS=
9
9
  :StopIteration, :RubyVM, :Thread, :TOPLEVEL_BINDING, :ThreadGroup, :Mutex, :ThreadError, :Fiber, :FiberError, :Rational, :Complex,
10
10
  :RUBY_VERSION, :RUBY_RELEASE_DATE, :RUBY_PLATFORM, :RUBY_PATCHLEVEL, :RUBY_REVISION, :RUBY_DESCRIPTION, :RUBY_COPYRIGHT, :RUBY_ENGINE,
11
11
  :TracePoint, :ARGV, :Gem, :RbConfig, :Config, :CROSS_COMPILING, :Date, :ConditionVariable, :Queue, :SizedQueue, :MonitorMixin, :Monitor,
12
- :Exception2MessageMapper, :IRB, :RubyToken, :RubyLex, :Readline, :RUBYGEMS_ACTIVATION_MONITOR]
12
+ :Exception2MessageMapper, :IRB, :RubyToken, :RubyLex, :Readline, :RUBYGEMS_ACTIVATION_MONITOR
13
+ ]
@@ -16,7 +16,7 @@ def keep_methods(klass, methods)
16
16
  undef_methods = (klass.methods(false) - methods)
17
17
  undef_methods.each do |method|
18
18
  klass.send(:undef_method, method)
19
- end
19
+ end
20
20
  end
21
21
 
22
22
  def clean_constants
@@ -48,4 +48,4 @@ end
48
48
 
49
49
  clean_constants
50
50
 
51
- STRING
51
+ STRING
@@ -1,41 +1,41 @@
1
1
  IO_S_METHODS = %w[
2
- new
3
- foreach
4
- open
2
+ new
3
+ foreach
4
+ open
5
5
  ]
6
6
 
7
7
  KERNEL_S_METHODS = %w[
8
- Array
9
- binding
10
- block_given?
11
- catch
12
- chomp
13
- chomp!
14
- chop
15
- chop!
16
- eval
17
- fail
18
- Float
19
- format
20
- global_variables
21
- gsub
22
- gsub!
23
- Integer
24
- iterator?
25
- lambda
26
- local_variables
27
- loop
28
- method_missing
29
- proc
30
- raise
31
- scan
32
- split
33
- sprintf
34
- String
35
- sub
36
- sub!
37
- throw
38
- ].freeze
8
+ Array
9
+ binding
10
+ block_given?
11
+ catch
12
+ chomp
13
+ chomp!
14
+ chop
15
+ chop!
16
+ eval
17
+ fail
18
+ Float
19
+ format
20
+ global_variables
21
+ gsub
22
+ gsub!
23
+ Integer
24
+ iterator?
25
+ lambda
26
+ local_variables
27
+ loop
28
+ method_missing
29
+ proc
30
+ raise
31
+ scan
32
+ split
33
+ sprintf
34
+ String
35
+ sub
36
+ sub!
37
+ throw
38
+ ].freeze
39
39
 
40
40
  SYMBOL_S_METHODS = %w[
41
41
  all_symbols
@@ -268,4 +268,4 @@ upcase!
268
268
  upto
269
269
  []
270
270
  []=
271
- ].freeze
271
+ ].freeze
@@ -2,8 +2,8 @@ require 'childprocess'
2
2
  require_relative 'method_whitelist'
3
3
  require_relative 'constant_whitelist'
4
4
  require_relative 'make_safe_code'
5
- require_relative 'safe_ruby_runner'
5
+ require_relative 'safe_ruby/runner'
6
+ require_relative 'safe_ruby/version'
6
7
 
7
8
  class SafeRuby
8
- VERSION = "1.0.1"
9
- end
9
+ end
@@ -1,3 +1,5 @@
1
+ require 'tempfile'
2
+
1
3
  class EvalError < StandardError
2
4
  def initialize(msg); super; end
3
5
  end
@@ -29,7 +31,7 @@ class SafeRuby
29
31
  process.poll_for_exit(@timeout)
30
32
  rescue ChildProcess::TimeoutError => e
31
33
  process.stop # tries increasingly harsher methods to kill the process.
32
- return e
34
+ return e.message
33
35
  end
34
36
  write.close
35
37
  temp.unlink
@@ -55,7 +57,6 @@ class SafeRuby
55
57
  private
56
58
 
57
59
  def build_tempfile
58
- require 'tempfile'
59
60
  file = Tempfile.new('saferuby')
60
61
  file.write(MAKE_SAFE_CODE)
61
62
  file.write <<-STRING
@@ -0,0 +1,7 @@
1
+ class SafeRuby
2
+ MAJOR_VERSION = 1
3
+ MINOR_VERSION = 0
4
+ RELEASE_VERSION = 2
5
+
6
+ VERSION = [MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION].join('.')
7
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'safe_ruby/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'safe_ruby'
8
+ s.version = SafeRuby::VERSION
9
+ s.date = '2013-12-04'
10
+ s.authors = ["Uku Taht"]
11
+ s.email = 'uku.taht@gmail.com'
12
+
13
+ s.summary = "Run untrusted ruby code in a safe environment"
14
+ s.description = "Evaluates ruby code by writing it to a tempfile and spawning a child process. Uses a whitelist of methods and constants to keep, for example one cannot run system commands in the environment created by this gem. The environment created by the untrusted code does not leak out into the parent process."
15
+ s.homepage = 'http://rubygems.org/gems/safe_ruby'
16
+ s.license = 'MIT'
17
+
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_runtime_dependency 'childprocess', '>= 0.3.9'
24
+
25
+ s.add_development_dependency 'pry'
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rspec'
28
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe SafeRuby do
4
+ describe '#eval' do
5
+ it 'allows basic operations' do
6
+ expect(SafeRuby.eval('4 + 5')).to eq 9
7
+ expect(SafeRuby.eval('[4, 5].map{|n| n+1}')).to eq [5 ,6]
8
+ end
9
+
10
+ it 'returns correct object' do
11
+ expect(SafeRuby.eval('[1,2,3]')).to eq [1,2,3]
12
+ end
13
+
14
+ MALICIOUS_OPERATIONS = [
15
+ "system('rm *')",
16
+ "`rm *`",
17
+ "Kernel.abort",
18
+ "cat spec/spec_helper.rb",
19
+ "File.class_eval { `echo Hello` }",
20
+ "FileUtils.class_eval { `echo Hello` }",
21
+ "Dir.class_eval { `echo Hello` }",
22
+ "FileTest.class_eval { `echo Hello` }",
23
+ "File.eval \"`echo Hello`\"",
24
+ "FileUtils.eval \"`echo Hello`\"",
25
+ "Dir.eval \"`echo Hello`\"",
26
+ "FileTest.eval \"`echo Hello`\"",
27
+ "File.instance_eval { `echo Hello` }",
28
+ "FileUtils.instance_eval { `echo Hello` }",
29
+ "Dir.instance_eval { `echo Hello` }",
30
+ "FileTest.instance_eval { `echo Hello` }",
31
+ "f=IO.popen('uname'); f.readlines; f.close",
32
+ "IO.binread('/etc/passwd')",
33
+ "IO.read('/etc/passwd')",
34
+ ]
35
+
36
+ MALICIOUS_OPERATIONS.each do |op|
37
+ it "protects from malicious operations like (#{op})" do
38
+ expect{
39
+ SafeRuby.eval(op)
40
+ }.to raise_error RuntimeError
41
+ end
42
+ end
43
+
44
+ describe "options" do
45
+ describe "timeout" do
46
+ it 'defaults to a 5 second timeout' do
47
+ time = Benchmark.realtime do
48
+ SafeRuby.eval('(1..100000).map {|n| n**100}')
49
+ end
50
+ expect(time).to be_within(0.5).of(5)
51
+ end
52
+
53
+ it 'allows custom timeout' do
54
+ time = Benchmark.realtime do
55
+ SafeRuby.eval('(1..100000).map {|n| n**100}', timeout: 1)
56
+ end
57
+ expect(time).to be_within(0.5).of(1)
58
+ end
59
+ end
60
+
61
+ describe "raising errors" do
62
+ it "defaults to raising errors" do
63
+ expect{ SafeRuby.eval("asdasdasd") }.to raise_error RuntimeError
64
+ end
65
+
66
+ it "allows not raising errors" do
67
+ expect {SafeRuby.eval("asdasd", raise_errors: false)}.to_not raise_error
68
+ end
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,9 @@
1
+ require 'safe_ruby'
2
+ require 'benchmark'
3
+
4
+ RSpec.configure do |config|
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ config.order = 'random'
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safe_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uku Taht
@@ -14,30 +14,58 @@ dependencies:
14
14
  name: childprocess
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.3.9
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.3.9
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rspec
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - '>='
59
+ - - ">="
32
60
  - !ruby/object:Gem::Version
33
- version: 2.14.1
61
+ version: '0'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - '>='
66
+ - - ">="
39
67
  - !ruby/object:Gem::Version
40
- version: 2.14.1
68
+ version: '0'
41
69
  description: Evaluates ruby code by writing it to a tempfile and spawning a child
42
70
  process. Uses a whitelist of methods and constants to keep, for example one cannot
43
71
  run system commands in the environment created by this gem. The environment created
@@ -47,11 +75,22 @@ executables: []
47
75
  extensions: []
48
76
  extra_rdoc_files: []
49
77
  files:
50
- - lib/safe_ruby.rb
78
+ - ".gitignore"
79
+ - ".rspec"
80
+ - Gemfile
81
+ - Gemfile.lock
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
51
85
  - lib/constant_whitelist.rb
52
86
  - lib/make_safe_code.rb
53
87
  - lib/method_whitelist.rb
54
- - lib/safe_ruby_runner.rb
88
+ - lib/safe_ruby.rb
89
+ - lib/safe_ruby/runner.rb
90
+ - lib/safe_ruby/version.rb
91
+ - safe_ruby.gemspec
92
+ - spec/safe_ruby_spec.rb
93
+ - spec/spec_helper.rb
55
94
  homepage: http://rubygems.org/gems/safe_ruby
56
95
  licenses:
57
96
  - MIT
@@ -62,18 +101,20 @@ require_paths:
62
101
  - lib
63
102
  required_ruby_version: !ruby/object:Gem::Requirement
64
103
  requirements:
65
- - - '>='
104
+ - - ">="
66
105
  - !ruby/object:Gem::Version
67
106
  version: '0'
68
107
  required_rubygems_version: !ruby/object:Gem::Requirement
69
108
  requirements:
70
- - - '>='
109
+ - - ">="
71
110
  - !ruby/object:Gem::Version
72
111
  version: '0'
73
112
  requirements: []
74
113
  rubyforge_project:
75
- rubygems_version: 2.1.11
114
+ rubygems_version: 2.5.1
76
115
  signing_key:
77
116
  specification_version: 4
78
117
  summary: Run untrusted ruby code in a safe environment
79
- test_files: []
118
+ test_files:
119
+ - spec/safe_ruby_spec.rb
120
+ - spec/spec_helper.rb