trusted-sandbox 0.0.10.pre → 0.0.11.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|