inspec 4.7.24 → 4.10.4
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/README.md +1 -2
- data/lib/fetchers/git.rb +49 -10
- data/lib/inspec/cli.rb +23 -34
- data/lib/inspec/resources/windows_task.rb +5 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-artifact/test/functional/inspec_artifact_test.rb +7 -8
- data/lib/plugins/inspec-compliance/test/functional/inspec_compliance_test.rb +18 -6
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/profile.rb +0 -12
- data/lib/plugins/inspec-habitat/templates/habitat/plan.sh.erb +1 -78
- data/lib/plugins/inspec-habitat/test/functional/inspec_habitat_test.rb +5 -10
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/test/functional/inspec_plugin_template_test.rb +4 -4
- data/lib/plugins/inspec-init/test/functional/inspec_init_plugin_test.rb +17 -10
- data/lib/plugins/inspec-init/test/functional/inspec_init_profile_test.rb +31 -12
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +106 -69
- data/lib/plugins/inspec-plugin-manager-cli/test/functional/inspec-plugin_test.rb +180 -87
- metadata +2 -6
- data/lib/inspec/utils/latest_version.rb +0 -13
- data/lib/plugins/inspec-habitat/templates/habitat/config/inspec_exec_config.json.erb +0 -25
- data/lib/plugins/inspec-habitat/templates/habitat/default.toml.erb +0 -9
- data/lib/plugins/inspec-habitat/templates/habitat/hooks/run.erb +0 -32
@@ -5,7 +5,6 @@ class ProfileCli < Minitest::Test
|
|
5
5
|
include CorePluginFunctionalHelper
|
6
6
|
|
7
7
|
def setup
|
8
|
-
skip_windows!
|
9
8
|
@tmpdir = Dir.mktmpdir
|
10
9
|
@habitat_profile = File.join(@tmpdir, "habitat-profile")
|
11
10
|
run_inspec_process("init profile " + @habitat_profile)
|
@@ -18,22 +17,18 @@ class ProfileCli < Minitest::Test
|
|
18
17
|
def test_setup_subcommand
|
19
18
|
result = run_inspec_process("habitat profile setup " + @habitat_profile + " --log-level debug")
|
20
19
|
|
21
|
-
# Command runs without error
|
22
|
-
assert_empty result.stderr
|
23
|
-
assert_equal 0, result.exit_status
|
24
|
-
|
25
20
|
# Command creates only expected files
|
26
21
|
base_dir = File.join(@tmpdir, "habitat-profile", "habitat")
|
27
22
|
files = %w{
|
28
|
-
default.toml
|
29
23
|
plan.sh
|
30
|
-
config
|
31
|
-
config/inspec_exec_config.json
|
32
|
-
hooks
|
33
|
-
hooks/run
|
34
24
|
}
|
35
25
|
actual_files = Dir.glob(File.join(base_dir, "**/*"))
|
36
26
|
expected_files = files.map { |x| File.join(base_dir, x) }
|
37
27
|
assert_equal actual_files.sort, expected_files.sort
|
28
|
+
|
29
|
+
# Command runs without error
|
30
|
+
assert_empty result.stderr
|
31
|
+
|
32
|
+
assert_exit_code 0, result
|
38
33
|
end
|
39
34
|
end
|
@@ -35,7 +35,7 @@ describe 'inspec list-resources core' do
|
|
35
35
|
# Some tests through here use minitest Expectations, which attach to all
|
36
36
|
# Objects, and begin with 'must' (positive) or 'wont' (negative)
|
37
37
|
# See http://docs.seattlerb.org/minitest/Minitest/Expectations.html
|
38
|
-
it("should exit successfully") {
|
38
|
+
it("should exit successfully") { assert_exit_code 0, outcome }
|
39
39
|
it("should be silent on stderr") { outcome.stderr.must_be_empty }
|
40
40
|
|
41
41
|
# A selection of core resources, just spot checking.
|
@@ -59,7 +59,7 @@ describe 'inspec list-resources core' do
|
|
59
59
|
let(:outcome) { run_inspec_process_with_this_plugin("listresources core user") }
|
60
60
|
|
61
61
|
# Should be well-behaved...
|
62
|
-
it("should exit successfully") {
|
62
|
+
it("should exit successfully") { assert_exit_code 0, outcome }
|
63
63
|
it("should be silent on stderr") { outcome.stderr.must_be_empty }
|
64
64
|
|
65
65
|
# Here, we want to know it DID match some things, and NOT some others.
|
@@ -79,7 +79,7 @@ describe 'inspec list-resources core' do
|
|
79
79
|
let(:outcome) { run_inspec_process_with_this_plugin("listresources core autogyro") }
|
80
80
|
|
81
81
|
# Should be well-behaved...
|
82
|
-
it("should exit successfully") {
|
82
|
+
it("should exit successfully") { assert_exit_code 0, outcome }
|
83
83
|
it("should be silent on stderr") { outcome.stderr.must_be_empty }
|
84
84
|
|
85
85
|
# Output lines should be just two, for the summary.
|
@@ -99,7 +99,7 @@ describe 'inspec list-resources core' do
|
|
99
99
|
let(:outcome) { run_inspec_process_with_this_plugin('listresources core --no-summary') }
|
100
100
|
|
101
101
|
# Should be well-behaved...
|
102
|
-
it("should exit successfully") {
|
102
|
+
it("should exit successfully") { assert_exit_code 0, outcome }
|
103
103
|
it("should be silent on stderr") { outcome.stderr.must_be_empty }
|
104
104
|
|
105
105
|
# Check for the summary
|
@@ -3,18 +3,18 @@ require_relative "../../../shared/core_plugin_test_helper.rb"
|
|
3
3
|
class InitPluginCli < Minitest::Test
|
4
4
|
include CorePluginFunctionalHelper
|
5
5
|
|
6
|
-
def setup
|
7
|
-
skip_windows!
|
8
|
-
end
|
9
|
-
|
10
6
|
def test_generating_inspec_plugin_correct_prefix_required
|
11
7
|
Dir.mktmpdir do |dir|
|
12
8
|
plugin = "wacky-name"
|
13
9
|
run_result = run_inspec_process("init plugin --no-prompt #{plugin} ", prefix: "cd #{dir} &&")
|
14
|
-
|
15
|
-
|
10
|
+
|
11
|
+
skip_windows!
|
16
12
|
assert_includes run_result.stdout, "ERROR"
|
17
13
|
assert_includes run_result.stdout, "Plugin names must begin with"
|
14
|
+
|
15
|
+
assert_empty run_result.stderr
|
16
|
+
|
17
|
+
assert_exit_code 1, run_result
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -25,12 +25,15 @@ class InitPluginCli < Minitest::Test
|
|
25
25
|
module_name = plugin.sub(/^inspec\-/, "").split("-").map(&:capitalize).join("")
|
26
26
|
|
27
27
|
run_result = run_inspec_process("init plugin --no-prompt #{plugin}", prefix: "cd #{dir} &&")
|
28
|
-
assert_empty run_result.stderr
|
29
28
|
|
30
|
-
|
29
|
+
skip_windows!
|
31
30
|
assert_includes run_result.stdout, "Creating new inspec plugin at"
|
32
31
|
assert_includes run_result.stdout, plugin
|
33
32
|
|
33
|
+
assert_empty run_result.stderr
|
34
|
+
|
35
|
+
assert_exit_code 0, run_result
|
36
|
+
|
34
37
|
# Check generated files and contents.
|
35
38
|
# Each file must exist, and its contents must match each of the regexen given.
|
36
39
|
{
|
@@ -128,11 +131,15 @@ class InitPluginCli < Minitest::Test
|
|
128
131
|
opts += " --module_name FunPlugin"
|
129
132
|
|
130
133
|
run_result = run_inspec_process("init plugin #{plugin} --no-prompt #{opts}", prefix: "cd #{dir} &&")
|
131
|
-
|
132
|
-
|
134
|
+
|
135
|
+
skip_windows!
|
133
136
|
assert_includes run_result.stdout, "Creating new inspec plugin at"
|
134
137
|
assert_includes run_result.stdout, plugin
|
135
138
|
|
139
|
+
assert_empty run_result.stderr
|
140
|
+
|
141
|
+
assert_exit_code 0, run_result
|
142
|
+
|
136
143
|
# Check generated files and contents.
|
137
144
|
# Each file must exist, and its contents must match each of the regexen given.
|
138
145
|
{
|
@@ -4,19 +4,18 @@ require_relative "../../../shared/core_plugin_test_helper.rb"
|
|
4
4
|
class InitCli < Minitest::Test
|
5
5
|
include CorePluginFunctionalHelper
|
6
6
|
|
7
|
-
def setup
|
8
|
-
skip_windows!
|
9
|
-
end
|
10
|
-
|
11
7
|
def test_generating_inspec_profile
|
12
8
|
Dir.mktmpdir do |dir|
|
13
9
|
profile = File.join(dir, "test-profile")
|
14
10
|
out = run_inspec_process("init profile test-profile", prefix: "cd #{dir} &&")
|
15
|
-
|
11
|
+
|
12
|
+
skip_windows!
|
16
13
|
assert_includes out.stdout, "Creating new profile at"
|
17
14
|
assert_includes out.stdout, profile
|
18
15
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
19
16
|
assert_includes Dir.entries(profile).join, "README.md"
|
17
|
+
|
18
|
+
assert_exit_code 0, out
|
20
19
|
end
|
21
20
|
end
|
22
21
|
|
@@ -24,20 +23,26 @@ class InitCli < Minitest::Test
|
|
24
23
|
Dir.mktmpdir do |dir|
|
25
24
|
profile = File.join(dir, "test-profile")
|
26
25
|
out = run_inspec_process("init profile --platform os test-profile", prefix: "cd #{dir} &&")
|
27
|
-
|
26
|
+
|
27
|
+
skip_windows!
|
28
28
|
assert_includes out.stdout, "Creating new profile at"
|
29
29
|
assert_includes out.stdout, profile
|
30
30
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
31
31
|
assert_includes Dir.entries(profile).join, "README.md"
|
32
|
+
|
33
|
+
assert_exit_code 0, out
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
37
|
def test_generating_inspec_profile_with_bad_platform
|
36
38
|
Dir.mktmpdir do |dir|
|
37
39
|
out = run_inspec_process("init profile --platform nonesuch test-profile", prefix: "cd #{dir} &&")
|
38
|
-
|
40
|
+
|
41
|
+
skip_windows!
|
39
42
|
assert_includes out.stdout, "Unable to generate profile"
|
40
43
|
assert_includes out.stdout, "No template available for platform 'nonesuch'"
|
44
|
+
|
45
|
+
assert_exit_code 1, out
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
@@ -45,10 +50,12 @@ class InitCli < Minitest::Test
|
|
45
50
|
Dir.mktmpdir do |dir|
|
46
51
|
profile = dir + "/test/deeper/profile"
|
47
52
|
out = run_inspec_process("init profile test/deeper/profile", prefix: "cd #{dir} &&")
|
48
|
-
|
53
|
+
skip_windows!
|
49
54
|
assert_equal true, File.exist?(profile)
|
50
55
|
profile = YAML.load_file("#{profile}/inspec.yml")
|
51
56
|
assert_equal "profile", profile["name"]
|
57
|
+
|
58
|
+
assert_exit_code 0, out
|
52
59
|
end
|
53
60
|
end
|
54
61
|
|
@@ -56,11 +63,14 @@ class InitCli < Minitest::Test
|
|
56
63
|
Dir.mktmpdir do |dir|
|
57
64
|
profile = File.join(dir, "test-gcp-profile")
|
58
65
|
out = run_inspec_process("init profile --platform gcp test-gcp-profile", prefix: "cd #{dir} &&")
|
59
|
-
|
66
|
+
|
67
|
+
skip_windows!
|
60
68
|
assert_includes out.stdout, "Creating new profile at"
|
61
69
|
assert_includes out.stdout, profile
|
62
70
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
63
71
|
assert_includes Dir.entries(profile).join, "README.md"
|
72
|
+
|
73
|
+
assert_exit_code 0, out
|
64
74
|
end
|
65
75
|
end
|
66
76
|
|
@@ -68,11 +78,14 @@ class InitCli < Minitest::Test
|
|
68
78
|
Dir.mktmpdir do |dir|
|
69
79
|
profile = File.join(dir, "test-aws-profile")
|
70
80
|
out = run_inspec_process("init profile --platform aws test-aws-profile", prefix: "cd #{dir} &&")
|
71
|
-
|
81
|
+
|
82
|
+
skip_windows!
|
72
83
|
assert_includes out.stdout, "Creating new profile at"
|
73
84
|
assert_includes out.stdout, profile
|
74
85
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
75
86
|
assert_includes Dir.entries(profile).join, "README.md"
|
87
|
+
|
88
|
+
assert_exit_code 0, out
|
76
89
|
end
|
77
90
|
end
|
78
91
|
|
@@ -80,11 +93,14 @@ class InitCli < Minitest::Test
|
|
80
93
|
Dir.mktmpdir do |dir|
|
81
94
|
profile = File.join(dir, "test-azure-profile")
|
82
95
|
out = run_inspec_process("init profile --platform azure test-azure-profile", prefix: "cd #{dir} &&")
|
83
|
-
|
96
|
+
|
97
|
+
skip_windows!
|
84
98
|
assert_includes out.stdout, "Creating new profile at"
|
85
99
|
assert_includes out.stdout, profile
|
86
100
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
87
101
|
assert_includes Dir.entries(profile).join, "README.md"
|
102
|
+
|
103
|
+
assert_exit_code 0, out
|
88
104
|
end
|
89
105
|
end
|
90
106
|
|
@@ -92,11 +108,14 @@ class InitCli < Minitest::Test
|
|
92
108
|
Dir.mktmpdir do |dir|
|
93
109
|
profile = File.join(dir, "test-os-profile")
|
94
110
|
out = run_inspec_process("init profile --platform os test-os-profile", prefix: "cd #{dir} &&")
|
95
|
-
|
111
|
+
|
112
|
+
skip_windows!
|
96
113
|
assert_includes out.stdout, "Creating new profile at"
|
97
114
|
assert_includes out.stdout, profile
|
98
115
|
assert_includes Dir.entries(profile).join, "inspec.yml"
|
99
116
|
assert_includes Dir.entries(profile).join, "README.md"
|
117
|
+
|
118
|
+
assert_exit_code 0, out
|
100
119
|
end
|
101
120
|
end
|
102
121
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "term/ansicolor"
|
2
1
|
require "pathname"
|
3
2
|
require "inspec/plugin/v2"
|
4
3
|
require "inspec/plugin/v2/installer"
|
@@ -7,7 +6,6 @@ require "inspec/dist"
|
|
7
6
|
module InspecPlugins
|
8
7
|
module PluginManager
|
9
8
|
class CliCommand < Inspec.plugin(2, :cli_command)
|
10
|
-
include Term::ANSIColor
|
11
9
|
include Inspec::Dist
|
12
10
|
|
13
11
|
subcommand_desc "plugin SUBCOMMAND", "Manage #{PRODUCT_NAME} and Train plugins"
|
@@ -22,15 +20,17 @@ module InspecPlugins
|
|
22
20
|
plugin_statuses = Inspec::Plugin::V2::Registry.instance.plugin_statuses
|
23
21
|
plugin_statuses.reject! { |s| %i{core bundle}.include?(s.installation_type) } unless options[:all]
|
24
22
|
|
25
|
-
# TODO: ui object support
|
26
23
|
puts
|
27
|
-
|
28
|
-
|
24
|
+
ui.bold(format(" %-30s%-10s%-8s%-6s", "Plugin Name", "Version", "Via", "ApiVer"))
|
25
|
+
ui.line
|
29
26
|
plugin_statuses.sort_by(&:name).each do |status|
|
30
|
-
|
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))
|
31
31
|
end
|
32
|
-
|
33
|
-
|
32
|
+
ui.line
|
33
|
+
ui.plain(" #{plugin_statuses.count} plugin(s) total")
|
34
34
|
puts
|
35
35
|
end
|
36
36
|
|
@@ -59,23 +59,22 @@ module InspecPlugins
|
|
59
59
|
search_results.delete("train-test-fixture")
|
60
60
|
end
|
61
61
|
|
62
|
-
# TODO: ui object support
|
63
62
|
puts
|
64
|
-
|
65
|
-
|
63
|
+
ui.bold(format(" %-30s%-50s", "Plugin Name", "Versions Available"))
|
64
|
+
ui.line
|
66
65
|
search_results.keys.sort.each do |plugin_name|
|
67
66
|
versions = options[:all] ? search_results[plugin_name] : [search_results[plugin_name].first]
|
68
67
|
versions = "(" + versions.join(", ") + ")"
|
69
|
-
|
68
|
+
ui.plain(format(" %-30s%-50s", plugin_name, versions))
|
70
69
|
end
|
71
|
-
|
72
|
-
|
70
|
+
ui.line
|
71
|
+
ui.plain(" #{search_results.count} plugin(s) found")
|
73
72
|
puts
|
74
73
|
|
75
|
-
exit
|
74
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR if search_results.empty?
|
76
75
|
rescue Inspec::Plugin::V2::SearchError => ex
|
77
76
|
Inspec::Log.error ex.message
|
78
|
-
exit
|
77
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
79
78
|
end
|
80
79
|
|
81
80
|
#==================================================================#
|
@@ -119,13 +118,14 @@ module InspecPlugins
|
|
119
118
|
begin
|
120
119
|
installer.update(plugin_name)
|
121
120
|
rescue Inspec::Plugin::V2::UpdateError => ex
|
122
|
-
|
123
|
-
exit
|
121
|
+
ui.plain("#{ui.red('Update error:')} #{ex.message} - update failed")
|
122
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
124
123
|
end
|
125
124
|
post_update_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
|
126
125
|
new_version = (post_update_versions - pre_update_versions).first
|
127
126
|
|
128
|
-
|
127
|
+
ui.bold(plugin_name + " plugin, version #{old_version} -> " \
|
128
|
+
"#{new_version}, updated from rubygems.org")
|
129
129
|
end
|
130
130
|
|
131
131
|
#--------------------------
|
@@ -144,9 +144,9 @@ module InspecPlugins
|
|
144
144
|
def uninstall(plugin_name)
|
145
145
|
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
|
146
146
|
unless status
|
147
|
-
|
148
|
-
|
149
|
-
exit
|
147
|
+
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} is not " \
|
148
|
+
"installed - uninstall failed")
|
149
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
150
150
|
end
|
151
151
|
installer = Inspec::Plugin::V2::Installer.instance
|
152
152
|
|
@@ -156,11 +156,13 @@ module InspecPlugins
|
|
156
156
|
installer.uninstall(plugin_name)
|
157
157
|
|
158
158
|
if status.installation_type == :path
|
159
|
-
|
159
|
+
ui.bold(plugin_name + " path-based plugin install has been " \
|
160
|
+
"uninstalled")
|
160
161
|
else
|
161
|
-
|
162
|
+
ui.bold(plugin_name + " plugin, version #{old_version}, has " \
|
163
|
+
"been uninstalled")
|
162
164
|
end
|
163
|
-
exit
|
165
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
164
166
|
end
|
165
167
|
|
166
168
|
private
|
@@ -172,8 +174,8 @@ module InspecPlugins
|
|
172
174
|
|
173
175
|
def install_from_gemfile(gem_file)
|
174
176
|
unless File.exist? gem_file
|
175
|
-
|
176
|
-
exit
|
177
|
+
ui.red("No such plugin gem file #{gem_file} - installation failed.")
|
178
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
177
179
|
end
|
178
180
|
|
179
181
|
plugin_name_parts = File.basename(gem_file, ".gem").split("-")
|
@@ -183,14 +185,15 @@ module InspecPlugins
|
|
183
185
|
|
184
186
|
installer.install(plugin_name, gem_file: gem_file)
|
185
187
|
|
186
|
-
|
187
|
-
|
188
|
+
ui.bold("#{plugin_name} plugin, version #{version}, installed from " \
|
189
|
+
"local .gem file")
|
190
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
188
191
|
end
|
189
192
|
|
190
193
|
def install_from_path(path)
|
191
194
|
unless File.exist? path
|
192
|
-
|
193
|
-
exit
|
195
|
+
ui.red("No such source code path #{path} - installation failed.")
|
196
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
194
197
|
end
|
195
198
|
|
196
199
|
plugin_name = File.basename(path, ".rb")
|
@@ -204,8 +207,10 @@ module InspecPlugins
|
|
204
207
|
|
205
208
|
# Already installed?
|
206
209
|
if registry.known_plugin?(plugin_name.to_sym)
|
207
|
-
|
208
|
-
|
210
|
+
ui.red("Plugin already installed - #{plugin_name} - Use '#{EXEC_NAME} " \
|
211
|
+
"plugin list' to see previously installed plugin - " \
|
212
|
+
"installation failed.")
|
213
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
209
214
|
end
|
210
215
|
|
211
216
|
# Can we figure out how to load it?
|
@@ -217,8 +222,9 @@ module InspecPlugins
|
|
217
222
|
# OK, install it!
|
218
223
|
installer.install(plugin_name, path: entry_point)
|
219
224
|
|
220
|
-
|
221
|
-
|
225
|
+
ui.bold("#{plugin_name} plugin installed via source path reference, " \
|
226
|
+
"resolved to entry point #{entry_point}")
|
227
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
222
228
|
end
|
223
229
|
|
224
230
|
# Rationale for rubocop variances: It's a heuristics method, and will be full of
|
@@ -229,6 +235,7 @@ module InspecPlugins
|
|
229
235
|
given = given.expand_path # Resolve any relative paths
|
230
236
|
name_regex = /^(inspec|train)-/
|
231
237
|
versioned_regex = /^(inspec|train)-[a-z0-9\-\_]+-\d+\.\d+\.\d+$/
|
238
|
+
sha_ref_regex = /^(inspec|train)-[a-z0-9\-\_]+-[0-9a-f]{5,40}$/
|
232
239
|
|
233
240
|
# What are the last four things like?
|
234
241
|
parts = [
|
@@ -257,14 +264,14 @@ module InspecPlugins
|
|
257
264
|
# In that case, we'll have a version on the plugin name in part 0
|
258
265
|
# /home/you/.gems/2.4.0/gems/inspec-something-3.45.1/lib/inspec-something.rb
|
259
266
|
# parts index: ^0^ ^1^ ^2^ ^3^
|
260
|
-
if parts[0] =~ versioned_regex && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3] == ".rb"
|
267
|
+
if (parts[0] =~ versioned_regex || parts[0] =~ sha_ref_regex) && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3] == ".rb"
|
261
268
|
return given.to_s
|
262
269
|
end
|
263
270
|
|
264
271
|
# Case 4: Like case 3, but missing the .rb
|
265
272
|
# /home/you/.gems/2.4.0/gems/inspec-something-3.45.1/lib/inspec-something
|
266
273
|
# parts index: ^0^ ^1^ ^2^ ^3^ (empty)
|
267
|
-
if parts[0] =~ versioned_regex && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3].empty?
|
274
|
+
if (parts[0] =~ versioned_regex || parts[0] =~ sha_ref_regex) && parts[1] == "lib" && parts[0].start_with?(parts[2]) && parts[3].empty?
|
268
275
|
return given.to_s + ".rb"
|
269
276
|
end
|
270
277
|
|
@@ -279,8 +286,10 @@ module InspecPlugins
|
|
279
286
|
|
280
287
|
# Well, if we got here, parts[2] matches an inspec/train prefix, but we have no idea about anything.
|
281
288
|
# Give up.
|
282
|
-
|
283
|
-
|
289
|
+
ui.red("Unrecognizable plugin structure - #{parts[2]} - When " \
|
290
|
+
"installing from a path, please provide the path of the " \
|
291
|
+
"entry point file - installation failed.")
|
292
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
284
293
|
end
|
285
294
|
|
286
295
|
def install_from_path__probe_load(entry_point, plugin_name)
|
@@ -288,9 +297,11 @@ module InspecPlugins
|
|
288
297
|
begin
|
289
298
|
require entry_point
|
290
299
|
rescue LoadError => ex
|
291
|
-
|
292
|
-
|
293
|
-
|
300
|
+
ui.red("Plugin contains errors - #{plugin_name} - Encountered " \
|
301
|
+
"errors while trying to test load the plugin entry point, " \
|
302
|
+
"resolved to #{entry_point} - installation failed")
|
303
|
+
ui.plain ex.message
|
304
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
294
305
|
end
|
295
306
|
|
296
307
|
# OK, the wheels didn't fall off. But is it a plugin?
|
@@ -299,13 +310,19 @@ module InspecPlugins
|
|
299
310
|
# And the registry is keyed on Strings
|
300
311
|
registry_key = plugin_name.to_s.sub(/^train-/, "")
|
301
312
|
unless Train::Plugins.registry.key?(registry_key)
|
302
|
-
|
303
|
-
|
313
|
+
ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
|
314
|
+
"probe-loading the supposed plugin, it did not register " \
|
315
|
+
"itself to Train. Ensure something inherits from " \
|
316
|
+
"'Train.plugin(1)' - installation failed.")
|
317
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
304
318
|
end
|
305
319
|
else
|
306
320
|
unless registry.known_plugin?(plugin_name.to_sym)
|
307
|
-
|
308
|
-
|
321
|
+
ui.red("Does not appear to be a plugin - #{plugin_name} - After " \
|
322
|
+
"probe-loading the supposed plugin, it did not register " \
|
323
|
+
"itself to InSpec. Ensure something inherits from " \
|
324
|
+
"'Inspec.plugin(2)' - installation failed.")
|
325
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
309
326
|
end
|
310
327
|
end
|
311
328
|
end
|
@@ -325,8 +342,9 @@ module InspecPlugins
|
|
325
342
|
post_installed_versions = installer.list_installed_plugin_gems.select { |spec| spec.name == plugin_name }.map { |spec| spec.version.to_s }
|
326
343
|
new_version = (post_installed_versions - pre_installed_versions).first
|
327
344
|
|
328
|
-
|
329
|
-
|
345
|
+
ui.bold("#{plugin_name} plugin, version #{new_version}, installed " \
|
346
|
+
"from rubygems.org")
|
347
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
330
348
|
end
|
331
349
|
|
332
350
|
def install_from_remote_gem_verson_preflight_check(plugin_name, requested_version, pre_installed_versions)
|
@@ -348,38 +366,50 @@ module InspecPlugins
|
|
348
366
|
they_explicitly_asked_for_a_version = !options[:version].nil?
|
349
367
|
what_we_would_install_is_already_installed = pre_installed_versions.include?(requested_version)
|
350
368
|
if what_we_would_install_is_already_installed && they_explicitly_asked_for_a_version
|
351
|
-
|
369
|
+
ui.red("Plugin already installed at requested version - plugin " \
|
370
|
+
"#{plugin_name} #{requested_version} - refusing to install.")
|
352
371
|
elsif what_we_would_install_is_already_installed && !they_explicitly_asked_for_a_version
|
353
|
-
|
372
|
+
ui.red("Plugin already installed at latest version - plugin " \
|
373
|
+
"#{plugin_name} #{requested_version} - refusing to install.")
|
354
374
|
else
|
355
375
|
# There are existing versions installed, but none of them are what was requested
|
356
|
-
|
376
|
+
ui.red("Update required - plugin #{plugin_name}, requested " \
|
377
|
+
"#{requested_version}, have " \
|
378
|
+
"#{pre_installed_versions.join(', ')}; use `inspec " \
|
379
|
+
"plugin update` - refusing to install.")
|
357
380
|
end
|
358
381
|
|
359
|
-
exit
|
382
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
360
383
|
end
|
361
384
|
|
362
385
|
# Rationale for RuboCop variance: This is a one-line method with heavy UX-focused error handling.
|
363
386
|
def install_attempt_install(plugin_name) # rubocop: disable Metrics/AbcSize
|
364
387
|
installer.install(plugin_name, version: options[:version])
|
365
388
|
rescue Inspec::Plugin::V2::PluginExcludedError => ex
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
389
|
+
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: " +
|
393
|
+
File.join(Inspec.src_root, "etc", "plugin_filters.json"))
|
394
|
+
ui.plain("If you disagree with this determination, please accept " \
|
395
|
+
"our apologies for the misunderstanding, and open an issue " \
|
396
|
+
"at https://github.com/inspec/inspec/issues/new")
|
397
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
371
398
|
rescue Inspec::Plugin::V2::InstallError
|
372
399
|
raise if Inspec::Log.level == :debug
|
373
400
|
|
374
401
|
results = installer.search(plugin_name, exact: true)
|
375
402
|
if results.empty?
|
376
|
-
|
403
|
+
ui.red("No such plugin gem #{plugin_name} could be found on " \
|
404
|
+
"rubygems.org - installation failed.")
|
377
405
|
elsif options[:version] && !results[plugin_name].include?(options[:version])
|
378
|
-
|
406
|
+
ui.red("No such version - #{plugin_name} exists, but no such " \
|
407
|
+
"version #{options[:version]} found on rubygems.org - " \
|
408
|
+
"installation failed.")
|
379
409
|
else
|
380
|
-
|
410
|
+
ui.red("Unknown error occured - installation failed.")
|
381
411
|
end
|
382
|
-
exit
|
412
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
383
413
|
end
|
384
414
|
|
385
415
|
#==================================================================#
|
@@ -390,11 +420,14 @@ module InspecPlugins
|
|
390
420
|
# Check for path install
|
391
421
|
status = Inspec::Plugin::V2::Registry.instance[plugin_name.to_sym]
|
392
422
|
if !status
|
393
|
-
|
394
|
-
exit
|
423
|
+
ui.plain("#{ui.red('No such plugin installed:')} #{plugin_name} - update failed")
|
424
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
395
425
|
elsif status.installation_type == :path
|
396
|
-
|
397
|
-
|
426
|
+
ui.plain("#{ui.red('Cannot update path-based install:')} " \
|
427
|
+
"#{plugin_name} is installed via path reference; " \
|
428
|
+
"use `inspec plugin uninstall` to remove - refusing to" \
|
429
|
+
"update")
|
430
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
398
431
|
end
|
399
432
|
end
|
400
433
|
|
@@ -403,8 +436,10 @@ module InspecPlugins
|
|
403
436
|
latest_version = latest_version[plugin_name]&.last
|
404
437
|
|
405
438
|
if pre_update_versions.include?(latest_version)
|
406
|
-
|
407
|
-
|
439
|
+
ui.plain("#{ui.red('Already installed at latest version:')} " \
|
440
|
+
"#{plugin_name} is at #{latest_version}, which the " \
|
441
|
+
"latest - refusing to update")
|
442
|
+
ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
|
408
443
|
end
|
409
444
|
end
|
410
445
|
|
@@ -421,8 +456,10 @@ module InspecPlugins
|
|
421
456
|
|
422
457
|
def check_plugin_name(plugin_name, action)
|
423
458
|
unless plugin_name =~ /^(inspec|train)-/
|
424
|
-
|
425
|
-
|
459
|
+
ui.red("Invalid plugin name - #{plugin_name} - All inspec " \
|
460
|
+
"plugins must begin with either 'inspec-' or 'train-' " \
|
461
|
+
"- #{action} failed.")
|
462
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
426
463
|
end
|
427
464
|
end
|
428
465
|
|