inspec 2.1.59 → 2.1.67

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d57f969266c045b09307eba2c128be6fbb77e3f7
4
- data.tar.gz: 3feecd806c8a21b6f8ce3e37287e7905d0df86d9
3
+ metadata.gz: 3b433c23e0f104009667cb51b6b8ab4a81e01b63
4
+ data.tar.gz: 58c72645fab1bbf25e56338f522ba55f6ca51bbf
5
5
  SHA512:
6
- metadata.gz: cfd2b0a9cabfe3838b27d03c5dca5bd67bcca64c10e8bf48b628318a0fbe6cf118c98309f71ac0fce2fba65b10f06b28e821eeeb47b438b7f2559a00c6d29679
7
- data.tar.gz: 5d61ddf3ddb8126c490c1536c28c99b1a6b93615b78c6a7a17023b86133a2818b6e673cd5ff21400441c9c07a4c925b61fec730ac88318d2f4bee571fdf5c678
6
+ metadata.gz: ed147a0607f35c18186214bada157514130cd1000b31967b8c7f6ab861b7459e01ebfa9b57cb139d77d2aed80ba5d9e33d06eb5dad0c9f39f75dd6e01708f688
7
+ data.tar.gz: 3c2b47a3378ce52eaceac205a34d387ab9b301a752a7906decc8e29720876be0d13bbe17cc7fd414ae0ed0f88b6c533eebe22bacd089cbbd6624344c7d770a9c
data/CHANGELOG.md CHANGED
@@ -1,28 +1,47 @@
1
1
  # Change Log
2
2
  <!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
3
- <!-- latest_release 2.1.59 -->
4
- ## [v2.1.59](https://github.com/chef/inspec/tree/v2.1.59) (2018-04-26)
3
+ <!-- latest_release 2.1.67 -->
4
+ ## [v2.1.67](https://github.com/chef/inspec/tree/v2.1.67) (2018-05-03)
5
5
 
6
6
  #### Bug Fixes
7
- - Catch exceptions in control blocks and fail the control [#2987](https://github.com/chef/inspec/pull/2987) ([clintoncwolfe](https://github.com/clintoncwolfe))
7
+ - Add A2 support for profile compliance depends [#3014](https://github.com/chef/inspec/pull/3014) ([jquick](https://github.com/jquick))
8
8
  <!-- latest_release -->
9
9
 
10
- <!-- release_rollup since=2.1.54 -->
11
- ### Changes since 2.1.54 release
10
+ <!-- release_rollup since=2.1.59 -->
11
+ ### Changes since 2.1.59 release
12
+
13
+ #### New Features
14
+ - #2810 - Add check if aws s3 bucket is encrypted. [#2937](https://github.com/chef/inspec/pull/2937) ([UranusBytes](https://github.com/UranusBytes)) <!-- 2.1.64 -->
12
15
 
13
16
  #### Bug Fixes
14
- - Catch exceptions in control blocks and fail the control [#2987](https://github.com/chef/inspec/pull/2987) ([clintoncwolfe](https://github.com/clintoncwolfe)) <!-- 2.1.59 -->
17
+ - Add A2 support for profile compliance depends [#3014](https://github.com/chef/inspec/pull/3014) ([jquick](https://github.com/jquick)) <!-- 2.1.67 -->
18
+ - nginx_conf resource: Fix include paths with quotes [#2726](https://github.com/chef/inspec/pull/2726) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 2.1.63 -->
19
+
20
+ #### Enhancements
21
+ - Split inspec into a core gem. [#3008](https://github.com/chef/inspec/pull/3008) ([miah](https://github.com/miah)) <!-- 2.1.65 -->
22
+ - Refactors Terraform plan to break out steps [#2996](https://github.com/chef/inspec/pull/2996) ([dmccown](https://github.com/dmccown)) <!-- 2.1.61 -->
15
23
 
16
24
  #### Merged Pull Requests
17
- - os_env resource returns only user&#39;s environment variable on Windows [#2945](https://github.com/chef/inspec/pull/2945) ([omar-irizarry](https://github.com/omar-irizarry)) <!-- 2.1.58 -->
18
- - Fix case where res is nil in etc_group [#2984](https://github.com/chef/inspec/pull/2984) ([chris-rock](https://github.com/chris-rock)) <!-- 2.1.57 -->
19
- - Makes JSON resource enumerable, despite method_missing magic [#2910](https://github.com/chef/inspec/pull/2910) ([TheLonelyGhost](https://github.com/TheLonelyGhost)) <!-- 2.1.56 -->
25
+ - Add inspec-core gem to expeditor release [#3018](https://github.com/chef/inspec/pull/3018) ([jquick](https://github.com/jquick)) <!-- 2.1.66 -->
26
+ - cmp should recognise a string being a negative int [#3007](https://github.com/chef/inspec/pull/3007) ([james-stocks](https://github.com/james-stocks)) <!-- 2.1.62 -->
27
+ - Update Habitat plan [#3000](https://github.com/chef/inspec/pull/3000) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) <!-- 2.1.60 -->
28
+ <!-- release_rollup -->
29
+
30
+ <!-- latest_stable_release -->
31
+ ## [v2.1.59](https://github.com/chef/inspec/tree/v2.1.59) (2018-04-26)
20
32
 
21
33
  #### Enhancements
22
- - Update shadow#to_s to return @path instead of hardcoded `/etc/shadow` [#2978](https://github.com/chef/inspec/pull/2978) ([miah](https://github.com/miah)) <!-- 2.1.55 -->
23
- <!-- release_rollup -->
34
+ - Update shadow#to_s to return @path instead of hardcoded `/etc/shadow` [#2978](https://github.com/chef/inspec/pull/2978) ([miah](https://github.com/miah))
35
+
36
+ #### Bug Fixes
37
+ - Catch exceptions in control blocks and fail the control [#2987](https://github.com/chef/inspec/pull/2987) ([clintoncwolfe](https://github.com/clintoncwolfe))
24
38
 
39
+ #### Merged Pull Requests
40
+ - Makes JSON resource enumerable, despite method_missing magic [#2910](https://github.com/chef/inspec/pull/2910) ([TheLonelyGhost](https://github.com/TheLonelyGhost))
41
+ - Fix case where res is nil in etc_group [#2984](https://github.com/chef/inspec/pull/2984) ([chris-rock](https://github.com/chris-rock))
42
+ - os_env resource returns only user&#39;s environment variable on Windows [#2945](https://github.com/chef/inspec/pull/2945) ([omar-irizarry](https://github.com/omar-irizarry))
25
43
  <!-- latest_stable_release -->
44
+
26
45
  ## [v2.1.54](https://github.com/chef/inspec/tree/v2.1.54) (2018-04-19)
27
46
 
28
47
  #### New Features
@@ -43,7 +62,6 @@
43
62
 
44
63
  #### Merged Pull Requests
45
64
  - Add A2 support to the inspec-compliance toolset [#2963](https://github.com/chef/inspec/pull/2963) ([jquick](https://github.com/jquick))
46
- <!-- latest_stable_release -->
47
65
 
48
66
  ## [v2.1.43](https://github.com/chef/inspec/tree/v2.1.43) (2018-04-12)
49
67
 
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  source 'https://rubygems.org'
3
- gemspec
3
+ gemspec name: 'inspec'
4
4
 
5
5
  if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
6
6
  gem 'json', '~> 1.8'
data/README.md CHANGED
@@ -424,6 +424,12 @@ Use the rake task `bundle exec rake test:aws` to test the AWS resources against
424
424
 
425
425
  Please see [TESTING_AGAINST_AWS.md](./test/integration/aws/TESTING_AGAINST_AWS.md) for details on how to setup the needed AWS accounts to perform testing.
426
426
 
427
+ ### Azure Tests
428
+
429
+ Use the rake task `bundle exec rake test:azure` to test the Azure resources against an Azure account.
430
+
431
+ Please see [TESTING_AGAINST_AZURE.md](./test/integration/aws/TESTING_AGAINST_AZURE.md) for details on how to setup the needed Azure accounts to perform testing.
432
+
427
433
  ## License
428
434
 
429
435
  | | |
data/Rakefile CHANGED
@@ -2,13 +2,15 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  require 'bundler'
5
- require 'bundler/gem_tasks'
5
+ require 'bundler/gem_helper'
6
6
  require 'rake/testtask'
7
7
  require 'passgen'
8
8
  require 'train'
9
9
  require_relative 'tasks/maintainers'
10
10
  require_relative 'tasks/spdx'
11
11
 
12
+ Bundler::GemHelper.install_tasks name: 'inspec'
13
+
12
14
  def prompt(message)
13
15
  print(message)
14
16
  STDIN.gets.chomp
@@ -152,15 +154,30 @@ namespace :test do
152
154
  namespace :azure do
153
155
  # Specify the directory for the integration tests
154
156
  integration_dir = File.join(project_dir, 'test', 'integration', 'azure')
157
+ tf_vars_file = File.join(integration_dir, 'build', 'terraform.tfvars')
155
158
  attribute_file = File.join(integration_dir, '.attribute.yml')
156
159
 
157
160
  task :setup, :tf_workspace do |t, args|
158
161
  tf_workspace = args[:tf_workspace] || ENV['INSPEC_TERRAFORM_ENV']
159
162
  abort("You must either call the top-level test:azure task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace
160
- puts '----> Setup'
163
+
164
+ puts '----> Setup Terraform Workspace'
165
+
161
166
  sh("cd #{integration_dir}/build/ && terraform init -upgrade")
162
167
  sh("cd #{integration_dir}/build/ && terraform workspace new #{tf_workspace}")
163
168
 
169
+ Rake::Task["test:azure:vars"].execute
170
+ Rake::Task["test:azure:plan"].execute
171
+ Rake::Task["test:azure:apply"].execute
172
+ end
173
+
174
+ desc "Generate terraform.tfvars file"
175
+ task :vars do |t, args|
176
+
177
+ next if File.exist?(tf_vars_file)
178
+
179
+ puts '----> Generating Vars'
180
+
164
181
  # Generate Azure crendentials
165
182
  connection = Train.create('azure').connection
166
183
  creds = connection.options
@@ -172,23 +189,43 @@ namespace :test do
172
189
  # Use the first 4 characters of the storage account to create a suffix
173
190
  suffix = sa_name[0..3]
174
191
 
175
- # Create the plan that can be applied to Azure
176
- cmd = ""
177
- cmd += "cd #{integration_dir}/build/ && terraform plan -out inspec-azure.plan"
178
- cmd += " -var 'subscription_id=#{creds[:subscription_id]}' "
179
- cmd += " -var 'client_id=#{creds[:client_id]}' "
180
- cmd += " -var 'client_secret=#{creds[:client_secret]}' "
181
- cmd += " -var 'tenant_id=#{creds[:tenant_id]}' "
182
- cmd += " -var 'storage_account_name=#{sa_name}' "
183
- cmd += " -var 'admin_password=#{admin_password}' "
184
- cmd += " -var 'suffix=#{suffix}' "
185
- sh(cmd)
186
-
187
- # Apply the plan on Azure
188
- cmd = "cd #{integration_dir}/build/ && terraform apply inspec-azure.plan"
189
- sh(cmd)
190
-
191
- # Dump TF outputs to InSpec attributes file
192
+ content = <<~VARS
193
+ subscription_id = "#{creds[:subscription_id]}"
194
+ client_id = "#{creds[:client_id]}"
195
+ client_secret = "#{creds[:client_secret]}"
196
+ tenant_id = "#{creds[:tenant_id]}"
197
+ storage_account_name = "#{sa_name}"
198
+ admin_password = "#{admin_password}"
199
+ suffix = "#{suffix}"
200
+ VARS
201
+
202
+ content << "location = \"#{ENV['AZURE_LOCATION']}\"\n" if ENV['AZURE_LOCATION']
203
+
204
+ File.write(tf_vars_file, content)
205
+ end
206
+
207
+ desc "generate plan from state using terraform.tfvars file"
208
+ task :plan, [:tf_workspace] => [:vars] do |t, args|
209
+ tf_workspace = args[:tf_workspace] || ENV['INSPEC_TERRAFORM_ENV']
210
+ abort("You must set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace
211
+
212
+ puts '----> Generating Plan'
213
+
214
+ result = sh("cd #{integration_dir}/build/ && terraform workspace select #{tf_workspace}")
215
+
216
+ sh("cd #{integration_dir}/build/ && terraform plan -out inspec-azure.plan")
217
+ end
218
+
219
+ desc "apply terraform plan"
220
+ task :apply, [:tf_workspace] => [:plan] do |t, args|
221
+ tf_workspace = args[:tf_workspace] || ENV['INSPEC_TERRAFORM_ENV']
222
+ abort("You must set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace
223
+ puts '----> Applying Plan'
224
+
225
+ sh("cd #{integration_dir}/build/ && terraform workspace select #{tf_workspace}")
226
+
227
+ sh("cd #{integration_dir}/build/ && terraform apply inspec-azure.plan")
228
+
192
229
  Rake::Task["test:azure:dump_attrs"].execute
193
230
  end
194
231
 
@@ -197,7 +234,7 @@ namespace :test do
197
234
  raw_output = File.read(attribute_file)
198
235
  yaml_output = raw_output.gsub(" = ", " : ")
199
236
  File.open(attribute_file, "w") {|file| file.puts yaml_output}
200
- end
237
+ end
201
238
 
202
239
  task :run do
203
240
  puts '----> Run'
@@ -209,23 +246,11 @@ namespace :test do
209
246
  abort("You must either call the top-level test:azure task, or set the INSPEC_TERRAFORM_ENV variable.") unless tf_workspace
210
247
  puts '----> Cleanup'
211
248
 
212
- connection = Train.create('azure').connection
213
- creds = connection.options
214
-
215
- cmd = ""
216
- cmd += "cd #{integration_dir}/build/ && terraform destroy -force "
217
- cmd += " -var 'subscription_id=#{creds[:subscription_id]}' "
218
- cmd += " -var 'client_id=#{creds[:client_id]}' "
219
- cmd += " -var 'client_secret=#{creds[:client_secret]}' "
220
- cmd += " -var 'tenant_id=#{creds[:tenant_id]}' "
221
- cmd += " -var 'storage_account_name=dummy' "
222
- cmd += " -var 'admin_password=dummy' "
223
- cmd += " -var 'suffix=dummy' "
224
-
225
- sh(cmd)
249
+ sh("cd #{integration_dir}/build/ && terraform destroy -force ")
226
250
 
227
251
  sh("cd #{integration_dir}/build/ && terraform workspace select default")
228
252
  sh("cd #{integration_dir}/build && terraform workspace delete #{tf_workspace}")
253
+ File.delete(tf_vars_file)
229
254
  end
230
255
  end
231
256
 
@@ -132,3 +132,9 @@ Note: This resource does not detect insecure object ACLs.
132
132
  The `have_access_logging_enabled` matcher tests if access logging is enabled for the s3 bucket.
133
133
 
134
134
  it { should have_access_logging_enabled }
135
+
136
+ ### have\_default\_encryption\_enabled
137
+
138
+ The `have_default_encryption_enabled` matcher tests if default encryption is enabled for the s3 bucket.
139
+
140
+ it { should have_default_encryption_enabled }
@@ -20,7 +20,7 @@ A `filesystem` resource block declares tests for disk space in a partition:
20
20
  where
21
21
 
22
22
  * `filesystem('/')` states that the resource will look at the root (/) partition.
23
- * `size` is measured in megabytes (MB).
23
+ * `size` is measured in kilobytes (KB).
24
24
 
25
25
  <br>
26
26
 
@@ -28,7 +28,7 @@ where
28
28
 
29
29
  The following examples show how to use this InSpec audit resource.
30
30
 
31
- ### Test if the root partition is greater than 32000 MB
31
+ ### Test if the root partition is greater than 32000 KB
32
32
 
33
33
  describe filesystem('/') do
34
34
  its('size') { should be >= 32000 }
@@ -62,7 +62,8 @@ module Compliance
62
62
  config['token'] = Compliance::API.get_token(config)
63
63
 
64
64
  # Needed for automate2 post request
65
- config['profile'] = Compliance::API.profile_split(profile)
65
+ profile_stub = profile || target[:compliance]
66
+ config['profile'] = Compliance::API.profile_split(profile_stub)
66
67
 
67
68
  new(profile_fetch_url, config)
68
69
  rescue URI::Error => _e
data/lib/fetchers/url.rb CHANGED
@@ -157,6 +157,12 @@ module Fetchers
157
157
  opts = http_opts
158
158
  opts[:use_ssl] = uri.scheme == 'https'
159
159
 
160
+ if @insecure
161
+ opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
162
+ else
163
+ opts[:verify_mode] = OpenSSL::SSL::VERIFY_PEER
164
+ end
165
+
160
166
  req = Net::HTTP::Post.new(uri)
161
167
  opts.each do |key, value|
162
168
  req.add_field(key, value)
@@ -78,13 +78,16 @@ end
78
78
  require 'utils/filter'
79
79
 
80
80
  # AWS resources are included via their own file.
81
- require 'resource_support/aws'
81
+ require 'resource_support/aws' if Gem.loaded_specs.key?('aws-sdk')
82
+
83
+ if Gem.loaded_specs.key?('azure_mgmt_resources')
84
+ require 'resources/azure/azure_backend.rb'
85
+ require 'resources/azure/azure_generic_resource.rb'
86
+ require 'resources/azure/azure_resource_group.rb'
87
+ require 'resources/azure/azure_virtual_machine.rb'
88
+ require 'resources/azure/azure_virtual_machine_data_disk.rb'
89
+ end
82
90
 
83
- require 'resources/azure/azure_backend.rb'
84
- require 'resources/azure/azure_generic_resource.rb'
85
- require 'resources/azure/azure_resource_group.rb'
86
- require 'resources/azure/azure_virtual_machine.rb'
87
- require 'resources/azure/azure_virtual_machine_data_disk.rb'
88
91
  require 'resources/aide_conf'
89
92
  require 'resources/apache'
90
93
  require 'resources/apache_conf'
@@ -4,5 +4,5 @@
4
4
  # author: Christoph Hartmann
5
5
 
6
6
  module Inspec
7
- VERSION = '2.1.59'
7
+ VERSION = '2.1.67'
8
8
  end
@@ -211,7 +211,7 @@ end
211
211
  RSpec::Matchers.define :cmp do |first_expected| # rubocop:disable Metrics/BlockLength
212
212
 
213
213
  def integer?(value)
214
- !(value =~ /\A0+\Z|\A[1-9]\d*\Z/).nil?
214
+ !(value =~ /\A-?0+\Z|\A-?[1-9]\d*\Z/).nil?
215
215
  end
216
216
 
217
217
  def float?(value)
@@ -10,7 +10,7 @@ class AwsS3Bucket < Inspec.resource(1)
10
10
  supports platform: 'aws'
11
11
 
12
12
  include AwsSingularResourceMixin
13
- attr_reader :bucket_name, :has_access_logging_enabled, :region
13
+ attr_reader :bucket_name, :has_default_encryption_enabled, :has_access_logging_enabled, :region
14
14
 
15
15
  def to_s
16
16
  "S3 Bucket #{@bucket_name}"
@@ -35,8 +35,13 @@ class AwsS3Bucket < Inspec.resource(1)
35
35
  bucket_policy.any? { |s| s.effect == 'Allow' && s.principal == '*' }
36
36
  end
37
37
 
38
+ def has_default_encryption_enabled?
39
+ return false unless @exists
40
+ @has_default_encryption_enabled ||= fetch_bucket_encryption_configuration
41
+ end
42
+
38
43
  def has_access_logging_enabled?
39
- return unless @exists
44
+ return false unless @exists
40
45
  catch_aws_errors do
41
46
  @has_access_logging_enabled ||= !BackendFactory.create(inspec_runner).get_bucket_logging(bucket: bucket_name).logging_enabled.nil?
42
47
  end
@@ -89,6 +94,19 @@ class AwsS3Bucket < Inspec.resource(1)
89
94
  end
90
95
  end
91
96
 
97
+ def fetch_bucket_encryption_configuration
98
+ @has_default_encryption_enabled ||= catch_aws_errors do
99
+ begin
100
+ !BackendFactory.create(inspec_runner)
101
+ .get_bucket_encryption(bucket: bucket_name)
102
+ .server_side_encryption_configuration
103
+ .nil?
104
+ rescue Aws::S3::Errors::ServerSideEncryptionConfigurationNotFoundError
105
+ false
106
+ end
107
+ end
108
+ end
109
+
92
110
  # Uses the SDK API to really talk to AWS
93
111
  class Backend
94
112
  class AwsClientApi < AwsBackendBase
@@ -110,6 +128,10 @@ class AwsS3Bucket < Inspec.resource(1)
110
128
  def get_bucket_logging(query)
111
129
  aws_service_client.get_bucket_logging(query)
112
130
  end
131
+
132
+ def get_bucket_encryption(query)
133
+ aws_service_client.get_bucket_encryption(query)
134
+ end
113
135
  end
114
136
  end
115
137
  end
@@ -17,17 +17,20 @@ module FindFiles
17
17
 
18
18
  # ignores errors
19
19
  def find_files(path, opts = {})
20
- find_files_or_error(path, opts) || []
20
+ find_files_or_warn(path, opts) || []
21
21
  end
22
22
 
23
- def find_files_or_error(path, opts = {})
23
+ def find_files_or_warn(path, opts = {})
24
24
  depth = opts[:depth]
25
25
  type = TYPES[opts[:type].to_sym] if opts[:type]
26
26
 
27
- cmd = "sh -c \'find #{path}"
27
+ # If `path` contains a `'` we must modify how we quote the `sh -c` argument
28
+ quote = path.include?("'") ? '"' : '\''
29
+
30
+ cmd = "sh -c #{quote}find #{path}"
28
31
  cmd += " -type #{type}" unless type.nil?
29
32
  cmd += " -maxdepth #{depth.to_i}" if depth.to_i > 0
30
- cmd += "\'"
33
+ cmd += quote
31
34
 
32
35
  result = inspec.command(cmd)
33
36
  exit_status = result.exit_status
@@ -33,12 +33,32 @@ class NginxParser < Parslet::Parser
33
33
  standard_identifier | quoted_identifier
34
34
  }
35
35
 
36
- rule(:value) {
37
- ((match('[#;{]').absent? >> any) >> (
36
+ rule(:standard_value) {
37
+ ((match(/[#;{'"]/).absent? >> any) >> (
38
38
  str('\\') >> any | match('[#;{]|\s').absent? >> any
39
39
  ).repeat).as(:value) >> space.repeat
40
40
  }
41
41
 
42
+ rule(:single_quoted_value) {
43
+ str("'") >> (
44
+ str('\\') >> any | str("'").absent? >> any
45
+ ).repeat.as(:value) >> str("'") >> space.repeat
46
+ }
47
+
48
+ rule(:double_quoted_value) {
49
+ str('"') >> (
50
+ str('\\') >> any | str('"').absent? >> any
51
+ ).repeat.as(:value) >> str('"') >> space.repeat
52
+ }
53
+
54
+ rule(:quoted_value) {
55
+ single_quoted_value | double_quoted_value
56
+ }
57
+
58
+ rule(:value) {
59
+ standard_value | quoted_value
60
+ }
61
+
42
62
  rule(:values) {
43
63
  value.repeat >> space.maybe
44
64
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.59
4
+ version: 2.1.67
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dominik Richter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train