trusted-sandbox 0.0.10.pre → 0.0.11.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile.lock +17 -1
- data/README.md +63 -19
- data/lib/trusted_sandbox/cli.rb +17 -6
- data/lib/trusted_sandbox/config/trusted_sandbox.yml +5 -1
- data/lib/trusted_sandbox/config.rb +47 -13
- data/lib/trusted_sandbox/defaults.rb +4 -1
- data/lib/trusted_sandbox/general_purpose.rb +26 -0
- data/lib/trusted_sandbox/response.rb +30 -11
- data/lib/trusted_sandbox/runner.rb +22 -5
- data/lib/trusted_sandbox/server_images/{2.1.2 → ruby-2.1.2}/Dockerfile +0 -0
- data/lib/trusted_sandbox/server_images/{2.1.2 → ruby-2.1.2}/Gemfile +0 -0
- data/lib/trusted_sandbox/server_images/{2.1.2 → ruby-2.1.2}/bundle_config +0 -0
- data/lib/trusted_sandbox/server_images/{2.1.2 → ruby-2.1.2}/entrypoint.sh +0 -0
- data/lib/trusted_sandbox/server_images/{2.1.2 → ruby-2.1.2}/run.rb +0 -0
- data/lib/trusted_sandbox/uid_pool.rb +4 -0
- data/lib/trusted_sandbox/version.rb +1 -1
- data/lib/trusted_sandbox.rb +9 -0
- data/spec/integration/integration_spec.rb +85 -0
- data/spec/integration/quota_spec.rb +25 -0
- data/spec/lib/trusted_sandbox/config_spec.rb +91 -0
- data/spec/lib/trusted_sandbox/request_serializer_spec.rb +47 -0
- data/spec/lib/trusted_sandbox/response_spec.rb +90 -0
- data/spec/lib/trusted_sandbox/runner_spec.rb +171 -0
- data/spec/lib/trusted_sandbox/uid_pool_spec.rb +110 -0
- data/spec/lib/trusted_sandbox_spec.rb +15 -0
- data/spec/spec_helper.rb +95 -0
- data/trusted-sandbox.gemspec +4 -2
- metadata +58 -10
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# This should not be run by CI as it requires server installation.
|
4
|
+
|
5
|
+
describe 'integration testing' do
|
6
|
+
|
7
|
+
describe 'sanity test' do
|
8
|
+
it 'works for inline' do
|
9
|
+
TrustedSandbox.run_code!('input[:x] ** 2', input: {x: 10}).should == 100
|
10
|
+
|
11
|
+
response = TrustedSandbox.run_code('puts "hi"; input[:x] ** 2', input: {x: 10})
|
12
|
+
response.valid?.should == true
|
13
|
+
response.output.should == 100
|
14
|
+
response.stdout.should == ["hi\n"]
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'works for a class' do
|
18
|
+
TrustedSandbox.run!(TrustedSandbox::GeneralPurpose, 'input[:x] ** 2', input: {x: 10}).should == 100
|
19
|
+
|
20
|
+
response = TrustedSandbox.run(TrustedSandbox::GeneralPurpose, 'puts "hi"; input[:x] ** 2', input: {x: 10})
|
21
|
+
response.valid?.should == true
|
22
|
+
response.output.should == 100
|
23
|
+
response.stdout.should == ["hi\n"]
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'works when there is an error' do
|
27
|
+
expect {TrustedSandbox.run_code!('asfsadf')}.to raise_error(TrustedSandbox::UserCodeError)
|
28
|
+
|
29
|
+
response = TrustedSandbox.run_code('asfsadf')
|
30
|
+
response.valid?.should == false
|
31
|
+
response.output.should == nil
|
32
|
+
response.status.should == 'error'
|
33
|
+
response.error.is_a?(NameError).should == true
|
34
|
+
response.error_to_raise.is_a?(TrustedSandbox::UserCodeError).should == true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'memory limit' do
|
39
|
+
it 'raises error when limited' do
|
40
|
+
response = TrustedSandbox.with_options(memory_limit: 50_000_000) do |s|
|
41
|
+
s.run_code('x = "*" * 50_000_000')
|
42
|
+
end
|
43
|
+
response.valid?.should == false
|
44
|
+
response.stderr.should == ["Killed\n"]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'works when not limited' do
|
48
|
+
response = TrustedSandbox.with_options(memory_limit: 100_000_000) do |s|
|
49
|
+
s.run_code('x = "*" * 50_000_000')
|
50
|
+
end
|
51
|
+
response.stderr.should be_empty
|
52
|
+
response.stdout.should be_empty
|
53
|
+
response.valid?.should == true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'network limit' do
|
58
|
+
it 'raises error when limited' do
|
59
|
+
response = TrustedSandbox.with_options(network_access: false) do |s|
|
60
|
+
s.run_code('`ping www.google.com -c 1; echo $?`.split("\n").last')
|
61
|
+
end
|
62
|
+
response.stderr.should == ["ping: unknown host www.google.com\n"]
|
63
|
+
response.output.to_i.should_not == 0
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'works when not limited' do
|
67
|
+
response = TrustedSandbox.with_options(network_access: true) do |s|
|
68
|
+
s.run_code('`ping www.google.com -c 1; echo $?`.split("\n").last')
|
69
|
+
end
|
70
|
+
response.stderr.should be_empty
|
71
|
+
response.output.to_i.should == 0
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'time limit' do
|
76
|
+
it 'raises error' do
|
77
|
+
response = TrustedSandbox.with_options(execution_timeout: 1) do |s|
|
78
|
+
s.run_code('puts "hi"; while true; end')
|
79
|
+
end
|
80
|
+
response.valid?.should == false
|
81
|
+
response.error.is_a?(Timeout::Error).should == true
|
82
|
+
response.error_to_raise.is_a?(TrustedSandbox::ExecutionTimeoutError).should == true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Note! Will only work on linux machine that is configured appropriately with user quotas of 10 MB.
|
4
|
+
# This should not be run by CI.
|
5
|
+
|
6
|
+
# Usage from a configured server:
|
7
|
+
# rspec spec/integration/quota_spec.rb
|
8
|
+
|
9
|
+
describe 'quota limit integration testing' do
|
10
|
+
it 'works when quotas are unlimited' do
|
11
|
+
response = TrustedSandbox.with_options(enable_quotas: false) do |s|
|
12
|
+
s.run_code "File.open('test','w') {|f| f.write '*' * 15_000_000}"
|
13
|
+
end
|
14
|
+
response.valid?.should == true
|
15
|
+
end
|
16
|
+
|
17
|
+
# rspec spec/integration/quota_spec.rb --example "quota limit integration testing does not work when quotas are limited"
|
18
|
+
it 'does not work when quotas are limited' do
|
19
|
+
response = TrustedSandbox.with_options(enable_quotas: true) do |s|
|
20
|
+
s.run_code "File.open('test','w') {|f| f.write '*' * 15_000_000}"
|
21
|
+
end
|
22
|
+
response.valid?.should == false
|
23
|
+
response.stderr.any? {|row| row =~ /disk quota exceeded/i}.should == true
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox::Config do
|
4
|
+
before do
|
5
|
+
@defaults = TrustedSandbox::Defaults.send(:new)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'override mechanism' do
|
9
|
+
before do
|
10
|
+
@subject = @defaults.override cpu_shares: 2
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'ensures defaults have what we expect' do
|
14
|
+
@defaults.cpu_shares.should == 1
|
15
|
+
@defaults.execution_timeout.should == 15
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'works' do
|
19
|
+
@subject.cpu_shares.should == 2
|
20
|
+
@subject.execution_timeout.should == 15
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#pool_max_id' do
|
25
|
+
before do
|
26
|
+
@subject = @defaults.override pool_min_uid: 100, pool_size: 10
|
27
|
+
end
|
28
|
+
it 'works' do
|
29
|
+
@subject.pool_max_uid.should == 109
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'docker_url=' do
|
34
|
+
before do
|
35
|
+
@url = 'http://localhost'
|
36
|
+
@subject = @defaults.override docker_url: @url
|
37
|
+
end
|
38
|
+
it 'sets up Docker' do
|
39
|
+
Docker.url.should == @url
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'host_code_root_path= and host_uid_pool_lock_path=' do
|
44
|
+
before do
|
45
|
+
@subject = @defaults.override host_code_root_path: '~/tmp', host_uid_pool_lock_path: '~/tmp2'
|
46
|
+
end
|
47
|
+
it 'expands the path' do
|
48
|
+
@subject.host_code_root_path.should == File.expand_path('~/tmp')
|
49
|
+
@subject.host_uid_pool_lock_path.should == File.expand_path('~/tmp2')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'docker_cert_path and docker_options' do
|
54
|
+
before do
|
55
|
+
@subject = @defaults.override docker_cert_path: '~/tmp', docker_options: { ssl_verify_peer: true }
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'works' do
|
59
|
+
@subject.finished_configuring
|
60
|
+
Docker.options = { private_key_path: File.expand_path('~/tmp/key.pem'),
|
61
|
+
certificate_path: File.expand_path('~/tmp/cert.pem'),
|
62
|
+
ssl_verify_peer: true }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'docker authentication' do
|
67
|
+
context 'user did not request to authenticate' do
|
68
|
+
before do
|
69
|
+
@subject = @defaults.override
|
70
|
+
dont_allow(Docker).authenticate!
|
71
|
+
end
|
72
|
+
it 'does not perform authentication' do
|
73
|
+
@subject.finished_configuring
|
74
|
+
end
|
75
|
+
end
|
76
|
+
context 'user requested to authenticate' do
|
77
|
+
before do
|
78
|
+
@subject = @defaults.override docker_login: {user: 'user', password: 'password', email: 'email'}
|
79
|
+
mock(Docker).authenticate!(username: 'user', password: 'password', email: 'email').times(1)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'call Docker.authenticate!' do
|
83
|
+
@subject.finished_configuring
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'does not call Docker.authenticate! twice' do
|
87
|
+
2.times { @subject.finished_configuring }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox::RequestSerializer do
|
4
|
+
before do
|
5
|
+
@tmp_path = 'tmp/test/request_serializer'
|
6
|
+
@file_name = 'args'
|
7
|
+
@args_file_path = File.expand_path File.join(@tmp_path, @file_name)
|
8
|
+
FileUtils.rm_rf @tmp_path
|
9
|
+
FileUtils.mkdir_p @tmp_path
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#initialize' do
|
13
|
+
before do
|
14
|
+
@subject = TrustedSandbox::RequestSerializer.new(@tmp_path, @file_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'initializes attributes correctly' do
|
18
|
+
@subject.host_code_dir_path.should == @tmp_path
|
19
|
+
@subject.input_file_name.should == @file_name
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#serialize' do
|
25
|
+
before do
|
26
|
+
@subject = TrustedSandbox::RequestSerializer.new(@tmp_path, @file_name)
|
27
|
+
@arg1 = { test: 'working' }
|
28
|
+
@arg2 = { another_test: 'working too' }
|
29
|
+
@subject.serialize TrustedSandbox::RequestSerializer, @arg1, @arg2
|
30
|
+
|
31
|
+
@source_class_file = File.expand_path('lib/trusted_sandbox/request_serializer.rb')
|
32
|
+
@target_class_file = File.expand_path File.join(@tmp_path, 'request_serializer.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'copies the class file' do
|
36
|
+
File.exists?(@target_class_file).should == true
|
37
|
+
File.read(@target_class_file).should == File.read(@source_class_file)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'serializes arguments' do
|
41
|
+
File.exists?(@args_file_path).should == true
|
42
|
+
data = File.binread(@args_file_path)
|
43
|
+
Marshal.load(data).should == ['TrustedSandbox::RequestSerializer', 'request_serializer.rb', [@arg1, @arg2]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox::Response do
|
4
|
+
before do
|
5
|
+
@tmp_path = 'tmp/test/response'
|
6
|
+
@file_name = 'hello'
|
7
|
+
@file_path = File.expand_path File.join(@tmp_path, @file_name)
|
8
|
+
FileUtils.rm_rf @tmp_path
|
9
|
+
FileUtils.mkdir_p @tmp_path
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'no error' do
|
13
|
+
before do
|
14
|
+
File.binwrite @file_path, Marshal.dump(status: 'success', output: 'hi')
|
15
|
+
@subject = TrustedSandbox::Response.new('stdout', 'stderr', @tmp_path, @file_name)
|
16
|
+
@subject.parse!
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'instantiates correctly' do
|
20
|
+
@subject.host_code_dir_path.should == @tmp_path
|
21
|
+
@subject.output_file_name.should == @file_name
|
22
|
+
@subject.stdout.should == 'stdout'
|
23
|
+
@subject.stderr.should == 'stderr'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'parses the file correctly' do
|
27
|
+
@subject.raw_response.should == {status: 'success', output: 'hi'}
|
28
|
+
@subject.status.should == 'success'
|
29
|
+
@subject.output.should == 'hi'
|
30
|
+
@subject.error.should be_nil
|
31
|
+
@subject.error_to_raise.should be_nil
|
32
|
+
@subject.valid?.should == true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'user error' do
|
37
|
+
before do
|
38
|
+
@err = 1 / 0 rescue $!
|
39
|
+
File.binwrite @file_path, Marshal.dump(status: 'error', error: @err)
|
40
|
+
@subject = TrustedSandbox::Response.new(nil, nil, @tmp_path, @file_name)
|
41
|
+
@subject.parse!
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'initializes with an error' do
|
45
|
+
@subject.raw_response.should == {status: 'error', error: @err}
|
46
|
+
@subject.status.should == 'error'
|
47
|
+
@subject.output.should == nil
|
48
|
+
@subject.error.should == @err
|
49
|
+
@subject.error_to_raise.is_a?(TrustedSandbox::UserCodeError).should == true
|
50
|
+
expect {@subject.output!}.to raise_error(TrustedSandbox::UserCodeError)
|
51
|
+
@subject.valid?.should == false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'unexpected file format' do
|
56
|
+
before do
|
57
|
+
@err = 1 / 0 rescue $!
|
58
|
+
File.binwrite @file_path, Marshal.dump(status: 'unexpected', output: 'hi', error: @err)
|
59
|
+
@subject = TrustedSandbox::Response.new(nil, nil, @tmp_path, @file_name)
|
60
|
+
@subject.parse!
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'initializes with an error' do
|
64
|
+
@subject.raw_response.should == {status: 'unexpected', output: 'hi', error: @err}
|
65
|
+
@subject.status.should == 'error'
|
66
|
+
@subject.output.should == nil
|
67
|
+
@subject.error.is_a?(TrustedSandbox::ContainerError).should == true
|
68
|
+
@subject.error_to_raise.is_a?(TrustedSandbox::ContainerError).should == true
|
69
|
+
expect {@subject.output!}.to raise_error(TrustedSandbox::ContainerError)
|
70
|
+
@subject.valid?.should == false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'file is missing' do
|
75
|
+
before do
|
76
|
+
@subject = TrustedSandbox::Response.new(nil, nil, @tmp_path, @file_name)
|
77
|
+
@subject.parse!
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'initializes with an error' do
|
81
|
+
@subject.raw_response.should == nil
|
82
|
+
@subject.status.should == 'error'
|
83
|
+
@subject.output.should == nil
|
84
|
+
@subject.error.is_a?(Errno::ENOENT).should == true
|
85
|
+
@subject.error_to_raise.is_a?(TrustedSandbox::ContainerError).should == true
|
86
|
+
expect {@subject.output!}.to raise_error(TrustedSandbox::ContainerError)
|
87
|
+
@subject.valid?.should == false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox::Runner do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@defaults = TrustedSandbox::Defaults.send(:new).override(quiet_mode: true)
|
7
|
+
@uid_pool = Object.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'UID pool and code dir handling' do
|
11
|
+
context 'keep_code_folders=false' do
|
12
|
+
before do
|
13
|
+
mock(@uid_pool).lock { 100 }
|
14
|
+
mock(@uid_pool).release(100) {}
|
15
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, keep_code_folders: false
|
16
|
+
stub(@subject).create_container
|
17
|
+
stub(@subject).start_container
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'locks and releases from UID pool' do
|
21
|
+
@subject.run TrustedSandbox::Runner
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'deletes the code folder' do
|
25
|
+
@subject.run TrustedSandbox::Runner
|
26
|
+
Dir.exists?(@subject.send(:code_dir_path)).should == false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'keep_code_folders=true' do
|
31
|
+
before do
|
32
|
+
mock(@uid_pool).lock { 100 }
|
33
|
+
dont_allow(@uid_pool).release
|
34
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, keep_code_folders: true
|
35
|
+
stub(@subject).create_container
|
36
|
+
stub(@subject).start_container
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'locks but does not release from UID pool' do
|
40
|
+
@subject.run TrustedSandbox::Runner
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'does not delete the code folder' do
|
44
|
+
@subject.run TrustedSandbox::Runner
|
45
|
+
Dir.exists?(@subject.send(:code_dir_path)).should == true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'container creation' do
|
51
|
+
before do
|
52
|
+
stub(@uid_pool).lock { 100 }
|
53
|
+
stub(@uid_pool).release(100) {}
|
54
|
+
|
55
|
+
container = Object.new
|
56
|
+
@container = container
|
57
|
+
|
58
|
+
create_req = {}
|
59
|
+
stub(Docker::Container).create { |req| create_req.clear; create_req.merge!(req); container }
|
60
|
+
@create_req = create_req
|
61
|
+
|
62
|
+
start_req = {}
|
63
|
+
stub(container).start { |req| start_req.clear; start_req.merge!(req) }
|
64
|
+
@start_req = start_req
|
65
|
+
|
66
|
+
mock(container).attach(stream: true, stdin: nil, stdout: true, stderr: true, logs: true, tty: false) { ['stdout', 'stderr'] }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'keep_containers=true' do
|
70
|
+
before do
|
71
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, keep_containers: true
|
72
|
+
dont_allow(@container).delete
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'does not delete the container' do
|
76
|
+
@subject.run TrustedSandbox::Runner
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'keep_containers=false' do
|
81
|
+
before do
|
82
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, keep_containers: false
|
83
|
+
mock(@container).delete(force: true) {}
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'does not delete the container' do
|
87
|
+
@subject.run TrustedSandbox::Runner
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'basic request parameters' do
|
92
|
+
before do
|
93
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, cpu_shares: 5, memory_limit: 100,
|
94
|
+
docker_image_name: 'image', container_code_path: '/code',
|
95
|
+
network_access: false, keep_containers: true
|
96
|
+
@subject.run TrustedSandbox::Runner
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'sends the right requests' do
|
100
|
+
@create_req.should == {"CpuShares"=>5, "Memory"=>100, "AttachStdin"=>false, "AttachStdout"=>true, "AttachStderr"=>true, "Tty"=>false, "OpenStdin"=>false, "StdinOnce"=>false, "Cmd"=>["100"], "Image"=>"image", "Volumes"=>{"/code"=>{}}, "NetworkDisabled"=>true}
|
101
|
+
@start_req.should == {"Binds"=>["#{File.expand_path('tmp/code_dirs/100')}:/code"]}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'enable_quotas=true' do
|
106
|
+
before do
|
107
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, enable_quotas: true, keep_containers: true
|
108
|
+
@subject.run TrustedSandbox::Runner
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'sends the right request' do
|
112
|
+
@create_req['Env'].should == ['USE_QUOTAS=1']
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'enable_quotas=false' do
|
117
|
+
before do
|
118
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, enable_quotas: false, keep_containers: true
|
119
|
+
@subject.run TrustedSandbox::Runner
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'sends the right request' do
|
123
|
+
@create_req['Env'].should be_nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'enable_swap_limit=true' do
|
128
|
+
before do
|
129
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, enable_swap_limit: true, memory_swap_limit: 200, keep_containers: true
|
130
|
+
@subject.run TrustedSandbox::Runner
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'sends the right request' do
|
134
|
+
@create_req['MemorySwap'].should == 200
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'enable_swap_limit=false' do
|
139
|
+
before do
|
140
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, enable_swap_limit: false, memory_swap_limit: 200, keep_containers: true
|
141
|
+
@subject.run TrustedSandbox::Runner
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'sends the right request' do
|
145
|
+
@create_req['MemorySwap'].should be_nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'network_access=true' do
|
150
|
+
before do
|
151
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, network_access: true, keep_containers: true
|
152
|
+
@subject.run TrustedSandbox::Runner
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'sends the right request' do
|
156
|
+
@create_req['NetworkDisabled'].should == false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'network_access=false' do
|
161
|
+
before do
|
162
|
+
@subject = TrustedSandbox::Runner.new @defaults, @uid_pool, network_access: false, keep_containers: true
|
163
|
+
@subject.run TrustedSandbox::Runner
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'sends the right request' do
|
167
|
+
@create_req['NetworkDisabled'].should == true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox::UidPool do
|
4
|
+
before do
|
5
|
+
@tmp_dir = 'tmp/test/uid_pool'
|
6
|
+
FileUtils.rm_rf @tmp_dir
|
7
|
+
FileUtils.mkdir_p @tmp_dir
|
8
|
+
@class = TrustedSandbox::UidPool
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
context 'with defaults' do
|
13
|
+
before do
|
14
|
+
@subject = @class.new(@tmp_dir, 1, 3)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets up defaults correctly' do
|
18
|
+
@subject.timeout.should == 3
|
19
|
+
@subject.retries.should == 5
|
20
|
+
@subject.delay.should == 0.5
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with other values' do
|
26
|
+
before do
|
27
|
+
@subject = @class.new(@tmp_dir, 1, 3, 'timeout' => 5, retries: 10, 'delay' => 1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'sets up values correctly' do
|
31
|
+
@subject.timeout.should == 5
|
32
|
+
@subject.retries.should == 10
|
33
|
+
@subject.delay.should == 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'usage' do
|
40
|
+
before do
|
41
|
+
@subject = @class.new(@tmp_dir, 1, 3, retries: 1, timeout: 0.1, delay: 0.1)
|
42
|
+
@subject.release_all
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#lock' do
|
46
|
+
context 'There are still available IDs' do
|
47
|
+
it 'gives the UIDs' do
|
48
|
+
[@subject.lock, @subject.lock, @subject.lock].should == [1, 2, 3]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'There are no available IDs' do
|
53
|
+
before do
|
54
|
+
3.times { @subject.lock }
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'raises an error' do
|
58
|
+
expect {@subject.lock}.to raise_error(TrustedSandbox::PoolTimeoutError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#available, #used, #release' do
|
64
|
+
before do
|
65
|
+
@subject.release_all
|
66
|
+
@uid = @subject.lock
|
67
|
+
end
|
68
|
+
it 'sets the right available and used' do
|
69
|
+
@subject.available.should == 2
|
70
|
+
@subject.used.should == 1
|
71
|
+
@subject.available_uids.should == [2,3]
|
72
|
+
@subject.used_uids.should == [1]
|
73
|
+
end
|
74
|
+
it 'releases the right uid' do
|
75
|
+
@subject.release @uid
|
76
|
+
@subject.available.should == 3
|
77
|
+
@subject.used.should == 0
|
78
|
+
@subject.available_uids.should == [1,2,3]
|
79
|
+
@subject.used_uids.should == []
|
80
|
+
end
|
81
|
+
it 'does not release the wrong uid' do
|
82
|
+
@subject.release @uid + 1
|
83
|
+
@subject.available.should == 2
|
84
|
+
@subject.used.should == 1
|
85
|
+
@subject.available_uids.should == [2,3]
|
86
|
+
@subject.used_uids.should == [1]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#release_all' do
|
91
|
+
before do
|
92
|
+
@subject.release_all
|
93
|
+
3.times { @subject.lock }
|
94
|
+
end
|
95
|
+
it 'passes sanity tests' do
|
96
|
+
@subject.available.should == 0
|
97
|
+
@subject.used.should == 3
|
98
|
+
@subject.available_uids.should == []
|
99
|
+
@subject.used_uids.should == [1,2,3]
|
100
|
+
end
|
101
|
+
it 'works' do
|
102
|
+
@subject.release_all
|
103
|
+
@subject.available.should == 3
|
104
|
+
@subject.used.should == 0
|
105
|
+
@subject.available_uids.should == [1,2,3]
|
106
|
+
@subject.used_uids.should == []
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrustedSandbox do
|
4
|
+
describe '#with_options' do
|
5
|
+
before do
|
6
|
+
@default_network_access = TrustedSandbox.config.network_access
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'overrides configuration' do
|
10
|
+
TrustedSandbox.with_options(network_access: !@default_network_access) do |runner|
|
11
|
+
runner.config.network_access.should == !@default_network_access
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|