secure_headers 3.0.0.pre2 → 3.0.0.pre3

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.

Potentially problematic release.


This version of secure_headers might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6e439e921b5270ed007c604d2287b04a5ef691f
4
- data.tar.gz: 6ae708cd125952e4ad7f24121d1be4f5b8d54d1d
3
+ metadata.gz: 7e0a5f8e1d4955125f71ede3b2f1bd882ccaca56
4
+ data.tar.gz: 656cc8d6965a49288b7ccd2ab3fc91fb13ab9792
5
5
  SHA512:
6
- metadata.gz: a426253499c8e6e1c70d6f1f11cde022d90f4ea9dc8db1073f1055ee0c82e6be007b2746ff5e98cb4e12c0f0064b7e656c4861e97bf10fd01f156f8e78d551a1
7
- data.tar.gz: 91ef0e9f9f32d311389d35c0caf3b607da10b6e8fc029d1a4a1514c35ca2df92b1a9dbda224d6e4808d39517dc4d2ef62317bcf1c7f3d1071cd37231fe461141
6
+ metadata.gz: 4a61ccca281e3968c41aa6daf1d069b6a6aef9d796c62cc0b5c7be45007fc3ca41908f71310c289c854e386dfafbb1b96cfa5eca45fc598f43113edb8b7678f0
7
+ data.tar.gz: edd0190e206824a91e961131f8f612ac7a10559ced00c9b314cba681d579cfc27c9280205dbe687725579a7a242fcae70c6e4a279bafcb2981e63ee00679c4e6
data/README.md CHANGED
@@ -1,26 +1,31 @@
1
- # SecureHeaders [![Build Status](https://travis-ci.org/twitter/secureheaders.png?branch=master)](http://travis-ci.org/twitter/secureheaders) [![Code Climate](https://codeclimate.com/github/twitter/secureheaders.png)](https://codeclimate.com/github/twitter/secureheaders) [![Coverage Status](https://coveralls.io/repos/twitter/secureheaders/badge.png)](https://coveralls.io/r/twitter/secureheaders)
1
+ # Secure Headers [![Build Status](https://travis-ci.org/twitter/secureheaders.png?branch=master)](http://travis-ci.org/twitter/secureheaders) [![Code Climate](https://codeclimate.com/github/twitter/secureheaders.png)](https://codeclimate.com/github/twitter/secureheaders) [![Coverage Status](https://coveralls.io/repos/twitter/secureheaders/badge.png)](https://coveralls.io/r/twitter/secureheaders)
2
+
2
3
 
3
4
  **The 3.x branch was recently merged**. See the [upgrading to 3.x doc](upgrading-to-3-0.md) for instructions on how to upgrade including the differences and benefits of using the 3.x branch.
4
5
 
5
- **The [2.x branch](https://github.com/twitter/secureheaders/tree/2.x) will be maintained**. The documentation below only applies to the 2.x branch. See the 2.x [README](https://github.com/twitter/secureheaders/blob/2.x/README.md) for the old way of doing things.
6
+ **The [2.x branch](https://github.com/twitter/secureheaders/tree/2.x) will be maintained**. The documentation below only applies to the 3.x branch. See the 2.x [README](https://github.com/twitter/secureheaders/blob/2.x/README.md) for the old way of doing things.
6
7
 
7
8
  The gem will automatically apply several headers that are related to security. This includes:
8
9
  - Content Security Policy (CSP) - Helps detect/prevent XSS, mixed-content, and other classes of attack. [CSP 2 Specification](http://www.w3.org/TR/CSP2/)
9
10
  - HTTP Strict Transport Security (HSTS) - Ensures the browser never visits the http version of a website. Protects from SSLStrip/Firesheep attacks. [HSTS Specification](https://tools.ietf.org/html/rfc6797)
10
11
  - X-Frame-Options (XFO) - Prevents your content from being framed and potentially clickjacked. [X-Frame-Options draft](https://tools.ietf.org/html/draft-ietf-websec-x-frame-options-02)
11
- - X-XSS-Protection - [Cross site scripting heuristic filter for IE/Chrome](http://msdn.microsoft.com/en-us/library/dd565647\(v=vs.85\).aspx)
12
- - X-Content-Type-Options - [Prevent content type sniffing](http://msdn.microsoft.com/en-us/library/ie/gg622941\(v=vs.85\).aspx)
13
- - X-Download-Options - [Prevent file downloads opening](http://msdn.microsoft.com/en-us/library/ie/jj542450(v=vs.85).aspx)
12
+ - X-XSS-Protection - [Cross site scripting heuristic filter for IE/Chrome](https://msdn.microsoft.com/en-us/library/dd565647\(v=vs.85\).aspx)
13
+ - X-Content-Type-Options - [Prevent content type sniffing](https://msdn.microsoft.com/library/gg622941\(v=vs.85\).aspx)
14
+ - X-Download-Options - [Prevent file downloads opening](https://msdn.microsoft.com/library/jj542450(v=vs.85).aspx)
14
15
  - X-Permitted-Cross-Domain-Policies - [Restrict Adobe Flash Player's access to data](https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html)
15
16
  - Public Key Pinning - Pin certificate fingerprints in the browser to prevent man-in-the-middle attacks due to compromised Certificate Authorities. [Public Key Pinning Specification](https://tools.ietf.org/html/rfc7469)
16
17
 
17
- `secure_headers` is a library with a global config, per request overrides, and rack milddleware that enables you customize your application settings.
18
+ `secure_headers` is a library with a global config, per request overrides, and rack middleware that enables you customize your application settings.
19
+
20
+ ## Use
21
+
22
+ `gem install secure_headers`
18
23
 
19
24
  ## Configuration
20
25
 
21
26
  If you do not supply a `default` configuration, exceptions will be raised. If you would like to use a default configuration (which is fairly locked down), just call `SecureHeaders::Configuration.default` without any arguments or block.
22
27
 
23
- All `nil` values will fallback to their default value. `SecureHeaders::OPT_OUT` will disable the header entirely.
28
+ All `nil` values will fallback to their default values. `SecureHeaders::OPT_OUT` will disable the header entirely.
24
29
 
25
30
  ```ruby
26
31
  SecureHeaders::Configuration.default do |config|
@@ -31,12 +36,15 @@ SecureHeaders::Configuration.default do |config|
31
36
  config.x_download_options = "noopen"
32
37
  config.x_permitted_cross_domain_policies = "none"
33
38
  config.csp = {
39
+ # "meta" values. these will shaped the header, but the values are not included in the header.
40
+ report_only: true, # default: false
41
+ preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
42
+
43
+ # directive values: these values will directly translate into source directives
34
44
  default_src: %w(https: 'self'),
35
- report_only: false,
36
- frame_src: %w(*.twimg.com itunes.apple.com),
45
+ frame_src: %w('self' *.twimg.com itunes.apple.com),
37
46
  connect_src: %w(wws:),
38
47
  font_src: %w('self' data:),
39
- frame_src: %w('self'),
40
48
  img_src: %w(mycdn.com data:),
41
49
  media_src: %w(utoob.com),
42
50
  object_src: %w('self'),
@@ -129,7 +137,7 @@ end
129
137
 
130
138
  ## Per-action configuration
131
139
 
132
- You can override the settings for a given action by producing a temporary override. This approach is not recommended because the header values will be computed per request.
140
+ You can override the settings for a given action by producing a temporary override. Be aware that because of the dynamic nature of the value, the header values will be computed per request.
133
141
 
134
142
  ```ruby
135
143
  # Given a config of:
@@ -148,7 +156,7 @@ class MyController < ApplicationController
148
156
 
149
157
  # Overrides the previously set source list, override 'none' values
150
158
  # Produces: default-src 'self'; script-src s3.amazaonaws.com; object-src 'self'
151
- override_content_security_policy_directive(script_src: %w(s3.amazaonaws.com), object_src: %w('self'))
159
+ override_content_security_policy_directives(script_src: %w(s3.amazaonaws.com), object_src: %w('self'))
152
160
 
153
161
  # Global settings default to "sameorigin"
154
162
  override_x_frame_options("DENY")
@@ -157,7 +165,7 @@ class MyController < ApplicationController
157
165
 
158
166
  The following methods are available as controller instance methods. They are also available as class methods, but require you to pass in the `request` object.
159
167
  * `append_content_security_policy_directives(hash)`: appends each value to the corresponding CSP app-wide configuration.
160
- * `override_content_security_policy_directive(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
168
+ * `override_content_security_policy_directives(hash)`: merges the hash into the app-wide configuration, overwriting any previous config
161
169
  * `override_x_frame_options(value)`: sets the `X-Frame-Options header` to `value`
162
170
 
163
171
  ## Appending / overriding Content Security Policy
@@ -169,7 +177,7 @@ When manipulating content security policy, there are a few things to consider. T
169
177
  The value of `default_src` is joined with the addition. Note the `https:` is carried over from the `default-src` config. If you do not want this, use `override_content_security_policy_directives` instead. To illustrate:
170
178
 
171
179
  ```ruby
172
- ::SecureHeaders::Configuration.configure do |config|
180
+ ::SecureHeaders::Configuration.default do |config|
173
181
  config.csp = {
174
182
  default_src: %w('self')
175
183
  }
@@ -181,11 +189,6 @@ Code | Result
181
189
  `append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src 'self' mycdn.com`
182
190
  `override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src 'self'; script-src mycdn.com`
183
191
 
184
- Code | Result
185
- ------------- | -------------
186
- `append_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src https:; script-src https: mycdn.com`
187
- `override_content_security_policy_directives(script_src: %w(mycdn.com))` | `default-src https:; script-src mycdn.com`
188
-
189
192
  #### Nonce
190
193
 
191
194
  script/style-nonce can be used to whitelist inline content. To do this, call the SecureHeaders::content_security_policy_nonce then set the nonce attributes on the various tags.
@@ -269,7 +272,7 @@ require 'secure_headers'
269
272
 
270
273
  use SecureHeaders::Middleware
271
274
 
272
- SecureHeaders::Configuration.configure do |config|
275
+ SecureHeaders::Configuration.default do |config|
273
276
  ...
274
277
  end
275
278
 
@@ -314,7 +317,7 @@ and in `config/boot.rb`:
314
317
 
315
318
  ```ruby
316
319
  def before_load
317
- SecureHeaders::Configuration.configure do |config|
320
+ SecureHeaders::Configuration.default do |config|
318
321
  ...
319
322
  end
320
323
  end
@@ -322,13 +325,14 @@ end
322
325
 
323
326
  ## Similar libraries
324
327
 
325
- * Rack [rack-secure_headers](https://github.com/harmoni/rack-secure_headers)
326
- * Node.js (express) [helmet](https://github.com/evilpacket/helmet) and [hood](https://github.com/seanmonstar/hood)
328
+ * Rack [rack-secure_headers](https://github.com/frodsan/rack-secure_headers)
329
+ * Node.js (express) [helmet](https://github.com/helmetjs/helmet) and [hood](https://github.com/seanmonstar/hood)
327
330
  * Node.js (hapi) [blankie](https://github.com/nlf/blankie)
328
331
  * J2EE Servlet >= 3.0 [headlines](https://github.com/sourceclear/headlines)
329
332
  * ASP.NET - [NWebsec](https://github.com/NWebsec/NWebsec/wiki)
330
333
  * Python - [django-csp](https://github.com/mozilla/django-csp) + [commonware](https://github.com/jsocol/commonware/); [django-security](https://github.com/sdelements/django-security)
331
334
  * Go - [secureheader](https://github.com/kr/secureheader)
335
+ * Elixir [secure_headers](https://github.com/anotherhale/secure_headers)
332
336
 
333
337
  ## License
334
338
 
@@ -47,12 +47,15 @@ module SecureHeaders
47
47
  # additions - a hash containing directives. e.g.
48
48
  # script_src: %w(another-host.com)
49
49
  def override_content_security_policy_directives(request, additions)
50
- config = config_for(request).dup
51
- if config.csp == OPT_OUT
52
- config.csp = {}
50
+ config = config_for(request)
51
+ unless CSP.idempotent_additions?(config.csp, additions)
52
+ config = config.dup
53
+ if config.csp == OPT_OUT
54
+ config.csp = {}
55
+ end
56
+ config.csp.merge!(additions)
57
+ override_secure_headers_request_config(request, config)
53
58
  end
54
- config.csp.merge!(additions)
55
- override_secure_headers_request_config(request, config)
56
59
  end
57
60
 
58
61
  # Public: appends source values to the current configuration. If no value
@@ -62,9 +65,12 @@ module SecureHeaders
62
65
  # additions - a hash containing directives. e.g.
63
66
  # script_src: %w(another-host.com)
64
67
  def append_content_security_policy_directives(request, additions)
65
- config = config_for(request).dup
66
- config.csp = CSP.combine_policies(config.csp, additions)
67
- override_secure_headers_request_config(request, config)
68
+ config = config_for(request)
69
+ unless CSP.idempotent_additions?(config.csp, additions)
70
+ config = config.dup
71
+ config.csp = CSP.combine_policies(config.csp, additions)
72
+ override_secure_headers_request_config(request, config)
73
+ end
68
74
  end
69
75
 
70
76
  # Public: override X-Frame-Options settings for this request.
@@ -145,7 +145,12 @@ module SecureHeaders
145
145
  STAR,
146
146
  DATA_PROTOCOL,
147
147
  BLOB_PROTOCOL
148
- ]
148
+ ].freeze
149
+
150
+ META_CONFIGS = [
151
+ :report_only,
152
+ :preserve_schemes
153
+ ].freeze
149
154
 
150
155
  class << self
151
156
  # Public: generate a header name, value array that is user-agent-aware.
@@ -157,13 +162,7 @@ module SecureHeaders
157
162
  [header.name, header.value]
158
163
  end
159
164
 
160
- # Public: Validates that the configuration has a valid type, or that it is a valid
161
- # source expression.
162
- #
163
- # Private: validates that a source expression:
164
- # 1. has a valid name
165
- # 2. is an array of strings
166
- # 3. does not contain any depreated, now invalid values (inline, eval, self, none)
165
+ # Public: Validates each source expression.
167
166
  #
168
167
  # Does not validate the invididual values of the source expression (e.g.
169
168
  # script_src => h*t*t*p: will not raise an exception)
@@ -171,7 +170,7 @@ module SecureHeaders
171
170
  return if config.nil? || config == OPT_OUT
172
171
  raise ContentSecurityPolicyConfigError.new(":default_src is required") unless config[:default_src]
173
172
  config.each do |key, value|
174
- if key == :report_only
173
+ if META_CONFIGS.include?(key)
175
174
  raise ContentSecurityPolicyConfigError.new("#{key} must be a boolean value") unless boolean?(value) || value.nil?
176
175
  else
177
176
  validate_directive!(key, value)
@@ -179,6 +178,17 @@ module SecureHeaders
179
178
  end
180
179
  end
181
180
 
181
+ # Public: determine if merging +additions+ will cause a change to the
182
+ # actual value of the config.
183
+ #
184
+ # e.g. config = { script_src: %w(example.org google.com)} and
185
+ # additions = { script_src: %w(google.com)} then idempotent_additions? would return
186
+ # because google.com is already in the config.
187
+ def idempotent_additions?(config, additions)
188
+ return false if config == OPT_OUT
189
+ config.to_s == combine_policies(config, additions).to_s
190
+ end
191
+
182
192
  # Public: combine the values from two different configs.
183
193
  #
184
194
  # original - the main config
@@ -208,11 +218,11 @@ module SecureHeaders
208
218
  # when each hash contains a value for a given key.
209
219
  original.merge(additions) do |directive, lhs, rhs|
210
220
  if source_list?(directive)
211
- lhs | rhs
221
+ (lhs.to_a + rhs).uniq.compact
212
222
  else
213
223
  rhs
214
224
  end
215
- end
225
+ end.reject { |_, value| value.nil? || value == [] } # this mess prevents us from adding empty directives.
216
226
  end
217
227
 
218
228
  private
@@ -275,7 +285,8 @@ module SecureHeaders
275
285
  else
276
286
  UserAgent.parse(user_agent)
277
287
  end
278
- @report_only = !!@config[:report_only]
288
+ @report_only = @config[:report_only]
289
+ @preserve_schemes = @config[:preserve_schemes]
279
290
  @script_nonce = @config[:script_nonce]
280
291
  @style_nonce = @config[:style_nonce]
281
292
  end
@@ -345,9 +356,12 @@ module SecureHeaders
345
356
  source_list.reject! { |value| value == NONE } if source_list.length > 1
346
357
 
347
358
  # remove schemes and dedup source expressions
348
- source_list = strip_source_schemes(source_list) unless directive_name == REPORT_URI
359
+ unless directive_name == REPORT_URI || @preserve_schemes
360
+ source_list = strip_source_schemes(source_list)
361
+ end
349
362
  dedup_source_list(source_list).join(" ")
350
363
  end
364
+
351
365
  [symbol_to_hyphen_case(directive_name), value].join(" ")
352
366
  end
353
367
 
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "secure_headers"
4
- gem.version = "3.0.0.pre2"
4
+ gem.version = "3.0.0.pre3"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Security related headers all in one gem.'
@@ -23,6 +23,35 @@ module SecureHeaders
23
23
  end
24
24
 
25
25
  describe "#validate_config!" do
26
+ it "accepts all keys" do
27
+ # (pulled from README)
28
+ config = {
29
+ # "meta" values. these will shaped the header, but the values are not included in the header.
30
+ report_only: true, # default: false
31
+ preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
32
+
33
+ # directive values: these values will directly translate into source directives
34
+ default_src: %w(https: 'self'),
35
+ frame_src: %w('self' *.twimg.com itunes.apple.com),
36
+ connect_src: %w(wws:),
37
+ font_src: %w('self' data:),
38
+ img_src: %w(mycdn.com data:),
39
+ media_src: %w(utoob.com),
40
+ object_src: %w('self'),
41
+ script_src: %w('self'),
42
+ style_src: %w('unsafe-inline'),
43
+ base_uri: %w('self'),
44
+ child_src: %w('self'),
45
+ form_action: %w('self' github.com),
46
+ frame_ancestors: %w('none'),
47
+ plugin_types: %w(application/x-shockwave-flash),
48
+ block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
49
+ report_uri: %w(https://example.com/uri-directive)
50
+ }
51
+
52
+ CSP.validate_config!(config)
53
+ end
54
+
26
55
  it "requires a :default_src value" do
27
56
  expect do
28
57
  CSP.validate_config!(script_src: %('self'))
@@ -35,6 +64,12 @@ module SecureHeaders
35
64
  end.to raise_error(ContentSecurityPolicyConfigError)
36
65
  end
37
66
 
67
+ it "requires :preserve_schemes to be a truthy value" do
68
+ expect do
69
+ CSP.validate_config!(default_opts.merge(preserve_schemes: "steve"))
70
+ end.to raise_error(ContentSecurityPolicyConfigError)
71
+ end
72
+
38
73
  it "requires :block_all_mixed_content to be a boolean value" do
39
74
  expect do
40
75
  CSP.validate_config!(default_opts.merge(block_all_mixed_content: "steve"))
@@ -109,6 +144,19 @@ module SecureHeaders
109
144
  end
110
145
  end
111
146
 
147
+ describe "#idempotent_additions?" do
148
+ specify { expect(ContentSecurityPolicy.idempotent_additions?(OPT_OUT, script_src: %w(b.com))).to be false }
149
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(c.com))).to be false }
150
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: %w(b.com))).to be false }
151
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(a.com b.com c.com))).to be false }
152
+
153
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com))).to be true }
154
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com a.com))).to be true }
155
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w())).to be true }
156
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: [nil])).to be true }
157
+ specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: [nil])).to be true }
158
+ end
159
+
112
160
  describe "#value" do
113
161
  it "discards 'none' values if any other source expressions are present" do
114
162
  csp = ContentSecurityPolicy.new(default_opts.merge(frame_src: %w('self' 'none')))
@@ -138,6 +186,11 @@ module SecureHeaders
138
186
  expect(csp.value).to eq("default-src https:; report-uri https://example.org")
139
187
  end
140
188
 
189
+ it "does not remove schemes when :preserve_schemes is true" do
190
+ csp = ContentSecurityPolicy.new(default_src: %w(https://example.org), :preserve_schemes => true)
191
+ expect(csp.value).to eq("default-src https://example.org")
192
+ end
193
+
141
194
  it "removes nil from source lists" do
142
195
  csp = ContentSecurityPolicy.new(default_src: ["https://example.org", nil])
143
196
  expect(csp.value).to eq("default-src example.org")
data/upgrading-to-3-0.md CHANGED
@@ -11,6 +11,7 @@ Changes
11
11
  | `self`/`none` source expressions | could be `self` / `none` / `'self'` / `'none'` | Must be `'self'` or `'none'` |
12
12
  | `inline` / `eval` source expressions | could be `inline`, `eval`, `'unsafe-inline'`, or `'unsafe-eval'` | Must be `'unsafe-eval'` or `'unsafe-inline'` |
13
13
  | Per-action configuration | override [`def secure_header_options_for(header, options)`](https://github.com/twitter/secureheaders/commit/bb9ebc6c12a677aad29af8e0f08ffd1def56efec#diff-04c6e90faac2675aa89e2176d2eec7d8R111) | Use [named overrides](https://github.com/twitter/secureheaders#named-overrides) or [per-action helpers](https://github.com/twitter/secureheaders#per-action-configuration) |
14
+ | CSP/HPKP use `report_only` config that defaults to false | `enforce: false` | `report_only: false` |
14
15
 
15
16
  Migrating to 3.x from <= 2.x
16
17
  ==
@@ -18,6 +19,7 @@ Migrating to 3.x from <= 2.x
18
19
  1. Convert all headers except for CSP/HPKP using hashes to string values. The values are validated at runtime and will provide guidance on misconfigured headers.
19
20
  1. Convert all instances of `self`/`none`/`eval`/`inline` to the corresponding values in the above table.
20
21
  1. Convert all CSP space-delimited directives to an array of strings.
22
+ 1. Convert all `enforce: true|false` to `report_only: true|false`.
21
23
 
22
24
  Everything is terrible, why should I upgrade?
23
25
  ==
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secure_headers
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.pre2
4
+ version: 3.0.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Matatall
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-22 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake