inspec-core 5.22.29 → 6.6.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/Chef-EULA +9 -0
- data/Gemfile +10 -1
- data/etc/features.sig +6 -0
- data/etc/features.yaml +94 -0
- data/inspec-core.gemspec +14 -5
- data/lib/inspec/backend.rb +2 -0
- data/lib/inspec/base_cli.rb +80 -4
- data/lib/inspec/cached_fetcher.rb +24 -3
- data/lib/inspec/cli.rb +300 -230
- data/lib/inspec/config.rb +24 -2
- data/lib/inspec/dependencies/cache.rb +33 -0
- data/lib/inspec/enhanced_outcomes.rb +1 -0
- data/lib/inspec/errors.rb +5 -0
- data/lib/inspec/exceptions.rb +2 -0
- data/lib/inspec/feature/config.rb +75 -0
- data/lib/inspec/feature/runner.rb +26 -0
- data/lib/inspec/feature.rb +34 -0
- data/lib/inspec/fetcher/git.rb +5 -0
- data/lib/inspec/globals.rb +6 -0
- data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +7 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +30 -2
- data/lib/inspec/profile.rb +373 -12
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters.rb +67 -54
- data/lib/inspec/resources/security_policy.rb +7 -2
- data/lib/inspec/run_data.rb +7 -5
- data/lib/inspec/runner.rb +34 -5
- data/lib/inspec/runner_rspec.rb +12 -9
- data/lib/inspec/secrets/yaml.rb +9 -3
- data/lib/inspec/shell.rb +10 -0
- data/lib/inspec/ui.rb +4 -0
- data/lib/inspec/utils/licensing_config.rb +9 -0
- data/lib/inspec/utils/profile_ast_helpers.rb +372 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +68 -27
- data/lib/inspec.rb +2 -1
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +189 -168
- data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +10 -3
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +23 -21
- data/lib/plugins/inspec-init/lib/inspec-init/cli_profile.rb +15 -13
- data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +15 -13
- data/lib/plugins/inspec-license/README.md +16 -0
- data/lib/plugins/inspec-license/inspec-license.gemspec +6 -0
- data/lib/plugins/inspec-license/lib/inspec-license/cli.rb +26 -0
- data/lib/plugins/inspec-license/lib/inspec-license.rb +14 -0
- data/lib/plugins/inspec-parallel/README.md +27 -0
- data/lib/plugins/inspec-parallel/inspec-parallel.gemspec +6 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/child_status_reporter.rb +61 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/cli.rb +39 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/command.rb +219 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/runner.rb +265 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/base.rb +24 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/silent.rb +7 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/status.rb +124 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/text.rb +23 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel/validator.rb +170 -0
- data/lib/plugins/inspec-parallel/lib/inspec-parallel.rb +18 -0
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +7 -6
- data/lib/plugins/inspec-reporter-html2/templates/default.js +6 -6
- data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +6 -2
- data/lib/plugins/inspec-sign/lib/inspec-sign/cli.rb +11 -4
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +6 -13
- metadata +54 -13
data/lib/inspec/cli.rb
CHANGED
@@ -6,6 +6,7 @@ require "inspec/backend"
|
|
6
6
|
require "inspec/dependencies/cache"
|
7
7
|
require "inspec/utils/json_profile_summary"
|
8
8
|
require "inspec/utils/yaml_profile_summary"
|
9
|
+
require "inspec/feature"
|
9
10
|
|
10
11
|
module Inspec # TODO: move this somewhere "better"?
|
11
12
|
autoload :BaseCLI, "inspec/base_cli"
|
@@ -61,6 +62,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
61
62
|
require "license_acceptance/cli_flags/thor"
|
62
63
|
include LicenseAcceptance::CLIFlags::Thor
|
63
64
|
|
65
|
+
if Inspec::Dist::EXEC_NAME == "inspec"
|
66
|
+
require "chef-licensing/cli_flags/thor"
|
67
|
+
include ChefLicensing::CLIFlags::Thor
|
68
|
+
end
|
69
|
+
|
64
70
|
desc "json PATH", "read all tests in the PATH and generate a JSON summary."
|
65
71
|
option :output, aliases: :o, type: :string,
|
66
72
|
desc: "Save the created profile to a path."
|
@@ -68,11 +74,19 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
68
74
|
desc: "A list of controls to include. Ignore all other tests."
|
69
75
|
option :tags, type: :array,
|
70
76
|
desc: "A list of tags to filter controls and include only those. Ignore all other tests."
|
77
|
+
option :legacy_export, type: :boolean, default: false,
|
78
|
+
desc: "Run with legacy export."
|
71
79
|
profile_options
|
72
80
|
def json(target)
|
73
|
-
|
74
|
-
|
75
|
-
|
81
|
+
Inspec.with_feature("inspec-cli-json") {
|
82
|
+
# Config initialisation is needed before deprecation warning can be issued
|
83
|
+
# Deprecator calls config get method to fetch the config value
|
84
|
+
# Without config initialisation, the config value is not set and hence calling config get through deprecator will set the value of config as blank, making options of json command inaccessible.
|
85
|
+
config
|
86
|
+
# This deprecation warning is ignored currently.
|
87
|
+
Inspec.deprecate(:renamed_to_inspec_export)
|
88
|
+
export(target, true)
|
89
|
+
}
|
76
90
|
end
|
77
91
|
|
78
92
|
desc "export PATH", "read the profile in PATH and generate a summary in the given format."
|
@@ -86,63 +100,70 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
86
100
|
desc: "For --what=profile, a list of controls to include. Ignore all other tests."
|
87
101
|
option :tags, type: :array,
|
88
102
|
desc: "For --what=profile, a list of tags to filter controls and include only those. Ignore all other tests."
|
103
|
+
option :legacy_export, type: :boolean, default: false,
|
104
|
+
desc: "Run with legacy export."
|
89
105
|
profile_options
|
90
106
|
def export(target, as_json = false)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
107
|
+
Inspec.with_feature("inspec-cli-export") {
|
108
|
+
begin
|
109
|
+
o = config
|
110
|
+
diagnose(o)
|
111
|
+
o["log_location"] = $stderr
|
112
|
+
configure_logger(o)
|
113
|
+
|
114
|
+
# using dup to resolve "can't modify frozen String" error.
|
115
|
+
what = o[:what].dup || "profile"
|
116
|
+
what.downcase!
|
117
|
+
raise Inspec::Error.new("Unrecognized option '#{what}' for --what - expected one of profile, readme, or metadata.") unless %w{profile readme metadata}.include?(what)
|
118
|
+
|
119
|
+
default_format_for_what = {
|
120
|
+
"profile" => "yaml",
|
121
|
+
"metadata" => "raw",
|
122
|
+
"readme" => "raw",
|
123
|
+
}
|
124
|
+
valid_formats_for_what = {
|
125
|
+
"profile" => %w{yaml json},
|
126
|
+
"metadata" => %w{yaml raw}, # not going to argue
|
127
|
+
"readme" => ["raw"],
|
128
|
+
}
|
129
|
+
format = o[:format] || default_format_for_what[what]
|
130
|
+
# default is json if we were called as old json command
|
131
|
+
format = "json" if as_json
|
132
|
+
raise Inspec::Error.new("Invalid option '#{format}' for --format and --what combination") unless format && valid_formats_for_what[what].include?(format)
|
133
|
+
|
134
|
+
o[:backend] = Inspec::Backend.create(Inspec::Config.mock)
|
135
|
+
o[:check_mode] = true
|
136
|
+
o[:vendor_cache] = Inspec::Cache.new(o[:vendor_cache])
|
137
|
+
profile = Inspec::Profile.for_target(target, o)
|
138
|
+
dst = o[:output].to_s
|
139
|
+
|
140
|
+
case what
|
141
|
+
when "profile"
|
142
|
+
profile_info = o[:legacy_export] ? profile.info : profile.info_from_parse
|
143
|
+
if format == "json"
|
144
|
+
require "json" unless defined?(JSON)
|
145
|
+
# Write JSON
|
146
|
+
Inspec::Utils::JsonProfileSummary.produce_json(
|
147
|
+
info: profile_info,
|
148
|
+
write_path: dst
|
149
|
+
)
|
150
|
+
elsif format == "yaml"
|
151
|
+
Inspec::Utils::YamlProfileSummary.produce_yaml(
|
152
|
+
info: profile_info,
|
153
|
+
write_path: dst
|
154
|
+
)
|
155
|
+
end
|
156
|
+
when "readme"
|
157
|
+
out = dst.empty? ? $stdout : File.open(dst, "w")
|
158
|
+
out.write(profile.readme)
|
159
|
+
when "metadata"
|
160
|
+
out = dst.empty? ? $stdout : File.open(dst, "w")
|
161
|
+
out.write(profile.metadata_src)
|
162
|
+
end
|
163
|
+
rescue StandardError => e
|
164
|
+
pretty_handle_exception(e)
|
136
165
|
end
|
137
|
-
|
138
|
-
out = dst.empty? ? $stdout : File.open(dst, "w")
|
139
|
-
out.write(profile.readme)
|
140
|
-
when "metadata"
|
141
|
-
out = dst.empty? ? $stdout : File.open(dst, "w")
|
142
|
-
out.write(profile.metadata_src)
|
143
|
-
end
|
144
|
-
rescue StandardError => e
|
145
|
-
pretty_handle_exception(e)
|
166
|
+
}
|
146
167
|
end
|
147
168
|
|
148
169
|
desc "check PATH", "Verify the metadata in the `inspec.yml` file,\
|
@@ -152,82 +173,89 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
152
173
|
desc: "The output format to use. Valid values: `json` and `doc`. Default value: `doc`."
|
153
174
|
option :with_cookstyle, type: :boolean,
|
154
175
|
desc: "Enable or disable cookstyle checks.", default: false
|
176
|
+
option :legacy_check, type: :boolean, default: false,
|
177
|
+
desc: "Run with legacy check."
|
155
178
|
profile_options
|
156
179
|
def check(path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
prepared_string = format("%-12s %s",
|
176
|
-
"#{item.to_s.capitalize} :",
|
177
|
-
result[:summary][item.to_sym])
|
178
|
-
ui.plain_line(prepared_string)
|
179
|
-
end
|
180
|
-
puts
|
181
|
-
|
182
|
-
enable_offenses = !Inspec.locally_windows? # See 5723
|
183
|
-
if result[:errors].empty? && result[:warnings].empty? && result[:offenses].empty?
|
184
|
-
if enable_offenses
|
185
|
-
ui.plain_line("No errors, warnings, or offenses")
|
180
|
+
Inspec.with_feature("inspec-cli-check") {
|
181
|
+
begin
|
182
|
+
o = config
|
183
|
+
diagnose(o)
|
184
|
+
o["log_location"] ||= STDERR if o["format"] == "json"
|
185
|
+
o["log_level"] ||= "warn"
|
186
|
+
configure_logger(o)
|
187
|
+
|
188
|
+
o[:backend] = Inspec::Backend.create(Inspec::Config.mock)
|
189
|
+
o[:check_mode] = true
|
190
|
+
o[:vendor_cache] = Inspec::Cache.new(o[:vendor_cache])
|
191
|
+
|
192
|
+
# run check
|
193
|
+
profile = Inspec::Profile.for_target(path, o)
|
194
|
+
result = o[:legacy_check] ? profile.legacy_check : profile.check
|
195
|
+
|
196
|
+
if o["format"] == "json"
|
197
|
+
puts JSON.generate(result)
|
186
198
|
else
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
199
|
+
%w{location profile controls timestamp valid}.each do |item|
|
200
|
+
prepared_string = format("%-12s %s",
|
201
|
+
"#{item.to_s.capitalize} :",
|
202
|
+
result[:summary][item.to_sym])
|
203
|
+
ui.plain_line(prepared_string)
|
204
|
+
end
|
205
|
+
puts
|
206
|
+
|
207
|
+
enable_offenses = !Inspec.locally_windows? # See 5723
|
208
|
+
if result[:errors].empty? && result[:warnings].empty? && result[:offenses].empty?
|
209
|
+
if enable_offenses
|
210
|
+
ui.plain_line("No errors, warnings, or offenses")
|
211
|
+
else
|
212
|
+
ui.plain_line("No errors or warnings")
|
213
|
+
end
|
214
|
+
else
|
215
|
+
item_msg = lambda { |item|
|
216
|
+
pos = [item[:file], item[:line], item[:column]].compact.join(":")
|
217
|
+
pos.empty? ? item[:msg] : pos + ": " + item[:msg]
|
218
|
+
}
|
194
219
|
|
195
|
-
|
196
|
-
|
220
|
+
result[:errors].each { |item| ui.red " #{Inspec::UI::GLYPHS[:script_x]} #{item_msg.call(item)}\n" }
|
221
|
+
result[:warnings].each { |item| ui.yellow " ! #{item_msg.call(item)}\n" }
|
197
222
|
|
198
|
-
|
223
|
+
puts
|
199
224
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
225
|
+
if enable_offenses && !result[:offenses].empty?
|
226
|
+
puts "Offenses:\n"
|
227
|
+
result[:offenses].each { |item| ui.cyan(" #{Inspec::UI::GLYPHS[:script_x]} #{item_msg.call(item)}\n\n") }
|
228
|
+
end
|
204
229
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
230
|
+
offenses = ui.cyan("#{result[:offenses].length} offenses", print: false)
|
231
|
+
errors = ui.red("#{result[:errors].length} errors", print: false)
|
232
|
+
warnings = ui.yellow("#{result[:warnings].length} warnings", print: false)
|
233
|
+
if enable_offenses
|
234
|
+
ui.plain_line("Summary: #{errors}, #{warnings}, #{offenses}")
|
235
|
+
else
|
236
|
+
ui.plain_line("Summary: #{errors}, #{warnings}")
|
237
|
+
end
|
238
|
+
end
|
212
239
|
end
|
240
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
241
|
+
rescue StandardError => e
|
242
|
+
pretty_handle_exception(e)
|
213
243
|
end
|
214
|
-
|
215
|
-
|
216
|
-
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
217
|
-
rescue StandardError => e
|
218
|
-
pretty_handle_exception(e)
|
244
|
+
}
|
219
245
|
end
|
220
246
|
|
221
247
|
desc "vendor PATH", "Download all dependencies and generate a lockfile in a `vendor` directory"
|
222
248
|
option :overwrite, type: :boolean, default: false,
|
223
249
|
desc: "Overwrite existing vendored dependencies and lockfile."
|
224
250
|
def vendor(path = nil)
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
251
|
+
Inspec.with_feature("inspec-cli-vendor") {
|
252
|
+
o = config
|
253
|
+
configure_logger(o)
|
254
|
+
o[:logger] = Logger.new($stdout)
|
255
|
+
o[:logger].level = get_log_level(o[:log_level])
|
229
256
|
|
230
|
-
|
257
|
+
vendor_deps(path, o)
|
258
|
+
}
|
231
259
|
end
|
232
260
|
|
233
261
|
desc "archive PATH", "Archive a profile to a tar file (default) or zip file."
|
@@ -248,37 +276,43 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
248
276
|
desc: "Run profile check before archiving."
|
249
277
|
option :export, type: :boolean, default: false,
|
250
278
|
desc: "Export the profile to inspec.json and include in archive"
|
279
|
+
option :legacy_export, type: :boolean, default: false,
|
280
|
+
desc: "Export the profile in legacy mode to inspec.json and include in archive"
|
251
281
|
def archive(path, log_level = nil)
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
282
|
+
Inspec.with_feature("inspec-cli-archive") {
|
283
|
+
begin
|
284
|
+
o = config
|
285
|
+
diagnose(o)
|
286
|
+
|
287
|
+
o[:logger] = Logger.new($stdout)
|
288
|
+
o[:logger].level = get_log_level(log_level || o[:log_level])
|
289
|
+
o[:backend] = Inspec::Backend.create(Inspec::Config.mock)
|
290
|
+
|
291
|
+
# Force vendoring with overwrite when archiving
|
292
|
+
vendor_options = o.dup
|
293
|
+
vendor_options[:overwrite] = true
|
294
|
+
vendor_deps(path, vendor_options)
|
295
|
+
|
296
|
+
profile = Inspec::Profile.for_target(path, o)
|
297
|
+
gem_deps = profile.metadata.gem_dependencies + \
|
298
|
+
profile.locked_dependencies.list.map { |_k, v| v.profile.metadata.gem_dependencies }.flatten
|
299
|
+
unless gem_deps.empty?
|
300
|
+
o[:logger].warn "Archiving a profile that contains gem dependencies, but InSpec cannot package gems with the profile! Please archive your ~/.inspec/gems directory separately."
|
301
|
+
end
|
270
302
|
|
271
|
-
|
303
|
+
result = profile.check if o[:check]
|
272
304
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
305
|
+
if result && !o[:ignore_errors] == false
|
306
|
+
o[:logger].info "Profile check failed. Please fix the profile before generating an archive."
|
307
|
+
return ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
308
|
+
end
|
277
309
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
310
|
+
# generate archive
|
311
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless profile.archive(o)
|
312
|
+
rescue StandardError => e
|
313
|
+
pretty_handle_exception(e)
|
314
|
+
end
|
315
|
+
}
|
282
316
|
end
|
283
317
|
|
284
318
|
desc "exec LOCATIONS", "Run all test files at the specified locations."
|
@@ -356,46 +390,60 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
356
390
|
```
|
357
391
|
EOT
|
358
392
|
exec_options
|
393
|
+
audit_log_options
|
359
394
|
def exec(*targets)
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
395
|
+
Inspec.with_feature("inspec-cli-exec") {
|
396
|
+
begin
|
397
|
+
o = config
|
398
|
+
diagnose(o)
|
399
|
+
deprecate_target_id(config)
|
400
|
+
configure_logger(o)
|
401
|
+
|
402
|
+
# Only runs this block when preview flag CHEF_PREVIEW_AUDIT_LOGGING is set
|
403
|
+
Inspec.with_feature("inspec-audit-logging") {
|
404
|
+
set_and_validate_audit_log_options(o)
|
405
|
+
}
|
406
|
+
|
407
|
+
runner = Inspec::Runner.new(o)
|
408
|
+
targets.each { |target| runner.add_target(target) }
|
409
|
+
|
410
|
+
ui.exit runner.run
|
411
|
+
rescue ArgumentError, RuntimeError, Train::UserError => e
|
412
|
+
$stderr.puts e.message
|
413
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
414
|
+
rescue StandardError => e
|
415
|
+
pretty_handle_exception(e)
|
416
|
+
end
|
417
|
+
}
|
374
418
|
end
|
375
419
|
|
376
420
|
desc "detect", "detects the target OS."
|
377
421
|
target_options
|
378
422
|
option :format, type: :string
|
379
423
|
def detect
|
380
|
-
|
381
|
-
|
382
|
-
|
424
|
+
Inspec.with_feature("inspec-cli-detect") {
|
425
|
+
begin
|
426
|
+
o = config
|
427
|
+
deprecate_target_id(config)
|
428
|
+
o[:command] = "platform.params"
|
383
429
|
|
384
|
-
|
430
|
+
configure_logger(o)
|
385
431
|
|
386
|
-
|
432
|
+
(_, res) = run_command(o)
|
387
433
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
434
|
+
if o["format"] == "json"
|
435
|
+
puts res.to_json
|
436
|
+
else
|
437
|
+
ui.headline("Platform Details")
|
438
|
+
ui.plain Inspec::BaseCLI.format_platform_info(params: res, indent: 0, color: 36, enable_color: ui.color?)
|
439
|
+
end
|
440
|
+
rescue ArgumentError, RuntimeError, Train::UserError => e
|
441
|
+
$stderr.puts e.message
|
442
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR
|
443
|
+
rescue StandardError => e
|
444
|
+
pretty_handle_exception(e)
|
445
|
+
end
|
446
|
+
}
|
399
447
|
end
|
400
448
|
|
401
449
|
desc "shell", "open an interactive debugging shell."
|
@@ -419,79 +467,99 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
419
467
|
desc: "Specify one or more inputs directly on the command line to the shell, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
420
468
|
option :enhanced_outcomes, type: :boolean,
|
421
469
|
desc: "Show enhanced outcomes in output"
|
470
|
+
audit_log_options
|
422
471
|
def shell_func
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
472
|
+
Inspec.with_feature("inspec-cli-shell") {
|
473
|
+
begin
|
474
|
+
o = config
|
475
|
+
deprecate_target_id(config)
|
476
|
+
diagnose(o)
|
477
|
+
o[:debug_shell] = true
|
478
|
+
Inspec.with_feature("inspec-audit-logging") {
|
479
|
+
set_and_validate_audit_log_options(o)
|
480
|
+
}
|
429
481
|
|
430
|
-
|
431
|
-
o[:logger] = Logger.new(log_device)
|
432
|
-
o[:logger].level = get_log_level(o[:log_level])
|
482
|
+
Inspec::Resource.toggle_inspect unless o[:inspect]
|
433
483
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
end
|
484
|
+
log_device = suppress_log_output?(o) ? nil : $stdout
|
485
|
+
o[:logger] = Logger.new(log_device)
|
486
|
+
o[:logger].level = get_log_level(o[:log_level])
|
438
487
|
|
439
|
-
|
440
|
-
|
488
|
+
if o[:command].nil?
|
489
|
+
runner = Inspec::Runner.new(o)
|
490
|
+
return Inspec::Shell.new(runner).start
|
491
|
+
end
|
441
492
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
493
|
+
run_type, res = run_command(o)
|
494
|
+
ui.exit res unless run_type == :ruby_eval
|
495
|
+
|
496
|
+
# No InSpec tests - just print evaluation output.
|
497
|
+
reporters = o["reporter"] || {}
|
498
|
+
if reporters.keys.include?("json")
|
499
|
+
res = if res.respond_to?(:to_json)
|
500
|
+
res.to_json
|
501
|
+
else
|
502
|
+
JSON.dump(res)
|
503
|
+
end
|
504
|
+
end
|
451
505
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
506
|
+
puts res
|
507
|
+
ui.exit Inspec::UI::EXIT_NORMAL
|
508
|
+
rescue RuntimeError, Train::UserError => e
|
509
|
+
$stderr.puts e.message
|
510
|
+
rescue StandardError => e
|
511
|
+
pretty_handle_exception(e)
|
512
|
+
end
|
513
|
+
}
|
458
514
|
end
|
459
515
|
|
460
516
|
desc "env", "Outputs shell-appropriate completion configuration."
|
461
517
|
def env(shell = nil)
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
518
|
+
Inspec.with_feature("inspec-cli-env") {
|
519
|
+
begin
|
520
|
+
p = Inspec::EnvPrinter.new(self.class, shell)
|
521
|
+
p.print_and_exit!
|
522
|
+
rescue StandardError => e
|
523
|
+
pretty_handle_exception(e)
|
524
|
+
end
|
525
|
+
}
|
466
526
|
end
|
467
527
|
|
468
528
|
option :enhanced_outcomes, type: :boolean,
|
469
529
|
desc: "Show enhanced outcomes output"
|
470
530
|
desc "schema NAME", "print the JSON schema", hide: true
|
471
531
|
def schema(name)
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
532
|
+
Inspec.with_feature("inspec-cli-schema") {
|
533
|
+
begin
|
534
|
+
require "inspec/schema/output_schema"
|
535
|
+
o = config
|
536
|
+
puts Inspec::Schema::OutputSchema.json(name, o)
|
537
|
+
rescue StandardError => e
|
538
|
+
puts e
|
539
|
+
puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
|
540
|
+
end
|
541
|
+
}
|
478
542
|
end
|
479
543
|
|
480
544
|
desc "run_context", "used to test run-context detection", hide: true
|
481
545
|
def run_context
|
482
|
-
|
483
|
-
|
546
|
+
Inspec.with_feature("inspec-cli-run-context") {
|
547
|
+
require "inspec/utils/telemetry/run_context_probe"
|
548
|
+
puts Inspec::Telemetry::RunContextProbe.guess_run_context
|
549
|
+
}
|
484
550
|
end
|
485
551
|
|
486
552
|
desc "version", "prints the version of this tool."
|
487
553
|
option :format, type: :string
|
488
554
|
def version
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
555
|
+
Inspec.with_feature("inspec-cli-version") {
|
556
|
+
if config["format"] == "json"
|
557
|
+
v = { version: Inspec::VERSION }
|
558
|
+
puts v.to_json
|
559
|
+
else
|
560
|
+
puts Inspec::VERSION
|
561
|
+
end
|
562
|
+
}
|
495
563
|
end
|
496
564
|
map %w{-v --version} => :version
|
497
565
|
|
@@ -499,14 +567,16 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
499
567
|
option :vendor_cache, type: :string,
|
500
568
|
desc: "Use the given path for caching dependencies, (default: `~/.inspec/cache`)."
|
501
569
|
def clear_cache
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
570
|
+
Inspec.with_feature("inspec-cli-clear-cache") {
|
571
|
+
o = config
|
572
|
+
configure_logger(o)
|
573
|
+
cache_path = o[:vendor_cache] || "~/.inspec/cache"
|
574
|
+
FileUtils.rm_r Dir.glob(File.expand_path(cache_path))
|
575
|
+
|
576
|
+
o[:logger] = Logger.new($stdout)
|
577
|
+
o[:logger].level = get_log_level(o[:log_level])
|
578
|
+
o[:logger].info "== InSpec cache cleared successfully =="
|
579
|
+
}
|
510
580
|
end
|
511
581
|
|
512
582
|
private
|