trusted-sandbox 0.0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f04a7997f512db9c4d422f4b5ca6f13e26b96c0e
4
+ data.tar.gz: 4e1ff6efa79e0353d880a4ea7bac92f680e464e3
5
+ SHA512:
6
+ metadata.gz: 72fb2983a31e0908a2d085b53c43d4e8452fb3edc3e81ca4d7af264bec9f8583211bc57a28c436dc6f3bade87645a94650e18f924ee27ba2780efd2afd56bd92
7
+ data.tar.gz: 6305312ad3faafa2295f16c47cbbfb4e8287185f986ac0c9ead45ef4340438e220c6f59f912e30f726c1fc689e1d4f92a459bb0e8c01211494f95fc6b4f00521
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .idea
2
+ .DS_Store
3
+ tmp/
4
+ .swp
5
+ pkg/
6
+ config/trusted_sandbox.yml
7
+ trusted_sandbox.yml
8
+ trusted_sandbox_images/
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ trusted-sandbox
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in trusted_sandbox.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ trusted-sandbox (0.0.2.pre)
5
+ docker-api (~> 1.13)
6
+ thor (~> 0.19)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ archive-tar-minitar (0.5.2)
12
+ docker-api (1.13.6)
13
+ archive-tar-minitar
14
+ excon (>= 0.38.0)
15
+ json
16
+ excon (0.40.0)
17
+ json (1.8.1)
18
+ rake (10.1.0)
19
+ thor (0.19.1)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bundler (~> 1.3)
26
+ rake
27
+ trusted-sandbox!
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Amit Aharoni
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,400 @@
1
+ # Trusted Sandbox
2
+
3
+ Run untrusted ruby code in a contained sandbox, using Docker. This gem was inspired by [Harry Marr's work][1].
4
+
5
+ ## Instant gratification
6
+
7
+ Trusted Sandbox makes it simple to execute Ruby classes that `eval` untrusted code in a resource-controlled docker container.
8
+ ```ruby
9
+ # lib/my_function.rb
10
+
11
+ class MyFunction
12
+ attr_reader :input
13
+
14
+ def initialize(user_code, input)
15
+ @user_code = user_code
16
+ @input = input
17
+ end
18
+
19
+ def run
20
+ eval @user_code
21
+ end
22
+ end
23
+ ```
24
+ ```ruby
25
+ # somewhere_else.rb
26
+ require 'trusted_sandbox'
27
+ require 'lib/my_function'
28
+
29
+ untrusted_code = "input[:number] ** 2"
30
+
31
+ # The following will run inside a Docker container
32
+ output = TrustedSandbox.run! MyFunction, untrusted_code, {number: 10}
33
+ # => 100
34
+ ```
35
+
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
+ ## Installing
40
+
41
+ ### Step 1
42
+ Add this line to your application's Gemfile:
43
+ ```
44
+ gem 'trusted-sandbox'
45
+ ```
46
+
47
+ And then execute:
48
+ ```
49
+ $ bundle
50
+ ```
51
+ Or install it yourself as:
52
+ ```
53
+ $ gem install trusted-sandbox
54
+ ```
55
+
56
+ Then, run the following command which will copy the `trusted_sandbox.yml` file into your current directory, or
57
+ `config` directory if it exists:
58
+ ```
59
+ $ trusted_sandbox install
60
+ ```
61
+
62
+ ### Step 2
63
+ Install Docker. Refer to the Docker documentation to see how to install Docker on your environment.
64
+
65
+ ### Step 3
66
+ Install the image. This step is optional, as Docker automatically installs images when you first run them. However,
67
+ since it takes a few minutes we suggest you do this in advance.
68
+ ```
69
+ $ docker run --rm vaharoni/trusted_sandbox:2.1.2.v1
70
+ ```
71
+ If you see the message "you must provide a uid", then you are set.
72
+
73
+ If you receive an error that looks like this: `Error response from daemon: Cannot start container 9f3bd8d72f0704980cedacc068261c38e280e7314916245550a6d48431ea8f11: fork/exec /var/lib/docker/init/dockerinit-1.0.1: cannot allocate memory`
74
+ consider restarting docker:
75
+ ```
76
+ $ sudo service docker.io restart
77
+ ```
78
+ and then try again.
79
+
80
+ ### Step 4
81
+
82
+ If you'd like to limit swap memory or set user quotas you'll have to install additional programs on your server.
83
+ Follow the instructions in the relevant sections of the configuration guide.
84
+
85
+ ## Configuring Trusted Sandbox
86
+
87
+ Let's go over the sections of the YAML configuration file you created in step 1 above.
88
+
89
+ ### Docker access
90
+ ```ruby
91
+ # ENV['DOCKER_HOST'] is used if omitted
92
+ docker_url: https://192.168.59.103:2376
93
+
94
+ # ENV['DOCKER_CERT_PATH'] is used if omitted
95
+ docker_cert_path: ~/.boot2docker/certs/boot2docker-vm
96
+
97
+ docker_image_name: vaharoni/trusted_sandbox:2.1.2.v1
98
+
99
+ # Optional authentication
100
+ docker_login:
101
+ user: my_user
102
+ password: my_password
103
+ email: email@email.com
104
+
105
+ ```
106
+
107
+ Trusted Sandbox uses the `docker-api` gem to communicate with docker. Some of the parameters above are used to setup
108
+ the global `Docker` class. For finer control of its configuration, you can add a `docker_options` hash entry to the
109
+ YAML file which will override any configuration and passed through to `Docker.options`.
110
+
111
+ ### Limiting resources
112
+ CPU:
113
+ ```ruby
114
+ cpu_shares: 1 # In relative units
115
+ ```
116
+ Memory:
117
+ ```ruby
118
+ memory_limit: 52_428_800 # In bytes
119
+ enable_swap_limit: false
120
+ memory_swap_limit: 52_428_800 # In bytes. Relevant only if enable_swap_limit is true.
121
+ ```
122
+ Execution
123
+ ```ruby
124
+ execution_timeout: 15 # In seconds
125
+ network_access: false
126
+ ```
127
+ Quotas
128
+ ```ruby
129
+ enable_quotas: false
130
+ ```
131
+ Settings for UID-pool used for assigning user quotas. Always used, even if quota functionality is disabled.
132
+ It's very unlikely you'll need to touch these:
133
+ ```ruby
134
+ pool_size: 5000
135
+ pool_min_uid: 20000
136
+ pool_timeout: 3
137
+ pool_retries: 5
138
+ pool_delay: 0.5
139
+ ```
140
+ Note that controlling memory swap limits and user quotas requires additional steps as outlined below.
141
+
142
+ ### Execution parameters
143
+
144
+ A temporary directory under which sub directories are created and mounted to containers.
145
+ The code and args exchange between the host and containers is done via these sub directories.
146
+
147
+ ```ruby
148
+ host_code_root_path: tmp/code_dirs
149
+ ```
150
+
151
+ When set to true, the temporary sub directories will not be erased. This allows you to login to the container to
152
+ troubleshoot issues as explained in the "Troubleshooting" section.
153
+ ```ruby
154
+ keep_code_folders: false
155
+ ```
156
+
157
+ A directory used by the UID-pool to handle locks.
158
+ ```ruby
159
+ host_uid_pool_lock_path: tmp/uid_pool_lock
160
+ ```
161
+
162
+ ### Limiting swap memory
163
+
164
+ In order to limit swap memory, you'll need to set up your host server to allow that.
165
+ The following should work for Debian / Ubuntu.
166
+
167
+ First, run:
168
+ ```
169
+ $ sudoedit /etc/default/grub
170
+ ```
171
+ and edit the following line:
172
+ ```
173
+ GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
174
+ ```
175
+ Then run:
176
+ ```
177
+ $ sudo update-grub
178
+ ```
179
+ Reboot the server, and you should be set. Read more about it [here][2].
180
+ Remember to set `enable_swap_limit: true` in the YAML file.
181
+
182
+ ### Limiting user quotas
183
+
184
+ Note: due to permission setting scheme, limiting user quota does not work on OS or Windows.
185
+
186
+ In order to control quotas we follow the technique suggested by [Harry Marr][3]. It makes use of the fact that
187
+ UIDs (user IDs) and GIDs (Group IDs) are shared between the host and its containers. When a container starts, we
188
+ run the untrusted code under an unprivileged user whose UID has a quota enforced by the host.
189
+
190
+ In order to enable quotas do the following on the server:
191
+ ```
192
+ $ sudo apt-get install quota
193
+ ```
194
+ And follow [these instructions][4], which are also brought here for completeness:
195
+ ```
196
+ $ sudo vim /etc/fstab
197
+ ```
198
+ Add `,usrquota` in the end of column no. 4 so it looks something like:
199
+ ```
200
+ LABEL=cloudimg-rootfs / ext4 defaults,discard,usrquota 0 0
201
+ ```
202
+ Then do:
203
+ ```
204
+ $ mount -o remount
205
+ ```
206
+ and reboot the server. Finally, run the following (quota is in KB):
207
+ ```
208
+ $ trusted_sandbox set_quotas 10000
209
+ ```
210
+ This sets ~10MB quota on all UIDs that are in the range defined by `pool_size` and `pool_min_uid` parameters. If you
211
+ change these configuration parameters you must rerun the `set_quotas` command.
212
+
213
+ Remember to set `enable_quotas: true` in the YAML file.
214
+
215
+ Note: At this time, there is no way to assign different quotas to different users.
216
+
217
+ ### Limiting network
218
+
219
+ The only option available is to turn on and off network access using `enable_network`. Finer control of network
220
+ access is currently not supported. If you need this feature please open an issue and share your use case.
221
+
222
+ ## Using Trusted Sandbox
223
+
224
+ ### Class and argument serialization
225
+
226
+ The class you send to a container can be as elaborate as you want, providing a context of execution for the user code.
227
+ When you call `run` or `run!` with a class constant, the file where that class is defined is copied to the
228
+ `/home/sandbox/src` folder inside the container. Any arguments needed to instantiate an object from that class are
229
+ serialized. When the container starts, it deserializes these arguments, invokes the `new` method with them, and runs
230
+ `run` on the instantiated object. The output of that method is then serialized back to the host.
231
+
232
+ A less trivial example:
233
+ ```ruby
234
+ # my_function.rb
235
+
236
+ # Example for requiring a gem, assuming it is in the Gemfile of both the container and the
237
+ # host. If you want to access a gem that is only available to the container, put the require
238
+ # directive inside `initialize` or `run` methods.
239
+ require 'hashie/mash'
240
+
241
+ class MyFunction
242
+
243
+ attr_reader :a, :b
244
+ def initialize(first_user_func, second_user_func, a, b)
245
+ @first_user_func = first_user_func
246
+ @second_user_func = second_user_func
247
+ @a = a
248
+ @b = b
249
+ end
250
+
251
+ def run
252
+ # Will have access to #a and #b through attr_reader
253
+ result1 = eval(@first_user_func)
254
+
255
+ result2 = Context.new(result1).run(@second_user_func)
256
+ [result1, result2]
257
+ end
258
+
259
+ class Context
260
+ attr_reader :x
261
+ def initialize(x)
262
+ @x = x
263
+ end
264
+
265
+ def run(code)
266
+ eval code
267
+ end
268
+ end
269
+ end
270
+ ```
271
+ ```ruby
272
+ # Somewhere else
273
+ require 'trusted_sandbox'
274
+ require 'my_function'
275
+ a, b = TrustedSandbox.run! MyFunction, "a + b", "x ** 2", 2, 5
276
+ # => 49
277
+ ```
278
+ Because serialization occurs through Marshalling, you should use primitive Ruby classes for your inputs as much as
279
+ possible. You can prepare a docker image with additional gems and custom Ruby classes, as explained in the
280
+ "Using custom docker images" section.
281
+
282
+ ### Running containers
283
+
284
+ There are two ways to run a container. Use `run!` to retrieve output from the container. If the user code raised
285
+ an exception, it will be raised by `run!`.
286
+
287
+ ```ruby
288
+ output = TrustedSandbox.run! MyFunction, "input ** 2", 10
289
+ # => 100
290
+ ```
291
+ Use `run` to retrieve a response object. The response object provides additional useful information about the
292
+ container execution.
293
+
294
+ Here is an error scenario:
295
+ ```ruby
296
+ response = TrustedSandbox.run MyFunction, "raise 'error!'", 10
297
+
298
+ response.status
299
+ # => "error"
300
+
301
+ response.valid?
302
+ # => false
303
+
304
+ response.output
305
+ # => nil
306
+
307
+ response.output!
308
+ # => TrustedSandbox::UserCodeError: error!
309
+
310
+ response.error
311
+ # => #<RuntimeError: error!>
312
+
313
+ response.error.backtrace
314
+ # => /home/sandbox/src/my_function.rb:14:in `eval'
315
+ # => /home/sandbox/src/my_function.rb:14:in `eval'
316
+ # => /home/sandbox/src/my_function.rb:14:in `run'
317
+
318
+ # Can be useful if MyFunction prints to stdout
319
+ puts response.stdout
320
+
321
+ # Can be useful for environment related errors
322
+ puts response.stderr
323
+ ```
324
+ Here is a success scenario:
325
+ ```ruby
326
+ response = TrustedSandbox.run MyFunction, "input ** 2", 10
327
+
328
+ response.status
329
+ # => "success"
330
+
331
+ response.valid?
332
+ # => true
333
+
334
+ response.output
335
+ # => 100
336
+
337
+ response.output!
338
+ # => 100
339
+
340
+ response.error
341
+ # => nil
342
+ ```
343
+ ### Overriding specific invocations
344
+
345
+ To override a configuration parameter for a specific invocation, use `with_options`:
346
+ ```ruby
347
+ TrustedSandbox.with_options(cpu_shares: 2) do |s|
348
+ s.run! MyFunction, untrusted_code, input
349
+ end
350
+ ```
351
+ You should not override user quota related parameters, as they must be prepared on the host in advance of execution.
352
+
353
+ ## Using custom docker images
354
+
355
+ Trusted Sandbox comes with one ready-to-use image that includes Ruby 2.1.2. It is hosted on Docker Hub under
356
+ `vaharoni/trusted_sandbox:2.1.2.v1`.
357
+
358
+ To use a different image from your Docker Hub account simply change the configuration parameters in the YAML file.
359
+
360
+ To customize the provided images, run the following. It will copy the image definition to your current directory under
361
+ `trusted_sandbox_images/2.1.2`.
362
+ ```
363
+ $ trusted_sandbox generate_image
364
+ ```
365
+
366
+ After modifying the files to your satisfaction, you can either push it to your Docker Hub account, or build directly
367
+ on the server. Assuming you kept the image under trusted_sandbox_images/2.1.2:
368
+ ```
369
+ $ docker build -t "your_user/your_image_name:your_image_version" trusted_sandbox_images/2.1.2
370
+ ```
371
+
372
+ ## Troubleshooting
373
+
374
+ If you encounter issues, try troubleshooting them by accessing your container's bash. Make the following change in the
375
+ YAML file:
376
+
377
+ ```ruby
378
+ keep_code_folders: true
379
+ ```
380
+ This will keep your code folders from getting deleted when containers stop running. This allows you to do the
381
+ following from your command line (adjust to your environment):
382
+ ```
383
+ $ docker run -it -v /home/MyUser/my_app/tmp/code_dirs/20000:/home/sandbox/src --entrypoint="/bin/bash" my_user/my_image:my_tag
384
+ ```
385
+
386
+ ## Contributing
387
+
388
+ 1. Fork it
389
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
390
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
391
+ 4. Push to the branch (`git push origin my-new-feature`)
392
+ 5. Create new Pull Request
393
+
394
+ ## License
395
+ Licensed under the [MIT license](http://opensource.org/licenses/MIT).
396
+
397
+ [1]: http://hmarr.com/2013/oct/16/codecube-runnable-gists/
398
+ [2]: https://www.digitalocean.com/community/articles/how-to-enable-user-quotas
399
+ [3]: http://hmarr.com/2013/oct/16/codecube-runnable-gists/
400
+ [4]: https://www.digitalocean.com/community/tutorials/how-to-enable-user-quotas
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'trusted_sandbox/cli'
4
+ TrustedSandbox::Cli.start(ARGV)
@@ -0,0 +1,43 @@
1
+ require 'thor'
2
+
3
+ module TrustedSandbox
4
+ class Cli < Thor
5
+ desc 'install', 'Creates trusted_sandbox.yml in `config`, if this directory exists, or in the current directory otherwise'
6
+ def install
7
+ curr_dir_file = 'trusted_sandbox.yml'
8
+ config_dir_file = 'config/trusted_sandbox.yml'
9
+
10
+ puts "#{curr_dir_file} already exists" or return if File.exist?(curr_dir_file)
11
+ puts "#{config_dir_file} already exists" or return if File.exist?(config_dir_file)
12
+
13
+ target_file = Dir.exist?('config') ? config_dir_file : curr_dir_file
14
+
15
+ puts "Creating #{target_file}"
16
+ FileUtils.cp File.expand_path('../config/trusted_sandbox.yml', __FILE__), target_file
17
+ end
18
+
19
+ desc 'generate_image VERSION', 'Creates the Docker image files and places them into the `trusted_sandbox_images` directory. Default version is 2.1.2'
20
+ def generate_image(image_version = '2.1.2')
21
+ target_dir = 'trusted_sandbox_images'
22
+ target_image_path = "#{target_dir}/#{image_version}"
23
+ gem_image_path = File.expand_path("../server_images/#{image_version}", __FILE__)
24
+
25
+ puts "Image #{image_version} does not exist" unless Dir.exist?(gem_image_path)
26
+ puts "Directory #{target_image_path} already exists" or return if Dir.exist?(target_image_path)
27
+
28
+ puts "Copying #{image_version} into #{target_image_path}"
29
+ FileUtils.mkdir_p target_dir
30
+ FileUtils.cp_r gem_image_path, target_image_path
31
+ end
32
+
33
+ desc 'set_quotas QUOTA_KB', 'Sets the quota for all the UIDs in the pool. This requires additional installation. Refer to the README file.'
34
+ def set_quotas(quota_kb)
35
+ from = TrustedSandbox.config.pool_min_uid
36
+ to = TrustedSandbox.config.pool_max_uid
37
+ puts "Configuring quota for UIDs [#{from}..#{to}]"
38
+ (from..to).each do |uid|
39
+ `setquota -u #{uid} 0 #{quota_kb} 0 0 /`
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ development:
2
+ # Optional login information
3
+ docker_login:
4
+ user: my_user
5
+ password: my_password
6
+ email: email@email.com
7
+
8
+ docker_url: https://192.168.59.103:2376
9
+ docker_cert_path: ~/.boot2docker/certs/boot2docker-vm
10
+
11
+ docker_image_name: vaharoni/trusted_sandbox:2.1.2.v1
12
+
13
+ cpu_shares: 1
14
+
15
+ memory_limit: 52_428_800 # 50 MB
16
+ enable_swap_limit: false
17
+ memory_swap_limit: 52_428_800 # 50 MB
18
+
19
+ execution_timeout: 15
20
+ network_access: false
21
+
22
+ enable_quotas: false
23
+
24
+ host_code_root_path: tmp/code_dirs
25
+ host_uid_pool_lock_path: tmp/uid_pool_lock
26
+ keep_code_folders: false
27
+
28
+ pool_size: 5000
29
+ pool_min_uid: 20000
30
+ pool_timeout: 3
31
+ pool_retries: 5
32
+ pool_delay: 0.5
@@ -0,0 +1,103 @@
1
+ module TrustedSandbox
2
+
3
+ # Allows chaining so that specific invocations can override configurations.
4
+ # Usage:
5
+ # general_config = Defaults.new.override(pool_size: 10, memory_limit: 100)
6
+ # specific_invocation = general_config.override(memory_limit: 200)
7
+ #
8
+ class Config
9
+ attr_reader :other_config
10
+
11
+ def self.attr_reader_with_fallback(*names)
12
+ names.each do |name|
13
+ define_method name do
14
+ value = instance_variable_get("@#{name}")
15
+ return value unless value.nil?
16
+ return other_config.send(name) if other_config.respond_to?(name)
17
+ nil
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.attr_accessor_with_fallback(*names)
23
+ names.each do |name|
24
+ attr_reader_with_fallback(name)
25
+ attr_writer(name)
26
+ end
27
+ end
28
+
29
+ attr_accessor_with_fallback :pool_size, :pool_min_uid, :pool_timeout, :pool_retries, :pool_delay, :docker_options,
30
+ :memory_limit, :memory_swap_limit, :cpu_shares, :docker_image_name,
31
+ :execution_timeout, :network_access, :enable_swap_limit, :enable_quotas,
32
+ :container_code_path, :container_input_filename, :container_output_filename,
33
+ :keep_code_folders
34
+
35
+ attr_reader_with_fallback :host_code_root_path, :host_uid_pool_lock_path
36
+
37
+ attr_reader :docker_url, :docker_cert_path, :docker_auth_email, :docker_auth_user, :docker_auth_password,
38
+ :docker_auth_needed
39
+
40
+ def override(params={})
41
+ Config.send :new, self, params
42
+ end
43
+
44
+ def pool_max_uid
45
+ pool_min_uid + pool_size - 1
46
+ end
47
+
48
+ def docker_url=(value)
49
+ @docker_url = value
50
+ Docker.url = value
51
+ end
52
+
53
+ def docker_cert_path=(value)
54
+ @docker_cert_path = File.expand_path(value)
55
+ Docker.options = {
56
+ private_key_path: "#{@docker_cert_path}/key.pem",
57
+ certificate_path: "#{@docker_cert_path}/cert.pem",
58
+ ssl_verify_peer: false
59
+ }.merge(docker_options)
60
+ end
61
+
62
+ def host_code_root_path=(path)
63
+ @host_code_root_path = File.expand_path(path)
64
+ end
65
+
66
+ def host_uid_pool_lock_path=(path)
67
+ @host_uid_pool_lock_path = File.expand_path(path)
68
+ end
69
+
70
+ # All keys are mandatory
71
+ # @option :user [String]
72
+ # @option :password [String]
73
+ # @option :email [String]
74
+ def docker_login=(options={})
75
+ @docker_auth_needed = true
76
+ @docker_auth_user = options[:user] || options['user']
77
+ @docker_auth_password = options[:password] || options['password']
78
+ @docker_auth_email = options[:email] || options['email']
79
+ end
80
+
81
+ # Called to do any necessary setup to allow staged configuration
82
+ # @return [Config] self for chaining
83
+ def finished_configuring
84
+ return self unless @docker_auth_needed
85
+ Docker.authenticate! username: @docker_auth_user, password: @docker_auth_password, email: @docker_auth_email
86
+ @docker_auth_needed = false
87
+ self
88
+ end
89
+
90
+ private_class_method :new
91
+
92
+ # @params other_config [Config] config object that will be deferred to if the current config object does not
93
+ # contain a value for the requested configuration options
94
+ # @params params [Hash] hash containing configuration options
95
+ def initialize(other_config, params={})
96
+ @other_config = other_config
97
+ params.each do |key, value|
98
+ send "#{key}=", value
99
+ end
100
+ end
101
+
102
+ end
103
+ end