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.
- checksums.yaml +4 -4
- data/etc/plugin_filters.json +0 -4
- data/lib/fetchers/git.rb +2 -0
- data/lib/inspec/base_cli.rb +2 -0
- data/lib/inspec/cli.rb +2 -2
- data/lib/inspec/config.rb +49 -2
- data/lib/inspec/input_registry.rb +30 -0
- data/lib/inspec/metadata.rb +4 -0
- data/lib/inspec/plugin/v1/plugin_types/resource.rb +5 -11
- data/lib/inspec/plugin/v2/filter.rb +33 -0
- data/lib/inspec/plugin/v2/installer.rb +10 -7
- data/lib/inspec/plugin/v2/loader.rb +64 -20
- data/lib/inspec/profile.rb +12 -2
- data/lib/inspec/resources.rb +1 -0
- data/lib/inspec/resources/postfix_conf.rb +31 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +88 -53
- data/lib/plugins/inspec-plugin-manager-cli/test/functional/inspec-plugin_test.rb +125 -97
- data/lib/plugins/inspec-plugin-manager-cli/test/unit/cli_args_test.rb +8 -6
- data/lib/source_readers/inspec.rb +14 -12
- metadata +3 -2
data/lib/inspec/profile.rb
CHANGED
@@ -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
|
-
|
131
|
-
|
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 =
|
data/lib/inspec/resources.rb
CHANGED
@@ -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
|
data/lib/inspec/version.rb
CHANGED
@@ -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: "
|
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
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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.
|
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.
|
90
|
+
ui.plain_line(format(" %-30s%-50s", plugin_name, versions))
|
69
91
|
end
|
70
92
|
ui.line
|
71
|
-
ui.
|
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.
|
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.
|
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.
|
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(
|
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.
|
392
|
-
ui.
|
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.
|
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.
|
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.
|
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.
|
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 :
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
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 =
|
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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
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
|
-
|
114
|
+
plugins_seen = parse_plugin_list_lines(result.stdout)
|
97
115
|
|
98
|
-
#
|
99
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
120
|
-
#
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
143
|
-
#
|
144
|
-
# train-test-fixture 0.1.0 gem
|
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
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
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
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
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
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
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
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
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
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
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
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
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
|
-
|
773
|
-
|
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
|
-
|
798
|
-
|
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
|
|