trusted-sandbox 0.0.2.pre

Sign up to get free protection for your applications and to get access to all the features.
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