inspec 1.31.0 → 1.45.9

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.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +2599 -1
  4. data/Gemfile +0 -1
  5. data/README.md +24 -34
  6. data/Rakefile +0 -31
  7. data/docs/dsl_inspec.md +10 -0
  8. data/docs/matchers.md +29 -0
  9. data/docs/plugin_kitchen_inspec.md +18 -24
  10. data/docs/profiles.md +101 -81
  11. data/docs/resources/aide_conf.md.erb +71 -0
  12. data/docs/resources/apache_conf.md.erb +19 -33
  13. data/docs/resources/apt.md.erb +22 -36
  14. data/docs/resources/audit_policy.md.erb +9 -24
  15. data/docs/resources/auditd.md.erb +78 -0
  16. data/docs/resources/auditd_conf.md.erb +20 -34
  17. data/docs/resources/auditd_rules.md.erb +8 -24
  18. data/docs/resources/bash.md.erb +4 -26
  19. data/docs/resources/bond.md.erb +25 -40
  20. data/docs/resources/bridge.md.erb +5 -25
  21. data/docs/resources/bsd_service.md.erb +5 -25
  22. data/docs/resources/command.md.erb +35 -50
  23. data/docs/resources/cpan.md.erb +62 -0
  24. data/docs/resources/cran.md.erb +54 -0
  25. data/docs/resources/crontab.md.erb +9 -23
  26. data/docs/resources/csv.md.erb +12 -27
  27. data/docs/resources/dh_params.md +1 -0
  28. data/docs/resources/directory.md.erb +5 -25
  29. data/docs/resources/docker.md.erb +61 -58
  30. data/docs/resources/docker_container.md.erb +23 -19
  31. data/docs/resources/docker_image.md.erb +20 -16
  32. data/docs/resources/elasticsearch.md.erb +245 -0
  33. data/docs/resources/etc_fstab.md.erb +120 -0
  34. data/docs/resources/etc_group.md.erb +29 -45
  35. data/docs/resources/etc_hosts.md.erb +68 -0
  36. data/docs/resources/etc_hosts_allow.md.erb +68 -0
  37. data/docs/resources/etc_hosts_deny.md.erb +68 -0
  38. data/docs/resources/file.md.erb +227 -216
  39. data/docs/resources/firewalld.md.erb +104 -0
  40. data/docs/resources/gem.md.erb +21 -35
  41. data/docs/resources/group.md.erb +16 -30
  42. data/docs/resources/grub_conf.md.erb +9 -24
  43. data/docs/resources/host.md.erb +32 -49
  44. data/docs/resources/http.md.erb +38 -44
  45. data/docs/resources/iis_app.md.erb +25 -35
  46. data/docs/resources/iis_site.md.erb +26 -40
  47. data/docs/resources/inetd_conf.md.erb +27 -42
  48. data/docs/resources/ini.md.erb +9 -23
  49. data/docs/resources/interface.md.erb +5 -25
  50. data/docs/resources/iptables.md.erb +15 -29
  51. data/docs/resources/json.md.erb +12 -27
  52. data/docs/resources/kernel_module.md.erb +47 -61
  53. data/docs/resources/kernel_parameter.md.erb +15 -29
  54. data/docs/resources/key_rsa.md.erb +3 -0
  55. data/docs/resources/launchd_service.md.erb +5 -25
  56. data/docs/resources/limits_conf.md.erb +15 -29
  57. data/docs/resources/login_def.md.erb +15 -30
  58. data/docs/resources/mount.md.erb +18 -33
  59. data/docs/resources/mssql_session.md.erb +9 -12
  60. data/docs/resources/mysql_conf.md.erb +28 -32
  61. data/docs/resources/mysql_session.md.erb +15 -29
  62. data/docs/resources/nginx.md.erb +78 -0
  63. data/docs/resources/nginx_conf.md.erb +127 -0
  64. data/docs/resources/npm.md.erb +19 -35
  65. data/docs/resources/ntp_conf.md.erb +20 -37
  66. data/docs/resources/oneget.md.erb +15 -30
  67. data/docs/resources/oracledb_session.md.erb +9 -11
  68. data/docs/resources/os.md.erb +29 -43
  69. data/docs/resources/os_env.md.erb +23 -44
  70. data/docs/resources/package.md.erb +34 -36
  71. data/docs/resources/parse_config.md.erb +5 -25
  72. data/docs/resources/parse_config_file.md.erb +31 -43
  73. data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +24 -39
  74. data/docs/resources/pip.md.erb +20 -35
  75. data/docs/resources/port.md.erb +43 -57
  76. data/docs/resources/postgres_conf.md.erb +17 -31
  77. data/docs/resources/postgres_hba_conf.md.erb +26 -38
  78. data/docs/resources/postgres_ident_conf.md.erb +25 -37
  79. data/docs/resources/postgres_session.md.erb +15 -29
  80. data/docs/resources/powershell.md.erb +27 -42
  81. data/docs/resources/processes.md.erb +17 -33
  82. data/docs/resources/rabbitmq_config.md.erb +9 -24
  83. data/docs/resources/registry_key.md.erb +27 -42
  84. data/docs/resources/runit_service.md.erb +5 -25
  85. data/docs/resources/security_policy.md.erb +12 -27
  86. data/docs/resources/service.md.erb +27 -42
  87. data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +41 -47
  88. data/docs/resources/ssh_config.md.erb +19 -34
  89. data/docs/resources/sshd_config.md.erb +19 -34
  90. data/docs/resources/ssl.md.erb +39 -54
  91. data/docs/resources/sys_info.md.erb +12 -26
  92. data/docs/resources/systemd_service.md.erb +5 -25
  93. data/docs/resources/sysv_service.md.erb +5 -25
  94. data/docs/resources/upstart_service.md.erb +5 -25
  95. data/docs/resources/user.md.erb +29 -44
  96. data/docs/resources/users.md.erb +12 -26
  97. data/docs/resources/vbscript.md.erb +9 -24
  98. data/docs/resources/virtualization.md.erb +8 -23
  99. data/docs/resources/windows_feature.md.erb +15 -30
  100. data/docs/resources/windows_hotfix.md.erb +50 -0
  101. data/docs/resources/windows_task.md.erb +12 -26
  102. data/docs/resources/wmi.md.erb +9 -24
  103. data/docs/resources/x509_certificate.md.erb +4 -0
  104. data/docs/resources/xinetd_conf.md.erb +65 -80
  105. data/docs/resources/xml.md.erb +61 -0
  106. data/docs/resources/yaml.md.erb +12 -27
  107. data/docs/resources/yum.md.erb +37 -51
  108. data/docs/resources/zfs_dataset.md.erb +15 -26
  109. data/docs/resources/zfs_pool.md.erb +9 -20
  110. data/docs/ruby_usage.md +0 -1
  111. data/examples/meta-profile/README.md +1 -1
  112. data/examples/profile-sensitive/README.md +29 -0
  113. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
  114. data/examples/profile-sensitive/controls/sensitive.rb +9 -0
  115. data/examples/profile-sensitive/inspec.yml +8 -0
  116. data/inspec.gemspec +3 -3
  117. data/lib/bundles/inspec-artifact/cli.rb +5 -5
  118. data/lib/bundles/inspec-compliance/README.md +24 -22
  119. data/lib/bundles/inspec-compliance/api/login.rb +152 -0
  120. data/lib/bundles/inspec-compliance/api.rb +46 -16
  121. data/lib/bundles/inspec-compliance/cli.rb +58 -165
  122. data/lib/bundles/inspec-compliance/target.rb +2 -3
  123. data/lib/bundles/inspec-habitat/cli.rb +7 -2
  124. data/lib/bundles/inspec-habitat/profile.rb +44 -20
  125. data/lib/bundles/inspec-init/templates/profile/README.md +1 -1
  126. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +1 -1
  127. data/lib/bundles/inspec-supermarket/api.rb +1 -1
  128. data/lib/inspec/backend.rb +8 -0
  129. data/lib/inspec/cli.rb +1 -1
  130. data/lib/inspec/control_eval_context.rb +16 -6
  131. data/lib/inspec/dependencies/requirement.rb +22 -8
  132. data/lib/inspec/dependencies/resolver.rb +1 -1
  133. data/lib/inspec/exceptions.rb +4 -0
  134. data/lib/inspec/file_provider.rb +38 -9
  135. data/lib/inspec/metadata.rb +17 -3
  136. data/lib/inspec/objects/attribute.rb +16 -7
  137. data/lib/inspec/objects/control.rb +10 -2
  138. data/lib/inspec/plugins/resource.rb +34 -5
  139. data/lib/inspec/profile.rb +10 -1
  140. data/lib/inspec/profile_context.rb +3 -1
  141. data/lib/inspec/resource.rb +17 -5
  142. data/lib/inspec/rspec_json_formatter.rb +48 -14
  143. data/lib/inspec/rule.rb +4 -0
  144. data/lib/inspec/runner.rb +72 -30
  145. data/lib/inspec/shell.rb +24 -19
  146. data/lib/inspec/version.rb +1 -1
  147. data/lib/matchers/matchers.rb +40 -0
  148. data/lib/resources/aide_conf.rb +162 -0
  149. data/lib/resources/auditd.rb +231 -0
  150. data/lib/resources/auditd_rules.rb +3 -1
  151. data/lib/resources/command.rb +1 -1
  152. data/lib/resources/cpan.rb +60 -0
  153. data/lib/resources/cran.rb +66 -0
  154. data/lib/resources/docker.rb +8 -1
  155. data/lib/resources/docker_container.rb +19 -2
  156. data/lib/resources/elasticsearch.rb +172 -0
  157. data/lib/resources/etc_fstab.rb +102 -0
  158. data/lib/resources/etc_group.rb +1 -1
  159. data/lib/resources/etc_hosts.rb +81 -0
  160. data/lib/resources/etc_hosts_allow_deny.rb +122 -0
  161. data/lib/resources/file.rb +87 -10
  162. data/lib/resources/firewalld.rb +144 -0
  163. data/lib/resources/groups.rb +0 -1
  164. data/lib/resources/host.rb +30 -15
  165. data/lib/resources/http.rb +178 -22
  166. data/lib/resources/mssql_session.rb +3 -3
  167. data/lib/resources/mysql_conf.rb +10 -0
  168. data/lib/resources/mysql_session.rb +1 -1
  169. data/lib/resources/nginx.rb +97 -0
  170. data/lib/resources/nginx_conf.rb +134 -1
  171. data/lib/resources/oracledb_session.rb +9 -8
  172. data/lib/resources/os_env.rb +7 -4
  173. data/lib/resources/package.rb +14 -2
  174. data/lib/resources/packages.rb +1 -1
  175. data/lib/resources/pip.rb +28 -20
  176. data/lib/resources/port.rb +251 -3
  177. data/lib/resources/postgres.rb +1 -1
  178. data/lib/resources/postgres_session.rb +1 -1
  179. data/lib/resources/processes.rb +106 -20
  180. data/lib/resources/registry_key.rb +11 -2
  181. data/lib/resources/service.rb +5 -24
  182. data/lib/resources/ssh_conf.rb +1 -1
  183. data/lib/resources/ssl.rb +4 -3
  184. data/lib/resources/toml.rb +2 -2
  185. data/lib/resources/windows_hotfix.rb +35 -0
  186. data/lib/resources/xinetd.rb +4 -6
  187. data/lib/resources/xml.rb +27 -0
  188. data/lib/source_readers/inspec.rb +3 -3
  189. data/lib/utils/find_files.rb +2 -1
  190. data/lib/utils/nginx_parser.rb +10 -1
  191. data/lib/utils/object_traversal.rb +35 -10
  192. data/lib/utils/parser.rb +21 -3
  193. metadata +48 -18
  194. data/docs/cli.md +0 -392
@@ -18,100 +18,90 @@ module Compliance
18
18
  namespace
19
19
  end
20
20
 
21
- desc "login SERVER --insecure --user='USER' --token='TOKEN'", 'Log in to a Chef Compliance SERVER'
21
+ desc "login https://SERVER --insecure --user='USER' --ent='ENTERPRISE' --token='TOKEN'", 'Log in to a Chef Compliance/Chef Automate SERVER'
22
+ long_desc <<-LONGDESC
23
+ `login` allows you to use InSpec with Chef Automate or a Chef Compliance Server
24
+
25
+ You need to a token for communication. More information about token retrieval
26
+ is available at:
27
+ https://docs.chef.io/api_automate.html#authentication-methods
28
+ https://docs.chef.io/api_compliance.html#obtaining-an-api-token
29
+ LONGDESC
22
30
  option :insecure, aliases: :k, type: :boolean,
23
31
  desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
24
32
  option :user, type: :string, required: false,
25
- desc: 'Chef Compliance Username'
33
+ desc: 'Username'
26
34
  option :password, type: :string, required: false,
27
- desc: 'Chef Compliance Password'
28
- option :apipath, type: :string, default: '/api',
29
- desc: 'Set the path to the API, defaults to /api'
35
+ desc: 'Password (Chef Compliance Only)'
30
36
  option :token, type: :string, required: false,
31
- desc: 'Chef Compliance access token'
37
+ desc: 'Access token'
32
38
  option :refresh_token, type: :string, required: false,
33
- desc: 'Chef Compliance refresh token'
34
- def login(server) # rubocop:disable Metrics/AbcSize
35
- # show warning if the Compliance Server does not support
36
-
39
+ desc: 'Chef Compliance refresh token (Chef Compliance Only)'
40
+ option :dctoken, type: :string, required: false,
41
+ desc: 'Data Collector token (Chef Automate Only)'
42
+ option :ent, type: :string, required: false,
43
+ desc: 'Enterprise for Chef Automate reporting (Chef Automate Only)'
44
+ def login(server)
37
45
  options['server'] = server
38
- url = options['server'] + options['apipath']
39
-
40
- if !options['user'].nil? && !options['password'].nil?
41
- # username / password
42
- _success, msg = login_username_password(url, options['user'], options['password'], options['insecure'])
43
- elsif !options['user'].nil? && !options['token'].nil?
44
- # access token
45
- _success, msg = store_access_token(url, options['user'], options['token'], options['insecure'])
46
- elsif !options['refresh_token'].nil? && !options['user'].nil?
47
- # refresh token
48
- _success, msg = store_refresh_token(url, options['refresh_token'], true, options['user'], options['insecure'])
49
- # TODO: we should login with the refreshtoken here
50
- elsif !options['refresh_token'].nil?
51
- _success, msg = login_refreshtoken(url, options)
52
- else
53
- puts 'Please run `inspec compliance login SERVER` with options --token or --refresh_token, --user, and --insecure or --not-insecure'
54
- exit 1
55
- end
56
-
57
- puts '', msg
46
+ Compliance::API.login(options)
58
47
  end
59
48
 
60
- desc "login_automate SERVER --insecure --user='USER' --ent='ENT' --usertoken='TOKEN'", 'Log in to an Automate SERVER'
49
+ desc "login_automate https://SERVER --insecure --user='USER' --ent='ENTERPRISE' --usertoken='TOKEN'", 'Log in to a Chef Automate SERVER (DEPRECATED: Please use `login`)'
61
50
  long_desc <<-LONGDESC
62
- `login_automate` allows you to use InSpec with Chef Automate
51
+ This commmand is deprecated and will be removed, please use `--login`.
52
+
53
+ `login_automate` allows you to use InSpec with Chef Automate.
63
54
 
64
- You need to a user-token for communication with Chef Automate. More
65
- information about token retrieval for Automate is available at:
66
- https://docs.chef.io/api_delivery.html
55
+ You need to a token for communication. More information about token retrieval
56
+ is available at:
57
+ https://docs.chef.io/api_automate.html#authentication-methods
58
+ https://docs.chef.io/api_compliance.html#obtaining-an-api-token
67
59
  LONGDESC
68
- option :dctoken, type: :string,
69
- desc: 'Data Collector token'
70
- option :usertoken, type: :string,
71
- desc: 'Automate user token'
72
- option :user, type: :string,
73
- desc: 'Automate username'
74
- option :ent, type: :string,
75
- desc: 'Enterprise for Chef Automate reporting'
76
60
  option :insecure, aliases: :k, type: :boolean,
77
61
  desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
78
- def login_automate(server) # rubocop:disable Metrics/AbcSize
62
+ option :user, type: :string, required: true,
63
+ desc: 'Username'
64
+ option :usertoken, type: :string, required: false,
65
+ desc: 'Access token (DEPRECATED: Please use `--token`)'
66
+ option :token, type: :string, required: false,
67
+ desc: 'Access token'
68
+ option :dctoken, type: :string, required: false,
69
+ desc: 'Data Collector token'
70
+ option :ent, type: :string, required: true,
71
+ desc: 'Enterprise for Chef Automate reporting'
72
+ def login_automate(server)
73
+ warn '[DEPRECATION] `inspec compliance login_automate` is deprecated. Please use `inspec compliance login`'
79
74
  options['server'] = server
80
- url = options['server'] + '/compliance'
81
75
 
82
- if url && !options['user'].nil? && !options['ent'].nil? && (!options['dctoken'].nil? || !options['usertoken'].nil?)
83
- msg = login_automate_config(url, options['user'], options['dctoken'], options['usertoken'], options['ent'], options['insecure'])
84
- puts '', msg
85
- exit 0
86
- end
76
+ options['token'] = options['usertoken'] if options['usertoken']
87
77
 
88
- # parameters are missing if we reach here
89
- puts 'Please specify an user using `--user \'USER\'`' if options['user'].nil?
90
- puts 'Please specify an enterprise using `--ent \'cd\'`' if options['ent'].nil?
91
- puts 'Please specify a token using `--usertoken=\'AUTOMATE_TOKEN\'`' if options['usertoken'].nil? && options['dctoken'].nil?
92
- exit 1
78
+ Compliance::API.login(options)
93
79
  end
94
80
 
95
81
  desc 'profiles', 'list all available profiles in Chef Compliance'
96
-
82
+ option :owner, type: :string, required: false,
83
+ desc: 'owner whose profiles to list'
97
84
  def profiles
98
85
  config = Compliance::Configuration.new
99
86
  return if !loggedin(config)
100
87
 
88
+ # set owner to config
89
+ config['owner'] = options['owner'] || config['user']
90
+
101
91
  msg, profiles = Compliance::API.profiles(config)
102
92
  profiles.sort_by! { |hsh| hsh['title'] }
103
93
  if !profiles.empty?
104
94
  # iterate over profiles
105
95
  headline('Available profiles:')
106
96
  profiles.each { |profile|
107
- li("#{profile['title']} #{mark_text(profile['owner_id'] + '/' + profile['name'])}")
97
+ li("#{profile['title']} v#{profile['version']} (#{mark_text(profile['owner_id'] + '/' + profile['name'])})")
108
98
  }
109
99
  else
110
100
  puts msg, 'Could not find any profiles'
111
101
  exit 1
112
102
  end
113
103
  rescue Compliance::ServerConfigurationMissing
114
- puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
104
+ STDERR.puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
115
105
  exit 1
116
106
  end
117
107
 
@@ -159,11 +149,16 @@ module Compliance
159
149
 
160
150
  desc 'upload PATH', 'uploads a local profile to Chef Compliance'
161
151
  option :overwrite, type: :boolean, default: false,
162
- desc: 'Overwrite existing profile on Chef Compliance.'
152
+ desc: 'Overwrite existing profile on Server.'
153
+ option :owner, type: :string, required: false,
154
+ desc: 'Owner that should own the profile'
163
155
  def upload(path) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, PerceivedComplexity, Metrics/CyclomaticComplexity
164
156
  config = Compliance::Configuration.new
165
157
  return if !loggedin(config)
166
158
 
159
+ # set owner to config
160
+ config['owner'] = options['owner'] || config['user']
161
+
167
162
  unless File.exist?(path)
168
163
  puts "Directory #{path} does not exist."
169
164
  exit 1
@@ -195,14 +190,12 @@ module Compliance
195
190
  error.call('Please login via `inspec compliance login`')
196
191
  end
197
192
 
198
- # owner
199
- owner = config['user']
200
193
  # read profile name from inspec.yml
201
194
  profile_name = profile.params[:name]
202
195
 
203
196
  # check that the profile is not uploaded already,
204
197
  # confirm upload to the user (overwrite with --force)
205
- if Compliance::API.exist?(config, "#{owner}/#{profile_name}") && !options['overwrite']
198
+ if Compliance::API.exist?(config, "#{config['owner']}/#{profile_name}") && !options['overwrite']
206
199
  error.call('Profile exists on the server, use --overwrite')
207
200
  end
208
201
 
@@ -221,12 +214,12 @@ module Compliance
221
214
  archive_path = path
222
215
  end
223
216
 
224
- puts "Start upload to #{owner}/#{profile_name}"
217
+ puts "Start upload to #{config['owner']}/#{profile_name}"
225
218
  pname = ERB::Util.url_encode(profile_name)
226
219
 
227
220
  Compliance::API.is_automate_server?(config) ? upload_msg = 'Uploading to Chef Automate' : upload_msg = 'Uploading to Chef Compliance'
228
221
  puts upload_msg
229
- success, msg = Compliance::API.upload(config, owner, pname, archive_path)
222
+ success, msg = Compliance::API.upload(config, config['owner'], pname, archive_path)
230
223
 
231
224
  if success
232
225
  puts 'Successfully uploaded profile'
@@ -272,109 +265,9 @@ module Compliance
272
265
 
273
266
  private
274
267
 
275
- def login_automate_config(url, user, dctoken, usertoken, ent, insecure) # rubocop:disable Metrics/ParameterLists
276
- config = Compliance::Configuration.new
277
- config.clean
278
- config['user'] = user
279
- config['server'] = url
280
- config['automate'] = {}
281
- config['automate']['ent'] = ent
282
- config['server_type'] = 'automate'
283
- config['insecure'] = insecure
284
-
285
- # determine token method being used
286
- if !dctoken.nil?
287
- config['token'] = dctoken
288
- token_type = 'dctoken'
289
- token_msg = 'data collector token'
290
- else
291
- config['token'] = usertoken
292
- token_type = 'usertoken'
293
- token_msg = 'automate user token'
294
- end
295
- config['automate']['token_type'] = token_type
296
- config['version'] = Compliance::API.version(config)
297
- config.store
298
- msg = "Stored configuration for Chef Automate: '#{url}' with user: '#{user}', ent: '#{ent}' and your #{token_msg}"
299
- msg
300
- end
301
-
302
- def login_refreshtoken(url, options)
303
- success, msg, _access_token = Compliance::API.get_token_via_refresh_token(url, options['refresh_token'], options['insecure'])
304
- if success
305
- config = Compliance::Configuration.new
306
- config.clean
307
- config['server'] = url
308
- config['insecure'] = options['insecure']
309
- config['server_type'] = 'compliance'
310
- config['version'] = Compliance::API.version(config)
311
- config.store
312
- end
313
-
314
- [success, msg]
315
- end
316
-
317
- def login_username_password(url, username, password, insecure)
318
- config = Compliance::Configuration.new
319
- config.clean
320
- success, msg, api_token = Compliance::API.get_token_via_password(url, username, password, insecure)
321
- if success
322
- config['server'] = url
323
- config['user'] = username
324
- config['token'] = api_token
325
- config['insecure'] = insecure
326
- config['server_type'] = 'compliance'
327
- config['version'] = Compliance::API.version(config)
328
- config.store
329
- success = true
330
- end
331
- [success, msg]
332
- end
333
-
334
- # saves a user access token (limited time)
335
- def store_access_token(url, user, token, insecure)
336
- config = Compliance::Configuration.new
337
- config.clean
338
- config['server'] = url
339
- config['insecure'] = insecure
340
- config['user'] = user
341
- config['token'] = token
342
- config['server_type'] = 'compliance'
343
- config['version'] = Compliance::API.version(config)
344
- config.store
345
-
346
- [true, 'API access token stored']
347
- end
348
-
349
- # saves a refresh token supplied by the user
350
- def store_refresh_token(url, refresh_token, verify, user, insecure)
351
- config = Compliance::Configuration.new
352
- config.clean
353
- config['server'] = url
354
- config['refresh_token'] = refresh_token
355
- config['user'] = user
356
- config['insecure'] = insecure
357
- config['server_type'] = 'compliance'
358
- config['version'] = Compliance::API.version(config)
359
-
360
- if !verify
361
- config.store
362
- success = true
363
- msg = 'API refresh token stored'
364
- else
365
- success, msg, _access_token= Compliance::API.get_token_via_refresh_token(url, refresh_token, insecure)
366
- if success
367
- config.store
368
- msg = 'API access token verified'
369
- end
370
- end
371
-
372
- [success, msg]
373
- end
374
-
375
268
  def loggedin(config)
376
269
  serverknown = !config['server'].nil?
377
- puts 'You need to login first with `inspec compliance login` or `inspec compliance login_automate`' if !serverknown
270
+ puts 'You need to login first with `inspec compliance login`' if !serverknown
378
271
  serverknown
379
272
  end
380
273
  end
@@ -32,7 +32,7 @@ module Compliance
32
32
  if config['token'].nil? && config['refresh_token'].nil?
33
33
  if config['server_type'] == 'automate'
34
34
  server = 'automate'
35
- msg = 'inspec compliance login_automate https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --usertoken USERTOKEN'
35
+ msg = 'inspec compliance login https://your_automate_server --user USER --ent ENT --dctoken DCTOKEN or --token USERTOKEN'
36
36
  else
37
37
  server = 'compliance'
38
38
  msg = "inspec compliance login https://your_compliance_server --user admin --insecure --token 'PASTE TOKEN HERE' "
@@ -90,8 +90,7 @@ EOF
90
90
 
91
91
  raise 'Unable to determine compliance profile name. This can be caused by ' \
92
92
  'an incorrect server in your configuration. Try to login to compliance ' \
93
- 'via the `inspec compliance login` or `inspec compliance login_automate` ' \
94
- 'commands.' if m.nil?
93
+ 'via the `inspec compliance login` command.' if m.nil?
95
94
 
96
95
  "#{m[:owner]}/#{m[:id]}"
97
96
  end
@@ -7,14 +7,19 @@ module Habitat
7
7
  class HabitatProfileCLI < Thor
8
8
  namespace 'habitat profile'
9
9
 
10
- desc 'create PATH', 'Create a Habitat artifact for the profile found at PATH'
10
+ desc 'create PATH', 'Create a one-time Habitat artifact for the profile found at PATH'
11
11
  option :output_dir, type: :string, required: false,
12
12
  desc: 'Directory in which to save the generated Habitat artifact. Default: current directory'
13
13
  def create(path)
14
14
  Habitat::Profile.create(path, options)
15
15
  end
16
16
 
17
- desc 'upload PATH', 'Create a Habitat artifact for the profile found at PATH, and upload it to a Habitat Depot'
17
+ desc 'setup PATH', 'Configure the profile at PATH for Habitat, including a plan and hooks'
18
+ def setup(path)
19
+ Habitat::Profile.setup(path)
20
+ end
21
+
22
+ desc 'upload PATH', 'Create a one-time Habitat artifact for the profile found at PATH, and upload it to a Habitat Depot'
18
23
  def upload(path)
19
24
  Habitat::Profile.upload(path, options)
20
25
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'inspec/profile_vendor'
5
5
  require 'mixlib/shellout'
6
- require 'toml'
6
+ require 'tomlrb'
7
7
 
8
8
  module Habitat
9
9
  class Profile # rubocop:disable Metrics/ClassLength
@@ -17,6 +17,10 @@ module Habitat
17
17
  creator.delete_work_dir
18
18
  end
19
19
 
20
+ def self.setup(path)
21
+ new(path).setup
22
+ end
23
+
20
24
  def self.upload(path, options = {})
21
25
  uploader = new(path, options)
22
26
  uploader.upload
@@ -41,10 +45,11 @@ module Habitat
41
45
  verify_profile
42
46
  vendor_profile_dependencies
43
47
  copy_profile_to_work_dir
44
- create_plan
45
- create_run_hook
46
- create_settings_file
47
- create_default_config
48
+ create_habitat_directories(work_dir)
49
+ create_plan(work_dir)
50
+ create_run_hook(work_dir)
51
+ create_settings_file(work_dir)
52
+ create_default_config(work_dir)
48
53
 
49
54
  # returns the path to the .hart file in the work directory
50
55
  build_hart
@@ -80,6 +85,18 @@ module Habitat
80
85
  FileUtils.rm_rf(work_dir) if Dir.exist?(work_dir)
81
86
  end
82
87
 
88
+ def setup
89
+ Habitat::Log.info("Setting up profile at #{path} for Habitat...")
90
+ create_profile_object
91
+ verify_profile
92
+ vendor_profile_dependencies
93
+ create_habitat_directories(path)
94
+ create_plan(path)
95
+ create_run_hook(path)
96
+ create_settings_file(path)
97
+ create_default_config(path)
98
+ end
99
+
83
100
  private
84
101
 
85
102
  def create_profile_object
@@ -151,20 +168,26 @@ module Habitat
151
168
  return @work_dir if @work_dir
152
169
 
153
170
  @work_dir ||= Dir.mktmpdir('inspec-habitat-exporter')
154
- Dir.mkdir(File.join(@work_dir, 'src'))
155
- Dir.mkdir(File.join(@work_dir, 'habitat'))
156
- Dir.mkdir(File.join(@work_dir, 'habitat', 'config'))
157
- Dir.mkdir(File.join(@work_dir, 'habitat', 'hooks'))
158
171
  Habitat::Log.debug("Generated work directory #{@work_dir}")
159
172
 
160
173
  @work_dir
161
174
  end
162
175
 
176
+ def create_habitat_directories(parent_directory)
177
+ [
178
+ File.join(parent_directory, 'habitat'),
179
+ File.join(parent_directory, 'habitat', 'config'),
180
+ File.join(parent_directory, 'habitat', 'hooks'),
181
+ ].each do |dir|
182
+ Dir.mkdir(dir) unless Dir.exist?(dir)
183
+ end
184
+ end
185
+
163
186
  def copy_profile_to_work_dir
164
187
  Habitat::Log.info('Copying profile contents to the work directory...')
165
188
  profile.files.each do |f|
166
189
  src = File.join(profile.root_path, f)
167
- dst = File.join(work_dir, 'src', f)
190
+ dst = File.join(work_dir, f)
168
191
  if File.directory?(f)
169
192
  Habitat::Log.debug("Creating directory #{dst}")
170
193
  FileUtils.mkdir_p(dst)
@@ -175,26 +198,26 @@ module Habitat
175
198
  end
176
199
  end
177
200
 
178
- def create_plan
179
- plan_file = File.join(work_dir, 'habitat', 'plan.sh')
201
+ def create_plan(directory)
202
+ plan_file = File.join(directory, 'habitat', 'plan.sh')
180
203
  Habitat::Log.info("Generating Habitat plan at #{plan_file}...")
181
204
  File.write(plan_file, plan_contents)
182
205
  end
183
206
 
184
- def create_run_hook
185
- run_hook_file = File.join(work_dir, 'habitat', 'hooks', 'run')
207
+ def create_run_hook(directory)
208
+ run_hook_file = File.join(directory, 'habitat', 'hooks', 'run')
186
209
  Habitat::Log.info("Generating a Habitat run hook at #{run_hook_file}...")
187
210
  File.write(run_hook_file, run_hook_contents)
188
211
  end
189
212
 
190
- def create_settings_file
191
- settings_file = File.join(work_dir, 'habitat', 'config', 'settings.sh')
213
+ def create_settings_file(directory)
214
+ settings_file = File.join(directory, 'habitat', 'config', 'settings.sh')
192
215
  Habitat::Log.info("Generating a settings file at #{settings_file}...")
193
216
  File.write(settings_file, "SLEEP_TIME={{cfg.sleep_time}}\n")
194
217
  end
195
218
 
196
- def create_default_config
197
- default_toml = File.join(work_dir, 'habitat', 'default.toml')
219
+ def create_default_config(directory)
220
+ default_toml = File.join(directory, 'habitat', 'default.toml')
198
221
  Habitat::Log.info("Generating Habitat's default.toml configuration...")
199
222
  File.write(default_toml, 'sleep_time = 300')
200
223
  end
@@ -275,7 +298,7 @@ module Habitat
275
298
  config_file = File.join(ENV['HOME'], '.hab', 'etc', 'cli.toml')
276
299
  return {} unless File.exist?(config_file)
277
300
 
278
- @cli_config = TOML.load_file(config_file)
301
+ @cli_config = Tomlrb.load_file(config_file)
279
302
  end
280
303
 
281
304
  def output_dir
@@ -308,7 +331,7 @@ EOL
308
331
  plan += <<-EOL
309
332
 
310
333
  do_build() {
311
- cp -vr $PLAN_CONTEXT/../src/* $HAB_CACHE_SRC_PATH/$pkg_dirname
334
+ cp -vr $PLAN_CONTEXT/../* $HAB_CACHE_SRC_PATH/$pkg_dirname
312
335
  }
313
336
 
314
337
  do_install() {
@@ -321,6 +344,7 @@ do_install() {
321
344
  profile_contents=(${profile_contents[@]/$item/})
322
345
  done
323
346
 
347
+ mkdir ${pkg_prefix}/dist
324
348
  cp -r ${profile_contents[@]} ${pkg_prefix}/dist/
325
349
  }
326
350
  EOL
@@ -1,3 +1,3 @@
1
1
  # Example InSpec Profile
2
2
 
3
- This example shows the implementation of an InSpec [profile](../../docs/profiles.rst).
3
+ This example shows the implementation of an InSpec profile.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # copyright: 2015, The Authors
2
+ # copyright: 2017, The Authors
3
3
 
4
4
  title 'sample section'
5
5
 
@@ -8,7 +8,7 @@ require 'addressable/uri'
8
8
 
9
9
  module Supermarket
10
10
  class API
11
- SUPERMARKET_URL = 'https://supermarket.chef.io'.freeze
11
+ SUPERMARKET_URL = 'https://supermarket.chef.io'
12
12
 
13
13
  # displays a list of profiles
14
14
  def self.profiles(supermarket_url = SUPERMARKET_URL)
@@ -17,6 +17,14 @@ module Inspec
17
17
  Inspec::VERSION
18
18
  end
19
19
 
20
+ # Determine whether the connection/transport is a local connection
21
+ # Useful for resources to modify behavior as necessary, such as using
22
+ # the Ruby stdlib for a better experience.
23
+ def local_transport?
24
+ return false unless defined?(Train::Transports::Local)
25
+ backend.is_a?(Train::Transports::Local::Connection)
26
+ end
27
+
20
28
  # Ruby internal for printing a nice name for this class
21
29
  def to_s
22
30
  'Inspec::Backend::Class'
data/lib/inspec/cli.rb CHANGED
@@ -186,7 +186,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
186
186
  option :command, aliases: :c,
187
187
  desc: 'A single command string to run instead of launching the shell'
188
188
  option :format, type: :string, default: nil, hide: true,
189
- desc: 'Which formatter to use: cli, progress, documentation, json, json-min, junit'
189
+ desc: 'Which formatter to use: cli, documentation, html, json, json-min, junit, progress'
190
190
  def shell_func
191
191
  diagnose
192
192
  o = opts.dup
@@ -35,7 +35,7 @@ module Inspec
35
35
  # @param profile_context [Inspec::ProfileContext]
36
36
  # @param outer_dsl [OuterDSLClass]
37
37
  # @return [ProfileContextClass]
38
- def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ def self.create(profile_context, resources_dsl) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
39
39
  rule_class = rule_context(resources_dsl)
40
40
  profile_context_owner = profile_context
41
41
  profile_id = profile_context.profile_id
@@ -45,12 +45,14 @@ module Inspec
45
45
  include Inspec::DSL::RequireOverride
46
46
  include resources_dsl
47
47
 
48
+ attr_accessor :skip_file
49
+
48
50
  def initialize(backend, conf, dependencies, require_loader)
49
51
  @backend = backend
50
52
  @conf = conf
51
53
  @dependencies = dependencies
52
54
  @require_loader = require_loader
53
- @skip_profile = false
55
+ @skip_file = false
54
56
  end
55
57
 
56
58
  define_method :title do |arg|
@@ -113,7 +115,7 @@ module Inspec
113
115
  end
114
116
 
115
117
  define_method :register_control do |control, &block|
116
- if @skip_profile || !profile_context_owner.profile_supports_os?
118
+ if @skip_file || !profile_context_owner.profile_supports_os?
117
119
  ::Inspec::Rule.set_skip_rule(control, true)
118
120
  end
119
121
 
@@ -129,9 +131,17 @@ module Inspec
129
131
  profile_context_owner.unregister_rule(id)
130
132
  end
131
133
 
132
- def only_if
133
- return unless block_given?
134
- @skip_profile ||= !yield
134
+ define_method :only_if do |&block|
135
+ return unless block
136
+ return if @skip_file == true || block.yield == true
137
+
138
+ # Apply `set_skip_rule` for other rules in the same file
139
+ profile_context_owner.rules.values.each do |r|
140
+ sources_match = r.source_file == block.source_location[0]
141
+ Inspec::Rule.set_skip_rule(r, true) if sources_match
142
+ end
143
+
144
+ @skip_file = true
135
145
  end
136
146
 
137
147
  alias_method :rule, :control
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'inspec/cached_fetcher'
3
3
  require 'inspec/dependencies/dependency_set'
4
+ require 'semverse'
4
5
 
5
6
  module Inspec
6
7
  #
@@ -10,7 +11,18 @@ module Inspec
10
11
  class Requirement
11
12
  def self.from_metadata(dep, cache, opts)
12
13
  raise 'Cannot load empty dependency.' if dep.nil? || dep.empty?
13
- new(dep[:name], dep[:version], cache, opts[:cwd], opts.merge(dep))
14
+
15
+ req_path = opts[:cwd]
16
+
17
+ if dep[:path]
18
+ req_path = File.expand_path(dep[:path], req_path)
19
+ end
20
+
21
+ new(dep[:name],
22
+ dep[:version],
23
+ cache,
24
+ req_path,
25
+ opts.merge(dep))
14
26
  end
15
27
 
16
28
  def self.from_lock_entry(entry, cwd, cache, backend, opts = {})
@@ -28,10 +40,10 @@ module Inspec
28
40
  req
29
41
  end
30
42
 
31
- attr_reader :cwd, :opts, :required_version
43
+ attr_reader :cwd, :opts, :version_constraints
32
44
  def initialize(name, version_constraints, cache, cwd, opts)
33
45
  @name = name
34
- @required_version = Gem::Requirement.new(Array(version_constraints))
46
+ @version_constraints = Array(version_constraints)
35
47
  @cache = cache
36
48
  @backend = opts[:backend]
37
49
  @opts = opts
@@ -51,11 +63,13 @@ module Inspec
51
63
  end
52
64
 
53
65
  def source_satisfies_spec?
54
- gem_dep.match?(profile.name, profile.version)
55
- end
66
+ return true if version_constraints.empty?
56
67
 
57
- def gem_dep
58
- @gem_dep ||= Gem::Dependency.new(profile.name, required_version, :runtime)
68
+ # Semverse::Constraint.satisfy_all returns a list of versions that match all of the
69
+ # supplied constraints. Since we're only matching against a single version, the return
70
+ # of satisfy_all will be non-empty if the profile version we have satisfies the constraints.
71
+ constraints = @version_constraints.map { |x| Semverse::Constraint.new(x) }
72
+ !Semverse::Constraint.satisfy_all(constraints, Semverse::Version.new(profile.version)).empty?
59
73
  end
60
74
 
61
75
  def resolved_source
@@ -66,7 +80,7 @@ module Inspec
66
80
  h = {
67
81
  'name' => name,
68
82
  'resolved_source' => resolved_source,
69
- 'version_constraints' => required_version.to_s,
83
+ 'version_constraints' => version_constraints.to_s,
70
84
  }
71
85
 
72
86
  if !dependencies.empty?