inspec 4.12.0 → 4.16.0

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.
@@ -116,9 +116,19 @@ module Inspec
116
116
  # we can create any inputs that were provided by various mechanisms.
117
117
  options[:runner_conf] ||= Inspec::Config.cached
118
118
 
119
+ # Catch legacy CLI input option usage
119
120
  if options[:runner_conf].key?(:attrs)
120
121
  Inspec.deprecate(:rename_attributes_to_inputs, "Use --input-file on the command line instead of --attrs.")
121
122
  options[:runner_conf][:input_file] = options[:runner_conf].delete(:attrs)
123
+ elsif options[:runner_conf].key?(:input_files)
124
+ # The kitchen-inspec docs say to use plural. Our CLI and internal expectations are singular.
125
+ options[:runner_conf][:input_file] = options[:runner_conf].delete(:input_files)
126
+ end
127
+
128
+ # Catch legacy kitchen-inspec input usage
129
+ if options[:runner_conf].key?(:attributes)
130
+ Inspec.deprecate(:rename_attributes_to_inputs, "Use :inputs in your kitchen.yml verifier config instead of :attributes.")
131
+ options[:runner_conf][:inputs] = options[:runner_conf].delete(:attributes)
122
132
  end
123
133
 
124
134
  Inspec::InputRegistry.bind_profile_inputs(
@@ -127,8 +137,8 @@ module Inspec
127
137
  # Remaining args are possible sources of inputs
128
138
  cli_input_files: options[:runner_conf][:input_file], # From CLI --input-file
129
139
  profile_metadata: metadata,
130
- # TODO: deprecation checks here
131
- runner_api: options[:runner_conf][:attributes] # This is the route the audit_cookbook and kitchen-inspec take
140
+ runner_api: options[:runner_conf][:inputs], # This is the route the audit_cookbook and kitchen-inspec take
141
+ cli_input_arg: options[:runner_conf][:input] # The --input name=value CLI option
132
142
  )
133
143
 
134
144
  @runner_context =
@@ -84,6 +84,7 @@ require "inspec/resources/passwd"
84
84
  require "inspec/resources/pip"
85
85
  require "inspec/resources/platform"
86
86
  require "inspec/resources/port"
87
+ require "inspec/resources/postfix_conf"
87
88
  require "inspec/resources/postgres"
88
89
  require "inspec/resources/postgres_conf"
89
90
  require "inspec/resources/postgres_hba_conf"
@@ -0,0 +1,31 @@
1
+ require "inspec/resources/ini"
2
+ require "inspec/utils/simpleconfig"
3
+
4
+ module Inspec::Resources
5
+ class PostfixConf < IniConfig
6
+ name "postfix_conf"
7
+ supports platform: "linux"
8
+ desc "Use the postfix_conf Inspec audit resource to test the configuration of the Postfix Mail Transfer Agent"
9
+
10
+ # Allow user to specify a custom configuration path, use default Postfix configuration path if no custom path is provided
11
+ def initialize(*opts)
12
+ @params = {}
13
+ if opts.length == 1
14
+ @raw_content = load_raw_content(opts)
15
+ else
16
+ @raw_content = load_raw_content("/etc/postfix/main.cf")
17
+ end
18
+ @params = parse(@raw_content)
19
+ end
20
+
21
+ def parse(content)
22
+ SimpleConfig.new(content).params
23
+ end
24
+
25
+ private
26
+
27
+ def resource_base_name
28
+ "POSTFIX_CONF"
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.12.0".freeze
2
+ VERSION = "4.16.0".freeze
3
3
  end
@@ -6,6 +6,14 @@ require "inspec/dist"
6
6
  module InspecPlugins
7
7
  module PluginManager
8
8
  class CliCommand < Inspec.plugin(2, :cli_command)
9
+ INSTALL_TYPE_LABELS = {
10
+ bundle: "core", # Calling this core, too - not much of a distinction
11
+ core: "core",
12
+ path: "path",
13
+ user_gem: "gem (user)",
14
+ system_gem: "gem (system)",
15
+ }.freeze
16
+
9
17
  include Inspec::Dist
10
18
 
11
19
  subcommand_desc "plugin SUBCOMMAND", "Manage #{PRODUCT_NAME} and Train plugins"
@@ -15,22 +23,36 @@ module InspecPlugins
15
23
  #==================================================================#
16
24
 
17
25
  desc "list [options]", "Lists user-installed #{PRODUCT_NAME} plugins."
18
- option :all, desc: "Include plugins shipped with #{PRODUCT_NAME} as well.", type: :boolean, aliases: [:a]
26
+ option :all, desc: "List all types of plugins (default)", type: :boolean, default: true, aliases: [:a]
27
+ option :user, desc: "List user plugins, from ~/.inspec/gems", banner: "", type: :boolean, default: false, aliases: [:u]
28
+ option :system, desc: "List system plugins, those InSpec depends on", banner: "", type: :boolean, default: false, aliases: [:s]
29
+ option :core, desc: "List core plugins, those InSpec ships with", banner: "", type: :boolean, default: false, aliases: [:c]
30
+
19
31
  def list
20
32
  plugin_statuses = Inspec::Plugin::V2::Registry.instance.plugin_statuses
21
- plugin_statuses.reject! { |s| %i{core bundle}.include?(s.installation_type) } unless options[:all]
33
+ options[:all] = false if options[:core] || options[:user] || options[:system]
34
+ plugin_statuses.select! do |status|
35
+ type = status.installation_type
36
+ options[:all] ||
37
+ (options[:core] && %i{core bundle}.include?(type)) ||
38
+ (options[:user] && %i{user_gem path}.include?(type)) ||
39
+ (options[:system] && :system_gem == type)
40
+ end
22
41
 
23
- puts
24
- ui.bold(format(" %-30s%-10s%-8s%-6s", "Plugin Name", "Version", "Via", "ApiVer"))
25
- ui.line
26
- plugin_statuses.sort_by(&:name).each do |status|
27
- ui.plain(format(" %-30s%-10s%-8s%-6s", status.name,
28
- make_pretty_version(status),
29
- status.installation_type,
30
- status.api_generation.to_s))
42
+ unless plugin_statuses.empty?
43
+ ui.table do |t|
44
+ t.header = ["Plugin Name", "Version", "Via", "ApiVer"]
45
+ plugin_statuses.sort_by { |s| s.name.to_s }.each do |status|
46
+ t << [
47
+ status.name,
48
+ make_pretty_version(status),
49
+ make_pretty_install_type(status),
50
+ status.api_generation,
51
+ ]
52
+ end
53
+ end
31
54
  end
32
- ui.line
33
- ui.plain(" #{plugin_statuses.count} plugin(s) total")
55
+ ui.plain_line(" #{plugin_statuses.count} plugin(s) total")
34
56
  puts
35
57
  end
36
58
 
@@ -60,15 +82,15 @@ module InspecPlugins
60
82
  end
61
83
 
62
84
  puts
63
- ui.bold(format(" %-30s%-50s", "Plugin Name", "Versions Available"))
85
+ ui.bold(format(" %-30s%-50s\n", "Plugin Name", "Versions Available"))
64
86
  ui.line
65
87
  search_results.keys.sort.each do |plugin_name|
66
88
  versions = options[:all] ? search_results[plugin_name] : [search_results[plugin_name].first]
67
89
  versions = "(" + versions.join(", ") + ")"
68
- ui.plain(format(" %-30s%-50s", plugin_name, versions))
90
+ ui.plain_line(format(" %-30s%-50s", plugin_name, versions))
69
91
  end
70
92
  ui.line
71
- ui.plain(" #{search_results.count} plugin(s) found")
93
+ ui.plain_line(" #{search_results.count} plugin(s) found")
72
94
  puts
73
95
 
74
96
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR if search_results.empty?
@@ -118,14 +140,14 @@ module InspecPlugins
118
140
  begin
119
141
  installer.update(plugin_name)
120
142
  rescue Inspec::Plugin::V2::UpdateError => ex
121
- ui.plain("#{ui.red('Update error:')} #{ex.message} - update failed")
143
+ ui.plain_line("#{ui.red("Update error:", print: false)} #{ex.message} - update failed")
122
144
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
123
145
  end
124
146
  post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
125
147
  new_version = (post_update_versions - pre_update_versions).first
126
148
 
127
149
  ui.bold(plugin_name + " plugin, version #{old_version} -> " \
128
- "#{new_version}, updated from rubygems.org")
150
+ "#{new_version}, updated from rubygems.org\n")
129
151
  end
130
152
 
131
153
  #--------------------------
@@ -144,7 +166,7 @@ module InspecPlugins
144
166
  def uninstall(plugin_name)
145
167
  status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
146
168
  unless status
147
- ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} is not " \
169
+ ui.plain_line("#{ui.red("No such plugin installed:", print: false)} #{plugin_name} is not " \
148
170
  "installed - uninstall failed")
149
171
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
150
172
  end
@@ -157,11 +179,12 @@ module InspecPlugins
157
179
 
158
180
  if status.installation_type == :path
159
181
  ui.bold(plugin_name + " path-based plugin install has been " \
160
- "uninstalled")
182
+ "uninstalled\n")
161
183
  else
162
184
  ui.bold(plugin_name + " plugin, version #{old_version}, has " \
163
- "been uninstalled")
185
+ "been uninstalled\n")
164
186
  end
187
+
165
188
  ui.exit Inspec::UI::EXIT_NORMAL
166
189
  end
167
190
 
@@ -174,7 +197,7 @@ module InspecPlugins
174
197
 
175
198
  def install_from_gemfile(gem_file)
176
199
  unless File.exist? gem_file
177
- ui.red("No such plugin gem file #{gem_file} - installation failed.")
200
+ ui.red("No such plugin gem file #{gem_file} - installation failed.\n")
178
201
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
179
202
  end
180
203
 
@@ -186,13 +209,13 @@ module InspecPlugins
186
209
  installer.install(plugin_name, gem_file: gem_file)
187
210
 
188
211
  ui.bold("#{plugin_name} plugin, version #{version}, installed from " \
189
- "local .gem file")
212
+ "local .gem file\n")
190
213
  ui.exit Inspec::UI::EXIT_NORMAL
191
214
  end
192
215
 
193
216
  def install_from_path(path)
194
217
  unless File.exist? path
195
- ui.red("No such source code path #{path} - installation failed.")
218
+ ui.red("No such source code path #{path} - installation failed.\n")
196
219
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
197
220
  end
198
221
 
@@ -209,7 +232,7 @@ module InspecPlugins
209
232
  if registry.known_plugin?(plugin_name.to_sym)
210
233
  ui.red("Plugin already installed - #{plugin_name} - Use '#{EXEC_NAME} " \
211
234
  "plugin list' to see previously installed plugin - " \
212
- "installation failed.")
235
+ "installation failed.\n")
213
236
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
214
237
  end
215
238
 
@@ -223,7 +246,7 @@ module InspecPlugins
223
246
  installer.install(plugin_name, path: entry_point)
224
247
 
225
248
  ui.bold("#{plugin_name} plugin installed via source path reference, " \
226
- "resolved to entry point #{entry_point}")
249
+ "resolved to entry point #{entry_point}\n")
227
250
  ui.exit Inspec::UI::EXIT_NORMAL
228
251
  end
229
252
 
@@ -288,7 +311,7 @@ module InspecPlugins
288
311
  # Give up.
289
312
  ui.red("Unrecognizable plugin structure - #{parts[2]} - When " \
290
313
  "installing from a path, please provide the path of the " \
291
- "entry point file - installation failed.")
314
+ "entry point file - installation failed.\n")
292
315
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
293
316
  end
294
317
 
@@ -299,8 +322,8 @@ module InspecPlugins
299
322
  rescue LoadError => ex
300
323
  ui.red("Plugin contains errors - #{plugin_name} - Encountered " \
301
324
  "errors while trying to test load the plugin entry point, " \
302
- "resolved to #{entry_point} - installation failed")
303
- ui.plain ex.message
325
+ "resolved to #{entry_point} - installation failed\n")
326
+ ui.plain_line ex.message
304
327
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
305
328
  end
306
329
 
@@ -313,7 +336,7 @@ module InspecPlugins
313
336
  ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
314
337
  "probe-loading the supposed plugin, it did not register " \
315
338
  "itself to Train. Ensure something inherits from " \
316
- "'Train.plugin(1)' - installation failed.")
339
+ "'Train.plugin(1)' - installation failed.\n")
317
340
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
318
341
  end
319
342
  else
@@ -321,7 +344,7 @@ module InspecPlugins
321
344
  ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
322
345
  "probe-loading the supposed plugin, it did not register " \
323
346
  "itself to InSpec. Ensure something inherits from " \
324
- "'Inspec.plugin(2)' - installation failed.")
347
+ "'Inspec.plugin(2)' - installation failed.\n")
325
348
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
326
349
  end
327
350
  end
@@ -343,7 +366,7 @@ module InspecPlugins
343
366
  new_version = (post_installed_versions - pre_installed_versions).first
344
367
 
345
368
  ui.bold("#{plugin_name} plugin, version #{new_version}, installed " \
346
- "from rubygems.org")
369
+ "from rubygems.org\n")
347
370
  ui.exit Inspec::UI::EXIT_NORMAL
348
371
  end
349
372
 
@@ -367,16 +390,16 @@ module InspecPlugins
367
390
  what_we_would_install_is_already_installed = pre_installed_versions.include?(requested_version)
368
391
  if what_we_would_install_is_already_installed && they_explicitly_asked_for_a_version
369
392
  ui.red("Plugin already installed at requested version - plugin " \
370
- "#{plugin_name} #{requested_version} - refusing to install.")
393
+ "#{plugin_name} #{requested_version} - refusing to install.\n")
371
394
  elsif what_we_would_install_is_already_installed && !they_explicitly_asked_for_a_version
372
395
  ui.red("Plugin already installed at latest version - plugin " \
373
- "#{plugin_name} #{requested_version} - refusing to install.")
396
+ "#{plugin_name} #{requested_version} - refusing to install.\n")
374
397
  else
375
398
  # There are existing versions installed, but none of them are what was requested
376
399
  ui.red("Update required - plugin #{plugin_name}, requested " \
377
400
  "#{requested_version}, have " \
378
- "#{pre_installed_versions.join(', ')}; use `inspec " \
379
- "plugin update` - refusing to install.")
401
+ "#{pre_installed_versions.join(", ")}; use `inspec " \
402
+ "plugin update` - refusing to install.\n")
380
403
  end
381
404
 
382
405
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
@@ -387,11 +410,11 @@ module InspecPlugins
387
410
  installer.install(plugin_name, version: options[:version])
388
411
  rescue Inspec::Plugin::V2::PluginExcludedError => ex
389
412
  ui.red("Plugin on Exclusion List - #{plugin_name} is listed as an " \
390
- "incompatible gem - refusing to install.")
391
- ui.plain("Rationale: #{ex.details.rationale}")
392
- ui.plain("Exclusion list location: " +
413
+ "incompatible gem - refusing to install.\n")
414
+ ui.plain_line("Rationale: #{ex.details.rationale}")
415
+ ui.plain_line("Exclusion list location: " +
393
416
  File.join(Inspec.src_root, "etc", "plugin_filters.json"))
394
- ui.plain("If you disagree with this determination, please accept " \
417
+ ui.plain_line("If you disagree with this determination, please accept " \
395
418
  "our apologies for the misunderstanding, and open an issue " \
396
419
  "at https://github.com/inspec/inspec/issues/new")
397
420
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
@@ -401,13 +424,13 @@ module InspecPlugins
401
424
  results = installer.search(plugin_name, exact: true)
402
425
  if results.empty?
403
426
  ui.red("No such plugin gem #{plugin_name} could be found on " \
404
- "rubygems.org - installation failed.")
427
+ "rubygems.org - installation failed.\n")
405
428
  elsif options[:version] && !results[plugin_name].include?(options[:version])
406
429
  ui.red("No such version - #{plugin_name} exists, but no such " \
407
430
  "version #{options[:version]} found on rubygems.org - " \
408
- "installation failed.")
431
+ "installation failed.\n")
409
432
  else
410
- ui.red("Unknown error occured - installation failed.")
433
+ ui.red("Unknown error occured - installation failed.\n")
411
434
  end
412
435
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
413
436
  end
@@ -420,10 +443,10 @@ module InspecPlugins
420
443
  # Check for path install
421
444
  status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
422
445
  if !status
423
- ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} - update failed")
446
+ ui.plain_line("#{ui.red("No such plugin installed:", print: false)} #{plugin_name} - update failed")
424
447
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
425
448
  elsif status.installation_type == :path
426
- ui.plain("#{ui.red('Cannot update path-based install:')} " \
449
+ ui.plain_line("#{ui.red("Cannot update path-based install:", print: false)} " \
427
450
  "#{plugin_name} is installed via path reference; " \
428
451
  "use `inspec plugin uninstall` to remove - refusing to" \
429
452
  "update")
@@ -436,7 +459,7 @@ module InspecPlugins
436
459
  latest_version = latest_version[plugin_name]&.last
437
460
 
438
461
  if pre_update_versions.include?(latest_version)
439
- ui.plain("#{ui.red('Already installed at latest version:')} " \
462
+ ui.plain_line("#{ui.red("Already installed at latest version:", print: false)} " \
440
463
  "#{plugin_name} is at #{latest_version}, which the " \
441
464
  "latest - refusing to update")
442
465
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
@@ -458,7 +481,7 @@ module InspecPlugins
458
481
  unless plugin_name =~ /^(inspec|train)-/
459
482
  ui.red("Invalid plugin name - #{plugin_name} - All inspec " \
460
483
  "plugins must begin with either 'inspec-' or 'train-' " \
461
- "- #{action} failed.")
484
+ "- #{action} failed.\n")
462
485
  ui.exit Inspec::UI::EXIT_USAGE_ERROR
463
486
  end
464
487
  end
@@ -467,17 +490,29 @@ module InspecPlugins
467
490
  case status.installation_type
468
491
  when :core, :bundle
469
492
  Inspec::VERSION
470
- when :gem
471
- # TODO: this is naive, and assumes the latest version is the one that will be used. Logged on #3317
472
- # In fact, the logic to determine "what version would be used" belongs in the Loader.
473
- Inspec::Plugin::V2::Loader.list_installed_plugin_gems
474
- .select { |spec| spec.name == status.name.to_s }
475
- .sort_by(&:version)
476
- .last.version
493
+ when :user_gem, :system_gem
494
+ if status.version.nil?
495
+ "(unknown)"
496
+ elsif status.version =~ /^\d+\.\d+\.\d+$/
497
+ status.version
498
+ else
499
+ # Assume it is a version constraint string and try to resolve
500
+ # TODO: this is naive, and assumes the latest version is the one that will be used. Logged on #3317
501
+ # In fact, the logic to determine "what version would be used" belongs in the Loader.
502
+ plugin_name = status.name.to_s
503
+ Inspec::Plugin::V2::Loader.list_installed_plugin_gems
504
+ .select { |spec| spec.name == plugin_name }
505
+ .sort_by(&:version)
506
+ .last.version
507
+ end
477
508
  when :path
478
509
  "src"
479
510
  end
480
511
  end
512
+
513
+ def make_pretty_install_type(status)
514
+ INSTALL_TYPE_LABELS[status.installation_type]
515
+ end
481
516
  end
482
517
  end
483
518
  end
@@ -15,7 +15,9 @@ module PluginManagerHelpers
15
15
  let(:list_after_run) do
16
16
  Proc.new do |run_result, tmp_dir|
17
17
  # After installing/uninstalling/whatevering, run list with config in the same dir, and capture it.
18
- run_result.payload.list_result = run_inspec_process("plugin list", env: { INSPEC_CONFIG_DIR: tmp_dir })
18
+ run_result.payload.list_result = parse_plugin_list_lines(
19
+ run_inspec_process("plugin list", env: { INSPEC_CONFIG_DIR: tmp_dir }).stdout
20
+ )
19
21
  end
20
22
  end
21
23
 
@@ -39,6 +41,27 @@ module PluginManagerHelpers
39
41
  end
40
42
  end
41
43
 
44
+ def parse_plugin_list_lines(stdout)
45
+ plugins = []
46
+
47
+ stdout.force_encoding("UTF-8").lines.each do |line|
48
+ next if line.strip.empty?
49
+ next if line.include? "─────" # This is some unicode glyphiness
50
+ next if line.include? "Plugin Name"
51
+ next if line.include? "plugin(s) total"
52
+
53
+ parts = line.split(/│/u).map(&:strip!).compact
54
+ plugins << {
55
+ name: parts[0],
56
+ version: parts[1],
57
+ type: parts[2],
58
+ generation: parts[3],
59
+ raw: line,
60
+ }
61
+ end
62
+ plugins
63
+ end
64
+
42
65
  def teardown
43
66
  clear_empty_config_dir
44
67
  end
@@ -76,31 +99,41 @@ class PluginManagerCliList < Minitest::Test
76
99
  include CorePluginFunctionalHelper
77
100
  include PluginManagerHelpers
78
101
 
79
- def test_list_when_no_user_plugins_installed
80
- result = run_inspec_process_with_this_plugin("plugin list")
81
-
82
- skip_windows!
83
- assert_includes result.stdout, "0 plugin(s) total", "Empty list should include zero count"
84
-
85
- assert_exit_code 0, result
86
- end
102
+ # Listing all plugins is now default behavior
103
+ LIST_CASES = [
104
+ { arg: "-c", name: "inspec-plugin-manager-cli", type: "core" },
105
+ { arg: "-c", name: "inspec-supermarket", type: "core" },
106
+ { arg: "-s", name: "train-aws", type: "gem (system)" },
107
+ ].freeze
87
108
 
88
109
  def test_list_all_when_no_user_plugins_installed
89
110
  result = run_inspec_process_with_this_plugin("plugin list --all")
90
-
91
111
  skip_windows!
92
- assert_includes result.stdout, "6 plugin(s) total", "--all list should find six"
93
- assert_includes result.stdout, "inspec-plugin-manager-cli", "--all list should find inspec-plugin-manager-cli"
94
- assert_includes result.stdout, "habitat", "--all list should find habitat"
112
+ assert_empty result.stderr
95
113
 
96
- assert_exit_code 0, result
114
+ plugins_seen = parse_plugin_list_lines(result.stdout)
97
115
 
98
- # TODO: split
99
- result = run_inspec_process_with_this_plugin("plugin list -a")
116
+ # Look for a specific plugin of each type - core, bundle, and system
117
+ LIST_CASES.each do |test_case|
118
+ plugin_line = plugins_seen.detect { |plugin| plugin[:name] == test_case[:name] }
119
+ refute_nil plugin_line, "#{test_case[:name]} should be detected in plugin list --all output"
120
+ assert_equal test_case[:type], plugin_line[:type], "#{test_case[:name]} should be detected as a '#{test_case[:type]}' type in list --all "
121
+ end
122
+ assert_exit_code 0, result
123
+ end
100
124
 
101
- assert_includes result.stdout, "6 plugin(s) total", "-a list should find six"
125
+ def test_list_selective_when_no_user_plugins_installed
126
+ LIST_CASES.each do |test_case|
127
+ result = run_inspec_process_with_this_plugin("plugin list #{test_case[:arg]}")
128
+ skip_windows!
102
129
 
103
- assert_exit_code 0, result
130
+ assert_empty result.stderr
131
+ plugins_seen = parse_plugin_list_lines(result.stdout)
132
+ plugin_line = plugins_seen.detect { |plugin| plugin[:name] == test_case[:name] }
133
+ refute_nil plugin_line, "#{test_case[:name]} should be detected in plugin list #{test_case[:arg]} output"
134
+ assert_equal plugin_line[:type], test_case[:type], "#{test_case[:name]} should be detected as a '#{test_case[:type]}' type in list #{test_case[:arg]} "
135
+ assert_exit_code 0, result
136
+ end
104
137
  end
105
138
 
106
139
  def test_list_when_gem_and_path_plugins_installed
@@ -109,21 +142,26 @@ class PluginManagerCliList < Minitest::Test
109
142
  copy_in_core_config_dir("test-fixture-1-float", tmp_dir)
110
143
  end
111
144
 
112
- result = run_inspec_process_with_this_plugin("plugin list", pre_run: pre_block)
113
-
145
+ result = run_inspec_process_with_this_plugin("plugin list --user ", pre_run: pre_block)
114
146
  skip_windows!
115
- assert_includes result.stdout, "2 plugin(s) total", "gem+path should show two plugins"
116
147
 
117
- # Plugin Name Version Via ApiVer
118
- # -------------------------------------------------------
119
- # inspec-meaning-of-life src path 2
120
- # inspec-test-fixture 0.1.0 gem 2
121
- # -------------------------------------------------------
148
+ assert_empty result.stderr
149
+ plugins_seen = parse_plugin_list_lines(result.stdout)
150
+ assert_equal 2, plugins_seen.count
151
+ # Plugin Name Version Via ApiVer
152
+ # ---------------------------------------------------------
153
+ # inspec-meaning-of-life src path 2
154
+ # inspec-test-fixture 0.1.0 gem (user) 2
155
+ # ---------------------------------------------------------
122
156
  # 2 plugin(s) total
123
- gem_line = result.stdout.split("\n").grep(/gem/).first
124
- assert_match(/\s*inspec-\S+\s+\d+\.\d+\.\d+\s+gem\s+2/, gem_line)
125
- path_line = result.stdout.split("\n").grep(/path/).first
126
- assert_match(/\s*inspec-\S+\s+src\s+path\s+2/, path_line)
157
+ meaning = plugins_seen.detect { |p| p[:name] == "inspec-meaning-of-life" }
158
+ refute_nil meaning
159
+ assert_equal "path", meaning[:type]
160
+
161
+ fixture = plugins_seen.detect { |p| p[:name] == "inspec-test-fixture" }
162
+ refute_nil fixture
163
+ assert_equal "gem (user)", fixture[:type]
164
+ assert_equal "0.1.0", fixture[:version]
127
165
 
128
166
  assert_exit_code 0, result
129
167
  end
@@ -134,21 +172,24 @@ class PluginManagerCliList < Minitest::Test
134
172
  copy_in_core_config_dir("train-test-fixture", tmp_dir)
135
173
  end
136
174
 
137
- result = run_inspec_process_with_this_plugin("plugin list", pre_run: pre_block)
138
-
175
+ result = run_inspec_process_with_this_plugin("plugin list --user ", pre_run: pre_block)
139
176
  skip_windows!
177
+
178
+ assert_empty result.stderr
179
+ plugins_seen = parse_plugin_list_lines(result.stdout)
180
+ assert_equal 1, plugins_seen.count
140
181
  assert_includes result.stdout, "1 plugin(s) total", "list train should show one plugins"
141
182
 
142
- # Plugin Name Version Via ApiVer
143
- # -------------------------------------------------------
144
- # train-test-fixture 0.1.0 gem train-1
145
- # -------------------------------------------------------
183
+ # Plugin Name Version Via ApiVer
184
+ # -------------------------------------------------------------
185
+ # train-test-fixture 0.1.0 gem (user) train-1
186
+ # -------------------------------------------------------------
146
187
  # 1 plugin(s) total
147
- train_line = result.stdout.split("\n").grep(/train/).first
148
- assert_includes(train_line, "train-test-fixture")
149
- assert_includes(train_line, "0.1.0")
150
- assert_includes(train_line, "gem")
151
- assert_includes(train_line, "train-1")
188
+ train_plugin = plugins_seen.detect { |p| p[:name] == "train-test-fixture" }
189
+ refute_nil train_plugin
190
+ assert_equal "gem (user)", train_plugin[:type]
191
+ assert_equal "train-1", train_plugin[:generation]
192
+ assert_equal "0.1.0", train_plugin[:version]
152
193
 
153
194
  assert_exit_code 0, result
154
195
  end
@@ -333,23 +374,21 @@ class PluginManagerCliInstall < Minitest::Test
333
374
  # Check UX messaging
334
375
  success_message = install_result.stdout.split("\n").grep(/installed/).last
335
376
  skip_windows!
377
+ assert_empty install_result.stderr
336
378
  refute_nil success_message, "Should find a success message at the end"
337
379
  assert_includes success_message, fixture_info[:plugin_name]
338
380
  assert_includes success_message, "plugin installed via source path reference"
339
381
 
340
382
  # Check round-trip UX via list
341
- list_result = install_result.payload.list_result
342
- itf_line = list_result.stdout.split("\n").grep(Regexp.new(fixture_info[:plugin_name])).first
343
- refute_nil itf_line, "plugin name should now appear in the output of inspec list"
344
- assert_match(/\s*(inspec|train)-test-fixture\s+src\s+path\s+/, itf_line, "list output should show that it is a path installation")
383
+ itf_plugin = install_result.payload.list_result.detect { |p| p[:name] == fixture_info[:plugin_name] }
384
+ refute_nil itf_plugin, "plugin name should now appear in the output of inspec list"
385
+ assert_equal "path", itf_plugin[:type], "list output should show that it is a path installation"
345
386
 
346
387
  # Check plugin statefile. Extra important in this case, since all should resolve to the same entry point.
347
388
  plugin_data = install_result.payload.plugin_data
348
389
  entry = plugin_data["plugins"].detect { |e| e["name"] == fixture_info[:plugin_name] }
349
390
  assert_equal fixture_info[:resolved_path], entry["installation_path"], "Regardless of input, the entry point should be correct."
350
391
 
351
- assert_empty install_result.stderr
352
-
353
392
  assert_exit_code 0, install_result
354
393
  end
355
394
  end
@@ -357,9 +396,9 @@ class PluginManagerCliInstall < Minitest::Test
357
396
  def test_fail_install_from_nonexistant_path
358
397
  bad_path = File.join(project_fixtures_path, "none", "such", "inspec-test-fixture-nonesuch.rb")
359
398
  install_result = run_inspec_process_with_this_plugin("plugin install #{bad_path}")
360
-
361
- error_message = install_result.stdout.split("\n").last
362
399
  skip_windows!
400
+
401
+ error_message = install_result.stdout
363
402
  assert_includes error_message, "No such source code path"
364
403
  assert_includes error_message, "inspec-test-fixture-nonesuch.rb"
365
404
  assert_includes error_message, "installation failed"
@@ -372,9 +411,9 @@ class PluginManagerCliInstall < Minitest::Test
372
411
  def test_fail_install_from_path_with_wrong_name
373
412
  bad_path = File.join(project_fixtures_path, "plugins", "wrong-name", "lib", "wrong-name.rb")
374
413
  install_result = run_inspec_process_with_this_plugin("plugin install #{bad_path}")
375
-
376
- error_message = install_result.stdout.split("\n").last
377
414
  skip_windows!
415
+
416
+ error_message = install_result.stdout
378
417
  assert_includes error_message, "Invalid plugin name"
379
418
  assert_includes error_message, "wrong-name"
380
419
  assert_includes error_message, "All inspec plugins must begin with either 'inspec-' or 'train-'"
@@ -388,9 +427,9 @@ class PluginManagerCliInstall < Minitest::Test
388
427
  def test_fail_install_from_path_when_it_is_not_a_plugin
389
428
  bad_path = File.join(project_fixtures_path, "plugins", "inspec-egg-white-omelette", "lib", "inspec-egg-white-omelette.rb")
390
429
  install_result = run_inspec_process_with_this_plugin("plugin install #{bad_path}")
391
-
392
- error_message = install_result.stdout.split("\n").last
393
430
  skip_windows!
431
+
432
+ error_message = install_result.stdout
394
433
  assert_includes error_message, "Does not appear to be a plugin"
395
434
  assert_includes error_message, "inspec-egg-white-omelette"
396
435
  assert_includes error_message, "After probe-loading the supposed plugin, it did not register"
@@ -413,9 +452,9 @@ class PluginManagerCliInstall < Minitest::Test
413
452
  end
414
453
 
415
454
  install_result = run_inspec_process_with_this_plugin("plugin install #{plugin_path}", pre_run: pre_block)
416
-
417
- error_message = install_result.stdout.split("\n").last
418
455
  skip_windows!
456
+
457
+ error_message = install_result.stdout
419
458
  assert_includes error_message, "Plugin already installed"
420
459
  assert_includes error_message, "inspec-test-fixture"
421
460
  assert_includes error_message, "Use 'inspec plugin list' to see previously installed plugin"
@@ -429,9 +468,9 @@ class PluginManagerCliInstall < Minitest::Test
429
468
  def test_fail_install_from_path_when_the_dir_structure_is_wrong
430
469
  bad_path = File.join(project_fixtures_path, "plugins", "inspec-wrong-structure")
431
470
  install_result = run_inspec_process_with_this_plugin("plugin install #{bad_path}")
432
-
433
- error_message = install_result.stdout.split("\n").last
434
471
  skip_windows!
472
+
473
+ error_message = install_result.stdout
435
474
  assert_includes error_message, "Unrecognizable plugin structure"
436
475
  assert_includes error_message, "inspec-wrong-structure"
437
476
  assert_includes error_message, " When installing from a path, please provide the path of the entry point file"
@@ -445,21 +484,18 @@ class PluginManagerCliInstall < Minitest::Test
445
484
  def test_install_from_gemfile
446
485
  fixture_gemfile_path = File.join(core_fixture_plugins_path, "inspec-test-fixture", "pkg", "inspec-test-fixture-0.1.0.gem")
447
486
  install_result = run_inspec_process_with_this_plugin("plugin install #{fixture_gemfile_path}", post_run: list_after_run)
487
+ skip_windows!
448
488
 
449
489
  success_message = install_result.stdout.split("\n").grep(/installed/).last
450
- skip_windows!
451
490
  refute_nil success_message, "Should find a success message at the end"
452
- assert_includes success_message, "inspec-test-fixture"
453
- assert_includes success_message, "0.1.0"
454
491
  assert_includes success_message, "installed from local .gem file"
455
492
 
456
- list_result = install_result.payload.list_result
457
- itf_line = list_result.stdout.split("\n").grep(/inspec-test-fixture/).first
458
- refute_nil itf_line, "inspec-test-fixture should now appear in the output of inspec list"
459
- assert_match(/\s*inspec-test-fixture\s+0.1.0\s+gem\s+/, itf_line, "list output should show that it is a gem installation with version")
493
+ itf_plugin = install_result.payload.list_result.detect { |p| p[:name] == "inspec-test-fixture" }
494
+ refute_nil itf_plugin, "plugin name should now appear in the output of inspec list"
495
+ assert_equal "gem (user)", itf_plugin[:type]
496
+ assert_equal "0.1.0", itf_plugin[:version]
460
497
 
461
498
  assert_empty install_result.stderr
462
-
463
499
  assert_exit_code 0, install_result
464
500
  end
465
501
 
@@ -477,21 +513,20 @@ class PluginManagerCliInstall < Minitest::Test
477
513
 
478
514
  def test_install_from_rubygems_latest
479
515
  install_result = run_inspec_process_with_this_plugin("plugin install inspec-test-fixture", post_run: list_after_run)
516
+ skip_windows!
480
517
 
481
518
  success_message = install_result.stdout.split("\n").grep(/installed/).last
482
- skip_windows!
483
519
  refute_nil success_message, "Should find a success message at the end"
484
520
  assert_includes success_message, "inspec-test-fixture"
485
521
  assert_includes success_message, "0.2.0"
486
522
  assert_includes success_message, "installed from rubygems.org"
487
523
 
488
- list_result = install_result.payload.list_result
489
- itf_line = list_result.stdout.split("\n").grep(/inspec-test-fixture/).first
490
- refute_nil itf_line, "inspec-test-fixture should now appear in the output of inspec list"
491
- assert_match(/\s*inspec-test-fixture\s+0.2.0\s+gem\s+/, itf_line, "list output should show that it is a gem installation with version")
524
+ itf_plugin = install_result.payload.list_result.detect { |p| p[:name] == "inspec-test-fixture" }
525
+ refute_nil itf_plugin, "plugin name should now appear in the output of inspec list"
526
+ assert_equal "gem (user)", itf_plugin[:type]
527
+ assert_equal "0.2.0", itf_plugin[:version]
492
528
 
493
529
  assert_empty install_result.stderr
494
-
495
530
  assert_exit_code 0, install_result
496
531
  end
497
532
 
@@ -516,10 +551,10 @@ class PluginManagerCliInstall < Minitest::Test
516
551
  assert_includes success_message, "0.1.0"
517
552
  assert_includes success_message, "installed from rubygems.org"
518
553
 
519
- list_result = install_result.payload.list_result
520
- itf_line = list_result.stdout.split("\n").grep(/inspec-test-fixture/).first
521
- refute_nil itf_line, "inspec-test-fixture should now appear in the output of inspec list"
522
- assert_match(/\s*inspec-test-fixture\s+0.1.0\s+gem\s+/, itf_line, "list output should show that it is a gem installation with version")
554
+ itf_plugin = install_result.payload.list_result.detect { |p| p[:name] == "inspec-test-fixture" }
555
+ refute_nil itf_plugin, "plugin name should now appear in the output of inspec list"
556
+ assert_equal "gem (user)", itf_plugin[:type]
557
+ assert_equal "0.1.0", itf_plugin[:version]
523
558
 
524
559
  assert_empty install_result.stderr
525
560
 
@@ -600,21 +635,20 @@ class PluginManagerCliInstall < Minitest::Test
600
635
 
601
636
  def test_install_from_rubygems_latest_with_train_plugin
602
637
  install_result = run_inspec_process_with_this_plugin("plugin install train-test-fixture", post_run: list_after_run)
638
+ skip_windows!
603
639
 
604
640
  success_message = install_result.stdout.split("\n").grep(/installed/).last
605
- skip_windows!
606
641
  refute_nil success_message, "Should find a success message at the end"
607
642
  assert_includes success_message, "train-test-fixture"
608
643
  assert_includes success_message, "0.1.0"
609
644
  assert_includes success_message, "installed from rubygems.org"
610
645
 
611
- list_result = install_result.payload.list_result
612
- itf_line = list_result.stdout.split("\n").grep(/train-test-fixture/).first
613
- refute_nil itf_line, "train-test-fixture should now appear in the output of inspec list"
614
- assert_match(/\s*train-test-fixture\s+0.1.0\s+gem\s+/, itf_line, "list output should show that it is a gem installation with version")
646
+ ttf_plugin = install_result.payload.list_result.detect { |p| p[:name] == "train-test-fixture" }
647
+ refute_nil ttf_plugin, "plugin name should now appear in the output of inspec list"
648
+ assert_equal "gem (user)", ttf_plugin[:type]
649
+ assert_equal "0.1.0", ttf_plugin[:version]
615
650
 
616
651
  assert_empty install_result.stderr
617
-
618
652
  assert_exit_code 0, install_result
619
653
  end
620
654
 
@@ -649,8 +683,8 @@ class PluginManagerCliInstall < Minitest::Test
649
683
  skip "this test requires bundler to pass" unless defined? ::Bundler
650
684
 
651
685
  install_result = run_inspec_process_with_this_plugin("plugin install inspec-test-fixture -v 0.1.1 --log-level debug")
652
-
653
686
  skip_windows!
687
+
654
688
  assert_includes install_result.stdout, "DEBUG"
655
689
 
656
690
  assert_includes install_result.stderr, "can't activate rake"
@@ -684,13 +718,12 @@ class PluginManagerCliUpdate < Minitest::Test
684
718
  assert_includes success_message, "0.2.0"
685
719
  assert_includes success_message, "updated from rubygems.org"
686
720
 
687
- list_result = update_result.payload.list_result
688
- itf_line = list_result.stdout.split("\n").grep(/inspec-test-fixture/).first
689
- refute_nil itf_line, "inspec-test-fixture should appear in the output of inspec list"
690
- assert_match(/\s*inspec-test-fixture\s+0.2.0\s+gem\s+/, itf_line, "list output should show that it is a gem installation with version 0.2.0")
721
+ itf_plugin = update_result.payload.list_result.detect { |p| p[:name] == "inspec-test-fixture" }
722
+ refute_nil itf_plugin, "plugin name should now appear in the output of inspec list"
723
+ assert_equal "gem (user)", itf_plugin[:type]
724
+ assert_equal "0.2.0", itf_plugin[:version]
691
725
 
692
726
  assert_empty update_result.stderr
693
-
694
727
  assert_exit_code 0, update_result
695
728
  end
696
729
 
@@ -769,12 +802,10 @@ class PluginManagerCliUninstall < Minitest::Test
769
802
  assert_includes success_message, "0.1.0"
770
803
  assert_includes success_message, "has been uninstalled"
771
804
 
772
- list_result = uninstall_result.payload.list_result
773
- itf_line = list_result.stdout.split("\n").grep(/inspec-test-fixture/).first
774
- assert_nil itf_line, "inspec-test-fixture should not appear in the output of inspec list"
805
+ itf_plugins = uninstall_result.payload.list_result.select { |p| p[:name] == "inspec-test-fixture" }
806
+ assert_empty itf_plugins, "inspec-test-fixture should not appear in the output of inspec list"
775
807
 
776
808
  assert_empty uninstall_result.stderr
777
-
778
809
  assert_exit_code 0, uninstall_result
779
810
  end
780
811
 
@@ -784,22 +815,19 @@ class PluginManagerCliUninstall < Minitest::Test
784
815
  # This fixture includes a path install for inspec-meaning-of-life
785
816
  copy_in_core_config_dir("test-fixture-1-float", tmp_dir)
786
817
  end
787
-
788
818
  uninstall_result = run_inspec_process_with_this_plugin("plugin uninstall inspec-meaning-of-life", pre_run: pre_block, post_run: list_after_run)
819
+ skip_windows!
789
820
 
790
821
  success_message = uninstall_result.stdout.split("\n").grep(/uninstalled/).last
791
- skip_windows!
792
822
  refute_nil success_message, "Should find a success message at the end"
793
823
  assert_includes success_message, "inspec-meaning-of-life"
794
824
  assert_includes success_message, "path-based plugin install"
795
825
  assert_includes success_message, "has been uninstalled"
796
826
 
797
- list_result = uninstall_result.payload.list_result
798
- itf_line = list_result.stdout.split("\n").grep(/inspec-meaning-of-life/).first
799
- assert_nil itf_line, "inspec-meaning-of-life should not appear in the output of inspec list"
827
+ itf_plugins = uninstall_result.payload.list_result.select { |p| p[:name] == "inspec-meaning-of-life" }
828
+ assert_empty itf_plugins, "inspec-meaning-of-life should not appear in the output of inspec list"
800
829
 
801
830
  assert_empty uninstall_result.stderr
802
-
803
831
  assert_exit_code 0, uninstall_result
804
832
  end
805
833