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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 087e7a3db62be30fbceb951541f60d39185fd272
4
- data.tar.gz: 470126d53f50f5f75a8a6210c6205169ad3102fa
3
+ metadata.gz: cc841b00560c9a8bd0b26bcc9ce940b095fed242
4
+ data.tar.gz: 7bd8e5c072575fea41bda718a32a99a6015d4d46
5
5
  SHA512:
6
- metadata.gz: 1acd7ef23ac33477479793c38ae674cd62284e8e60e1f186ed2cd375c5bcccd2482861ab3c948fbad9454f8905cb9b9c9fe4a18b27ec30ffca5f04194f4d3546
7
- data.tar.gz: fac057c808f1bf3da35f30432b4125783099358bca06b196bcfbd88edd0f29b96fbb33f7d9552af3739b71551595ab6f24bbdc87c773b04ddccf888e59d15ac8
6
+ metadata.gz: b2b63ac24b3daa49808d3ede5cef2fe21fbd7f0adf109412d06c91d5c77b78c2260d897af2ad292ccebccaea02937904e6209ff5bedbadef8b6e546512046617
7
+ data.tar.gz: 3acab287609c12d11a6b7e1c4635b41ea5afb94a1c2f4babb5cc43b6edbd9c2f38004d78bc4018aa68976d10c7f47f7080a1a9603bbbca9f85c9001c7431a313
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trusted-sandbox (0.0.9.pre)
4
+ trusted-sandbox (0.0.11.pre)
5
5
  docker-api (~> 1.13)
6
6
  thor (~> 0.19)
7
7
 
@@ -9,6 +9,7 @@ GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
11
  archive-tar-minitar (0.5.2)
12
+ diff-lcs (1.2.5)
12
13
  docker-api (1.13.6)
13
14
  archive-tar-minitar
14
15
  excon (>= 0.38.0)
@@ -16,6 +17,19 @@ GEM
16
17
  excon (0.40.0)
17
18
  json (1.8.1)
18
19
  rake (10.1.0)
20
+ rr (1.1.2)
21
+ rspec (3.1.0)
22
+ rspec-core (~> 3.1.0)
23
+ rspec-expectations (~> 3.1.0)
24
+ rspec-mocks (~> 3.1.0)
25
+ rspec-core (3.1.7)
26
+ rspec-support (~> 3.1.0)
27
+ rspec-expectations (3.1.2)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.1.0)
30
+ rspec-mocks (3.1.3)
31
+ rspec-support (~> 3.1.0)
32
+ rspec-support (3.1.2)
19
33
  thor (0.19.1)
20
34
 
21
35
  PLATFORMS
@@ -24,4 +38,6 @@ PLATFORMS
24
38
  DEPENDENCIES
25
39
  bundler (~> 1.3)
26
40
  rake
41
+ rr
42
+ rspec
27
43
  trusted-sandbox!
data/README.md CHANGED
@@ -1,10 +1,31 @@
1
1
  # Trusted Sandbox
2
2
 
3
- Run untrusted ruby code in a contained sandbox, using Docker. This gem was inspired by [Harry Marr's work][1].
3
+ Run untrusted code in a contained sandbox, using Docker. This gem was inspired by [Harry Marr's work][1].
4
4
 
5
5
  ## Instant gratification
6
6
 
7
- Trusted Sandbox makes it simple to execute Ruby classes that `eval` untrusted code in a resource-controlled docker container.
7
+ Trusted Sandbox makes it simple to execute classes that `eval` untrusted code in a resource-controlled docker
8
+ container.
9
+
10
+ The simplest way to get started is run "inline" code within a container:
11
+
12
+ ```ruby
13
+ require 'trusted_sandbox'
14
+
15
+ untrusted_code = "input[:number] ** 2"
16
+
17
+ # The following will run inside a Docker container
18
+ output = TrustedSandbox.run_code! untrusted_code, input: {number: 10}
19
+ # => 100
20
+ ```
21
+
22
+ `run_code!` receives user code and an arguments hash. Any key in the arguments hash is available when the user code
23
+ executes.
24
+
25
+ In addition, you can send any class to execute within a Docker container. All you need is to have the class respond to
26
+ `initialize` and `run`. Trusted Sandbox loads the container, copies the class file to the container, serializes the
27
+ arguments sent to `initialize`, instantiates an object, calls `run`, and serializes its return value back to the host.
28
+
8
29
  ```ruby
9
30
  # lib/my_function.rb
10
31
 
@@ -33,9 +54,6 @@ output = TrustedSandbox.run! MyFunction, untrusted_code, {number: 10}
33
54
  # => 100
34
55
  ```
35
56
 
36
- Classes you want to run in a container need to respond to #initialize and #run. Trusted Sandbox serializes the
37
- arguments sent to #initialize, loads the container, instantiates an object, and calls #run.
38
-
39
57
  ## Installing
40
58
 
41
59
  ### Step 1
@@ -89,7 +107,7 @@ $ trusted_sandbox test
89
107
  Install the image. This step is optional, as Docker automatically installs images when you first run them. However,
90
108
  since it takes a few minutes we suggest you do this in advance.
91
109
  ```
92
- $ docker run --rm vaharoni/trusted_sandbox:2.1.2.v1
110
+ $ docker run --rm vaharoni/trusted_sandbox:ruby-2.1.2.v1
93
111
  ```
94
112
  If you see the message "you must provide a uid", then you are set.
95
113
 
@@ -115,7 +133,7 @@ environment variables.
115
133
 
116
134
  ### Docker connection
117
135
 
118
- Trusted Sandbox uses the `docker-api` gem to communicate with docker. `docker-api`'s default work quite well for a
136
+ Trusted Sandbox uses the `docker-api` gem to communicate with docker. `docker-api`'s defaults work quite well for a
119
137
  Linux host, and you should be good by omitting `docker_url` and `docker_cert_path` all together.
120
138
 
121
139
  ```ruby
@@ -130,7 +148,7 @@ YAML file which will override any configuration and passed through to `Docker.op
130
148
 
131
149
  In addition, these docker-related configuration parameters can be used:
132
150
  ```ruby
133
- docker_image_name: vaharoni/trusted_sandbox:2.1.2.v1
151
+ docker_image_name: vaharoni/trusted_sandbox:ruby-2.1.2.v1
134
152
 
135
153
  # Optional authentication
136
154
  docker_login:
@@ -182,6 +200,11 @@ host_code_root_path: tmp/code_dirs
182
200
  # to the container to troubleshoot issues as explained in the "Troubleshooting" section.
183
201
  keep_code_folders: false
184
202
 
203
+ # When set to true, containers will not be erased after they finish running. This allows you
204
+ # to troubleshoot issues by viewing container parameters and logs as explained in the
205
+ # "Troubleshooting" section.
206
+ keep_containers: false
207
+
185
208
  # A folder used by the UID-pool to handle locks.
186
209
  host_uid_pool_lock_path: tmp/uid_pool_lock
187
210
  ```
@@ -218,7 +241,9 @@ In order to enable quotas do the following on the server:
218
241
  ```
219
242
  $ sudo apt-get install quota
220
243
  ```
221
- And follow [these instructions][4], which are also brought here for completeness:
244
+ And follow [these instructions][4] as well as [this resource][6], which we bring here for completeness. Note that these
245
+ may vary for your distro.
246
+
222
247
  ```
223
248
  $ sudo vim /etc/fstab
224
249
  ```
@@ -228,9 +253,21 @@ LABEL=cloudimg-rootfs / ext4 defaults,discard,usrquota 0 0
228
253
  ```
229
254
  Then do:
230
255
  ```
231
- $ mount -o remount
256
+ $ sudo touch /aquota.user
257
+ $ sudo chmod 600 /aquota.*
258
+ $ sudo mount -o remount /
259
+ ```
260
+ and **reboot the server**. Then do:
261
+ ```
262
+ $ sudo quotacheck -avum
263
+ $ sudo quotaon -avu
232
264
  ```
233
- and reboot the server. Finally, run the following (quota is in KB):
265
+ You should see something like this:
266
+ ```
267
+ /dev/disk/by-uuid/d36a9e2f-dae9-477f-8aea-29f1bdd1c04e [/]: user quotas turned on
268
+ ```
269
+
270
+ To actually set the quotas, run the following (quota is in KB):
234
271
  ```
235
272
  $ sudo trusted_sandbox set_quotas 10000
236
273
  ```
@@ -239,7 +276,10 @@ change these configuration parameters you must rerun the `set_quotas` command.
239
276
 
240
277
  Remember to set `enable_quotas: true` in the YAML file.
241
278
 
242
- Note: At this time, there is no way to assign different quotas to different users.
279
+ To get a quota report, do:
280
+ ```
281
+ $ sudo repquota -a
282
+ ```
243
283
 
244
284
  ### Limiting network
245
285
 
@@ -380,20 +420,23 @@ You should not override user quota related parameters, as they must be prepared
380
420
  ## Using custom docker images
381
421
 
382
422
  Trusted Sandbox comes with one ready-to-use image that includes Ruby 2.1.2. It is hosted on Docker Hub under
383
- `vaharoni/trusted_sandbox:2.1.2.v1`.
423
+ `vaharoni/trusted_sandbox:ruby-2.1.2.v1`.
424
+
425
+ We are actively looking for contributors who are willing to help expand the library of Docker images to support other
426
+ languages and environments.
384
427
 
385
428
  To use a different image from your Docker Hub account simply change the configuration parameters in the YAML file.
386
429
 
387
430
  To customize the provided images, run the following. It will copy the image definition to your current directory under
388
- `trusted_sandbox_images/2.1.2`.
431
+ `trusted_sandbox_images/ruby-2.1.2`.
389
432
  ```
390
433
  $ trusted_sandbox generate_image
391
434
  ```
392
435
 
393
436
  After modifying the files to your satisfaction, you can either push it to your Docker Hub account, or build directly
394
- on the server. Assuming you kept the image under trusted_sandbox_images/2.1.2:
437
+ on the server. Assuming you kept the image under trusted_sandbox_images/ruby-2.1.2:
395
438
  ```
396
- $ docker build -t "your_user/your_image_name:your_image_version" trusted_sandbox_images/2.1.2
439
+ $ docker build -t "your_user/your_image_name:your_image_version" trusted_sandbox_images/ruby-2.1.2
397
440
  ```
398
441
 
399
442
  ## Troubleshooting
@@ -421,7 +464,7 @@ $ trusted_sandbox reset_uid_pool
421
464
 
422
465
  To avoid containers from being deleted after they finish running, set:
423
466
  ```ruby
424
- keep_container: true
467
+ keep_containers: true
425
468
  ```
426
469
  This will allow you to view containers by running `docker ps -a` and then check out container logs
427
470
  `docker logs CONTAINER_ID` or container parameters `docker inspect CONTAINER_ID`.
@@ -443,7 +486,8 @@ $ docker ps -aq | xargs docker rm
443
486
  Licensed under the [MIT license](http://opensource.org/licenses/MIT).
444
487
 
445
488
  [1]: http://hmarr.com/2013/oct/16/codecube-runnable-gists/
446
- [2]: https://www.digitalocean.com/community/articles/how-to-enable-user-quotas
489
+ [2]: https://www.digitalocean.com/community/tutorials/how-to-enable-user-and-group-quotas
447
490
  [3]: http://hmarr.com/2013/oct/16/codecube-runnable-gists/
448
491
  [4]: https://www.digitalocean.com/community/tutorials/how-to-enable-user-quotas
449
- [5]: http://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo
492
+ [5]: http://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo
493
+ [6]: http://www.howtoforge.com/how-to-set-up-journaled-quota-on-debian-lenny
@@ -30,20 +30,31 @@ module TrustedSandbox
30
30
  `docker run -it -v #{local_code_dir}:/home/sandbox/src --entrypoint="/bin/bash" #{TrustedSandbox.config.docker_image_name} -s`
31
31
  end
32
32
 
33
- desc 'generate_image VERSION', 'Creates the Docker image files and places them into the `trusted_sandbox_images` directory. Default version is 2.1.2'
34
- def generate_image(image_version = '2.1.2')
33
+ desc 'generate_image IMAGE_NAME', 'Creates the Docker image files and places them into the `trusted_sandbox_images` directory. Default name is ruby-2.1.2'
34
+ def generate_image(image_name = 'ruby-2.1.2')
35
35
  target_dir = 'trusted_sandbox_images'
36
- target_image_path = "#{target_dir}/#{image_version}"
37
- gem_image_path = File.expand_path("../server_images/#{image_version}", __FILE__)
36
+ target_image_path = "#{target_dir}/#{image_name}"
37
+ gem_image_path = File.expand_path("../server_images/#{image_name}", __FILE__)
38
38
 
39
- puts "Image #{image_version} does not exist" unless Dir.exist?(gem_image_path)
39
+ puts "Image #{image_name} does not exist" or return unless Dir.exist?(gem_image_path)
40
40
  puts "Directory #{target_image_path} already exists" or return if Dir.exist?(target_image_path)
41
41
 
42
- puts "Copying #{image_version} into #{target_image_path}"
42
+ puts "Copying #{image_name} into #{target_image_path}"
43
43
  FileUtils.mkdir_p target_dir
44
44
  FileUtils.cp_r gem_image_path, target_image_path
45
45
  end
46
46
 
47
+ desc 'generate_images', 'Copies all Docker images files into `trusted_sandbox_images` directory'
48
+ def generate_images
49
+ target_dir = 'trusted_sandbox_images'
50
+ source_dir = File.expand_path("../server_images", __FILE__)
51
+
52
+ puts "Directory #{target_dir} already exists" or return if Dir.exist?(target_dir)
53
+ puts "Copying images into #{target_dir}"
54
+
55
+ FileUtils.cp_r source_dir, target_dir
56
+ end
57
+
47
58
  desc 'set_quotas QUOTA_KB', 'Sets the quota for all the UIDs in the pool. This requires additional installation. Refer to the README file.'
48
59
  def set_quotas(quota_kb)
49
60
  from = TrustedSandbox.config.pool_min_uid
@@ -9,7 +9,7 @@ development:
9
9
  # docker_url: https://192.168.59.103:2376
10
10
  # docker_cert_path: ~/.boot2docker/certs/boot2docker-vm
11
11
 
12
- docker_image_name: vaharoni/trusted_sandbox:2.1.2.v1
12
+ docker_image_name: vaharoni/trusted_sandbox:ruby-2.1.2.v1
13
13
 
14
14
  cpu_shares: 1
15
15
 
@@ -28,6 +28,10 @@ development:
28
28
  keep_code_folders: false
29
29
  keep_containers: false
30
30
 
31
+ # When this is set to false and keep_code_folders is true, you'll
32
+ # receive helpful messages about how to connect to your containers
33
+ quiet_mode: false
34
+
31
35
  # # It's very unlikely you'll need to change these
32
36
  # pool_size: 5000
33
37
  # pool_min_uid: 20000
@@ -6,19 +6,38 @@ module TrustedSandbox
6
6
  # specific_invocation = general_config.override(memory_limit: 200)
7
7
  #
8
8
  class Config
9
- attr_reader :other_config
10
-
9
+ attr_reader :fallback_config
10
+
11
+ # = Class macros
12
+
13
+ # Usage:
14
+ # attr_reader_with_fallback :my_attribute
15
+ #
16
+ # Equivalent to:
17
+ # def my_attribute
18
+ # return @my_attribute if @my_attribute
19
+ # return fallback_config.my_attribute if @my_attribute.nil? and fallback_config.respond_to?(:my_attribute)
20
+ # nil
21
+ # end
22
+ #
11
23
  def self.attr_reader_with_fallback(*names)
12
24
  names.each do |name|
13
25
  define_method name do
14
26
  value = instance_variable_get("@#{name}")
15
27
  return value unless value.nil?
16
- return other_config.send(name) if other_config.respond_to?(name)
28
+ return fallback_config.send(name) if fallback_config.respond_to?(name)
17
29
  nil
18
30
  end
19
31
  end
20
32
  end
21
33
 
34
+ # Usage:
35
+ # attr_accessor_with_fallback :my_attribute
36
+ #
37
+ # Equivalent to:
38
+ # attr_reader_with_fallback :my_attribute
39
+ # attr_writer :my_attribute
40
+ #
22
41
  def self.attr_accessor_with_fallback(*names)
23
42
  names.each do |name|
24
43
  attr_reader_with_fallback(name)
@@ -30,28 +49,36 @@ module TrustedSandbox
30
49
  :memory_limit, :memory_swap_limit, :cpu_shares, :docker_image_name,
31
50
  :execution_timeout, :network_access, :enable_swap_limit, :enable_quotas,
32
51
  :container_code_path, :container_input_filename, :container_output_filename,
33
- :keep_code_folders, :keep_containers
52
+ :keep_code_folders, :keep_containers, :quiet_mode
34
53
 
35
54
  attr_reader_with_fallback :host_code_root_path, :host_uid_pool_lock_path
36
55
 
37
56
  attr_reader :docker_url, :docker_cert_path, :docker_auth_email, :docker_auth_user, :docker_auth_password,
38
57
  :docker_auth_needed
39
58
 
59
+ # @param params [Hash] hash of parameters used to override the existing config object's attributes
60
+ # @return [Config] a new object with the fallback object set to self
40
61
  def override(params={})
41
62
  Config.send :new, self, params
42
63
  end
43
64
 
65
+ # @return [Integer] the upper boundary of the uid pool based on pool_min_uid and pool_size
44
66
  def pool_max_uid
45
67
  pool_min_uid + pool_size - 1
46
68
  end
47
69
 
48
- def docker_url=(value)
49
- @docker_url = value
50
- Docker.url = value
70
+ # @param url [String] URL for Docker daemon. Will be sent to the Docker class
71
+ # @return [String] the URL
72
+ def docker_url=(url)
73
+ @docker_url = url
74
+ Docker.url = url
51
75
  end
52
76
 
53
- def docker_cert_path=(value)
54
- @docker_cert_path = File.expand_path(value)
77
+ # Prepare to set Docker.options appropriately given a path to the cert directory.
78
+ # @param path [String] path to the certificate directory
79
+ # @return [Hash] of docker options that will be set
80
+ def docker_cert_path=(path)
81
+ @docker_cert_path = File.expand_path(path)
55
82
  @docker_options_for_cert = {
56
83
  private_key_path: "#{@docker_cert_path}/key.pem",
57
84
  certificate_path: "#{@docker_cert_path}/cert.pem",
@@ -59,14 +86,19 @@ module TrustedSandbox
59
86
  }
60
87
  end
61
88
 
89
+ # @param path [String] shorthand version of the path. E.g.: '~/tmp'
90
+ # @return [String] the full path that was set. E.g.: '/home/user/tmp'
62
91
  def host_code_root_path=(path)
63
92
  @host_code_root_path = File.expand_path(path)
64
93
  end
65
94
 
95
+ # @param path [String] shorthand version of the path
96
+ # @return [String] the full path that was set
66
97
  def host_uid_pool_lock_path=(path)
67
98
  @host_uid_pool_lock_path = File.expand_path(path)
68
99
  end
69
100
 
101
+ # Set hash used to authenticate with Docker
70
102
  # All keys are mandatory
71
103
  # @option :user [String]
72
104
  # @option :password [String]
@@ -78,7 +110,9 @@ module TrustedSandbox
78
110
  @docker_auth_email = options[:email] || options['email']
79
111
  end
80
112
 
81
- # Called to do any necessary setup to allow staged configuration
113
+ # Called to do any necessary setup to allow staged configuration. These involve:
114
+ # - Setting Docker.options based on the cert path
115
+ # - Calling Docker.authenticate! with the login parameters, if these were entered
82
116
  # @return [Config] self for chaining
83
117
  def finished_configuring
84
118
  Docker.options = @docker_options_for_cert.merge(docker_options)
@@ -91,12 +125,12 @@ module TrustedSandbox
91
125
 
92
126
  private_class_method :new
93
127
 
94
- # @params other_config [Config] config object that will be deferred to if the current config object does not
128
+ # @params fallback_config [Config] config object that will be deferred to if the current config object does not
95
129
  # contain a value for the requested configuration options
96
130
  # @params params [Hash] hash containing configuration options
97
- def initialize(other_config, params={})
131
+ def initialize(fallback_config, params={})
98
132
  @docker_options_for_cert = {}
99
- @other_config = other_config
133
+ @fallback_config = fallback_config
100
134
  params.each do |key, value|
101
135
  send "#{key}=", value
102
136
  end
@@ -3,7 +3,7 @@ module TrustedSandbox
3
3
 
4
4
  def initialize
5
5
  self.docker_options = {}
6
- self.docker_image_name = 'vaharoni/trusted_sandbox:2.1.2.v1'
6
+ self.docker_image_name = 'vaharoni/trusted_sandbox:ruby-2.1.2.v1'
7
7
  self.memory_limit = 50 * 1024 * 1024
8
8
  self.memory_swap_limit = 50 * 1024 * 1024
9
9
  self.cpu_shares = 1
@@ -27,6 +27,9 @@ module TrustedSandbox
27
27
  self.pool_size = 5000
28
28
 
29
29
  self.keep_code_folders = false
30
+ self.keep_containers = false
31
+
32
+ self.quiet_mode = false
30
33
  end
31
34
 
32
35
  end
@@ -0,0 +1,26 @@
1
+ module TrustedSandbox
2
+
3
+ # This is a general purpose class that can be used to run untrusted code in a container using TrustedSandbox.
4
+ # Usage:
5
+ #
6
+ # TrustedSandbox.run! TrustedSandbox::GeneralPurpose, "1 + 1"
7
+ # # => 2
8
+ #
9
+ # TrustedSandbox.run! TrustedSandbox::GeneralPurpose, "input[:a] + input[:b]", input: {a: 1, b: 2}
10
+ # # => 3
11
+ #
12
+ class GeneralPurpose
13
+ def initialize(code, args={})
14
+ @code = code
15
+ args.each do |name, value|
16
+ singleton_klass = class << self; self; end
17
+ singleton_klass.class_eval { attr_reader name }
18
+ instance_variable_set "@#{name}", value
19
+ end
20
+ end
21
+
22
+ def run
23
+ eval @code
24
+ end
25
+ end
26
+ end
@@ -4,32 +4,44 @@ module TrustedSandbox
4
4
  attr_reader :host_code_dir_path, :output_file_name, :stdout, :stderr,
5
5
  :raw_response, :status, :error, :error_to_raise, :output
6
6
 
7
+ # @param stdout [String, Array] response of stdout from the container
8
+ # @param stderr [String, Array] response of stderr from the container
7
9
  # @param host_code_dir_path [String] path to the folder where the argument value needs to be stored
8
10
  # @param output_file_name [String] name of output file inside the host_code_dir_path
9
- def initialize(host_code_dir_path, output_file_name, stdout, stderr)
10
- @host_code_dir_path = host_code_dir_path
11
- @output_file_name = output_file_name
11
+ def initialize(stdout = nil, stderr = nil, host_code_dir_path = nil, output_file_name = nil)
12
12
  @stdout = stdout
13
13
  @stderr = stderr
14
- parse_output_file
14
+ @host_code_dir_path = host_code_dir_path
15
+ @output_file_name = output_file_name
16
+ end
17
+
18
+ # @return [Response] object initialized with timeout error details
19
+ def self.timeout_error(err, logs)
20
+ obj = new(logs)
21
+ obj.instance_eval do
22
+ @status = 'error'
23
+ @error = err
24
+ @error_to_raise = TrustedSandbox::ExecutionTimeoutError.new(err)
25
+ end
26
+ obj
15
27
  end
16
28
 
29
+ # @return [Boolean]
17
30
  def valid?
18
31
  status == 'success'
19
32
  end
20
33
 
34
+ # @return [Object] the output returned by the container. Raises errors if encountered.
35
+ # @raise [ContainerError, UserCodeError, InternalError] if errors were raised by the container, they are bubbled
36
+ # as UserCodeError
21
37
  def output!
22
38
  propagate_errors!
23
39
  output
24
40
  end
25
41
 
26
- private
27
-
28
- def output_file_path
29
- File.join(host_code_dir_path, output_file_name)
30
- end
31
-
32
- def parse_output_file
42
+ # Parses the output file and stores the values in the appropriate ivars
43
+ # @return [nil]
44
+ def parse!
33
45
  begin
34
46
  data = File.binread output_file_path
35
47
  @raw_response = Marshal.load(data)
@@ -51,6 +63,13 @@ module TrustedSandbox
51
63
  @output = @raw_response[:output]
52
64
  @error = @raw_response[:error]
53
65
  @error_to_raise = UserCodeError.new(@error) if @error
66
+ nil
67
+ end
68
+
69
+ private
70
+
71
+ def output_file_path
72
+ File.join(host_code_dir_path, output_file_name)
54
73
  end
55
74
 
56
75
  def propagate_errors!
@@ -27,12 +27,27 @@ module TrustedSandbox
27
27
 
28
28
  # @param klass [Class] the class object that should be run
29
29
  # @param *args [Array] arguments to send to klass#initialize
30
- # @return [Response]
30
+ # @return [Object] return value from the #eval method
31
31
  # @raise [InternalError, UserCodeError, ContainerError]
32
32
  def run!(klass, *args)
33
33
  run(klass, *args).output!
34
34
  end
35
35
 
36
+ # @param code [String] code to be evaluated
37
+ # @param args [Hash] hash to send to GeneralPurpose
38
+ # @return [Response]
39
+ def run_code(code, args={})
40
+ run(GeneralPurpose, code, args)
41
+ end
42
+
43
+ # @param code [String] code to be evaluated
44
+ # @param args [Hash] hash to send to GeneralPurpose
45
+ # @return [Object] return value from the #eval method
46
+ # @raise [InternalError, UserCodeError, ContainerError]
47
+ def run_code!(code, args={})
48
+ run!(GeneralPurpose, code, args)
49
+ end
50
+
36
51
  private
37
52
 
38
53
  def obtain_uid
@@ -52,8 +67,7 @@ module TrustedSandbox
52
67
  end
53
68
 
54
69
  def create_code_dir
55
- if config.keep_code_folders
56
-
70
+ if config.keep_code_folders and !config.quiet_mode
57
71
  puts "Creating #{code_dir_path}"
58
72
  puts nil
59
73
  puts 'To launch and ssh into a new docker container with this directory mounted, run:'
@@ -80,9 +94,12 @@ module TrustedSandbox
80
94
  Timeout.timeout(config.execution_timeout) do
81
95
  stdout, stderr = @container.attach(stream: true, stdin: nil, stdout: true, stderr: true, logs: true, tty: false)
82
96
  end
83
- TrustedSandbox::Response.new code_dir_path, config.container_output_filename, stdout, stderr
97
+ response = TrustedSandbox::Response.new stdout, stderr, code_dir_path, config.container_output_filename
98
+ response.parse!
99
+ response
84
100
  rescue Timeout::Error => e
85
- raise TrustedSandbox::ExecutionTimeoutError.new(e)
101
+ logs = @container.logs(stdout: true, stderr: true)
102
+ TrustedSandbox::Response.timeout_error(e, logs)
86
103
  end
87
104
 
88
105
  def remove_container
@@ -50,7 +50,9 @@ module TrustedSandbox
50
50
  "#<TrustedSandbox::UidPool used: #{used}, available: #{available}, used_uids: #{used_uids}>"
51
51
  end
52
52
 
53
+ # Locks one UID from the pool, in a cross-process atomic manner
53
54
  # @return [Integer]
55
+ # @raise [PoolTimeoutError] if no ID is available after retries
54
56
  def lock
55
57
  retries.times do
56
58
  atomically(timeout) do
@@ -74,7 +76,9 @@ module TrustedSandbox
74
76
  self
75
77
  end
76
78
 
79
+ # Releases one UID
77
80
  # @param uid [Integer]
81
+ # @return [Integer] UID removed
78
82
  def release(uid)
79
83
  atomically(timeout) do
80
84
  release_uid uid
@@ -1,3 +1,3 @@
1
1
  module TrustedSandbox
2
- VERSION = '0.0.10.pre'
2
+ VERSION = '0.0.11.pre'
3
3
  end
@@ -5,6 +5,7 @@ module TrustedSandbox
5
5
  require 'trusted_sandbox/config'
6
6
  require 'trusted_sandbox/defaults'
7
7
  require 'trusted_sandbox/errors'
8
+ require 'trusted_sandbox/general_purpose'
8
9
  require 'trusted_sandbox/request_serializer'
9
10
  require 'trusted_sandbox/response'
10
11
  require 'trusted_sandbox/runner'
@@ -55,6 +56,14 @@ module TrustedSandbox
55
56
  new_runner.run!(klass, *args)
56
57
  end
57
58
 
59
+ def self.run_code(code, args={})
60
+ new_runner.run_code(code, args)
61
+ end
62
+
63
+ def self.run_code!(code, args={})
64
+ new_runner.run_code!(code, args)
65
+ end
66
+
58
67
  def self.new_runner(config_override = {})
59
68
  Runner.new(config, uid_pool, config_override)
60
69
  end