inspec-core 5.22.50 → 6.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Chef-EULA +9 -0
- data/Gemfile +23 -13
- data/etc/features.sig +6 -0
- data/etc/features.yaml +94 -0
- data/inspec-core.gemspec +14 -11
- 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 +292 -235
- data/lib/inspec/config.rb +24 -11
- data/lib/inspec/dependencies/cache.rb +33 -0
- data/lib/inspec/dependencies/dependency_set.rb +2 -2
- data/lib/inspec/dsl.rb +1 -1
- 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/fetcher/url.rb +3 -5
- 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 +46 -3
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters.rb +67 -54
- data/lib/inspec/resources/virtualization.rb +1 -1
- data/lib/inspec/rule.rb +9 -14
- data/lib/inspec/run_data.rb +7 -5
- data/lib/inspec/runner.rb +35 -6
- 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 +2 -1
- data/lib/inspec/utils/waivers/csv_file_reader.rb +1 -1
- data/lib/inspec/utils/waivers/excel_file_reader.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec/waiver_file_reader.rb +68 -27
- data/lib/inspec.rb +2 -1
- data/lib/matchers/matchers.rb +3 -3
- 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-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 +44 -18
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."
|
@@ -72,13 +78,15 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
72
78
|
desc: "Run with legacy export."
|
73
79
|
profile_options
|
74
80
|
def json(target)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
+
}
|
82
90
|
end
|
83
91
|
|
84
92
|
desc "export PATH", "read the profile in PATH and generate a summary in the given format."
|
@@ -96,62 +104,66 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
96
104
|
desc: "Run with legacy export."
|
97
105
|
profile_options
|
98
106
|
def export(target, as_json = false)
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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)
|
145
165
|
end
|
146
|
-
|
147
|
-
out = dst.empty? ? $stdout : File.open(dst, "w")
|
148
|
-
out.write(profile.readme)
|
149
|
-
when "metadata"
|
150
|
-
out = dst.empty? ? $stdout : File.open(dst, "w")
|
151
|
-
out.write(profile.metadata_src)
|
152
|
-
end
|
153
|
-
rescue StandardError => e
|
154
|
-
pretty_handle_exception(e)
|
166
|
+
}
|
155
167
|
end
|
156
168
|
|
157
169
|
desc "check PATH", "Verify the metadata in the `inspec.yml` file,\
|
@@ -165,80 +177,85 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
165
177
|
desc: "Run with legacy check."
|
166
178
|
profile_options
|
167
179
|
def check(path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
prepared_string = format("%-12s %s",
|
187
|
-
"#{item.to_s.capitalize} :",
|
188
|
-
result[:summary][item.to_sym])
|
189
|
-
ui.plain_line(prepared_string)
|
190
|
-
end
|
191
|
-
puts
|
192
|
-
|
193
|
-
enable_offenses = !Inspec.locally_windows? # See 5723
|
194
|
-
if result[:errors].empty? && result[:warnings].empty? && result[:offenses].empty?
|
195
|
-
if enable_offenses
|
196
|
-
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)
|
197
198
|
else
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
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
|
+
}
|
205
219
|
|
206
|
-
|
207
|
-
|
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" }
|
208
222
|
|
209
|
-
|
223
|
+
puts
|
210
224
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
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
|
215
229
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
223
239
|
end
|
240
|
+
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
241
|
+
rescue StandardError => e
|
242
|
+
pretty_handle_exception(e)
|
224
243
|
end
|
225
|
-
|
226
|
-
|
227
|
-
ui.exit Inspec::UI::EXIT_USAGE_ERROR unless result[:summary][:valid]
|
228
|
-
rescue StandardError => e
|
229
|
-
pretty_handle_exception(e)
|
244
|
+
}
|
230
245
|
end
|
231
246
|
|
232
247
|
desc "vendor PATH", "Download all dependencies and generate a lockfile in a `vendor` directory"
|
233
248
|
option :overwrite, type: :boolean, default: false,
|
234
249
|
desc: "Overwrite existing vendored dependencies and lockfile."
|
235
250
|
def vendor(path = nil)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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])
|
240
256
|
|
241
|
-
|
257
|
+
vendor_deps(path, o)
|
258
|
+
}
|
242
259
|
end
|
243
260
|
|
244
261
|
desc "archive PATH", "Archive a profile to a tar file (default) or zip file."
|
@@ -262,36 +279,40 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
262
279
|
option :legacy_export, type: :boolean, default: false,
|
263
280
|
desc: "Export the profile in legacy mode to inspec.json and include in archive"
|
264
281
|
def archive(path, log_level = nil)
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
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
|
283
302
|
|
284
|
-
|
303
|
+
result = profile.check if o[:check]
|
285
304
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
290
309
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
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
|
+
}
|
295
316
|
end
|
296
317
|
|
297
318
|
desc "exec LOCATIONS", "Run all test files at the specified locations."
|
@@ -369,46 +390,60 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
369
390
|
```
|
370
391
|
EOT
|
371
392
|
exec_options
|
393
|
+
audit_log_options
|
372
394
|
def exec(*targets)
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
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
|
+
}
|
387
418
|
end
|
388
419
|
|
389
420
|
desc "detect", "detects the target OS."
|
390
421
|
target_options
|
391
422
|
option :format, type: :string
|
392
423
|
def detect
|
393
|
-
|
394
|
-
|
395
|
-
|
424
|
+
Inspec.with_feature("inspec-cli-detect") {
|
425
|
+
begin
|
426
|
+
o = config
|
427
|
+
deprecate_target_id(config)
|
428
|
+
o[:command] = "platform.params"
|
396
429
|
|
397
|
-
|
430
|
+
configure_logger(o)
|
398
431
|
|
399
|
-
|
432
|
+
(_, res) = run_command(o)
|
400
433
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
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
|
+
}
|
412
447
|
end
|
413
448
|
|
414
449
|
desc "shell", "open an interactive debugging shell."
|
@@ -432,79 +467,99 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
432
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."
|
433
468
|
option :enhanced_outcomes, type: :boolean,
|
434
469
|
desc: "Show enhanced outcomes in output"
|
470
|
+
audit_log_options
|
435
471
|
def shell_func
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
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
|
+
}
|
442
481
|
|
443
|
-
|
444
|
-
o[:logger] = Logger.new(log_device)
|
445
|
-
o[:logger].level = get_log_level(o[:log_level])
|
482
|
+
Inspec::Resource.toggle_inspect unless o[:inspect]
|
446
483
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
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])
|
451
487
|
|
452
|
-
|
453
|
-
|
488
|
+
if o[:command].nil?
|
489
|
+
runner = Inspec::Runner.new(o)
|
490
|
+
return Inspec::Shell.new(runner).start
|
491
|
+
end
|
454
492
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
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
|
464
505
|
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
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
|
+
}
|
471
514
|
end
|
472
515
|
|
473
516
|
desc "env", "Outputs shell-appropriate completion configuration."
|
474
517
|
def env(shell = nil)
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
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
|
+
}
|
479
526
|
end
|
480
527
|
|
481
528
|
option :enhanced_outcomes, type: :boolean,
|
482
529
|
desc: "Show enhanced outcomes output"
|
483
530
|
desc "schema NAME", "print the JSON schema", hide: true
|
484
531
|
def schema(name)
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
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
|
+
}
|
491
542
|
end
|
492
543
|
|
493
544
|
desc "run_context", "used to test run-context detection", hide: true
|
494
545
|
def run_context
|
495
|
-
|
496
|
-
|
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
|
+
}
|
497
550
|
end
|
498
551
|
|
499
552
|
desc "version", "prints the version of this tool."
|
500
553
|
option :format, type: :string
|
501
554
|
def version
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
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
|
+
}
|
508
563
|
end
|
509
564
|
map %w{-v --version} => :version
|
510
565
|
|
@@ -512,14 +567,16 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
512
567
|
option :vendor_cache, type: :string,
|
513
568
|
desc: "Use the given path for caching dependencies, (default: `~/.inspec/cache`)."
|
514
569
|
def clear_cache
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
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
|
+
}
|
523
580
|
end
|
524
581
|
|
525
582
|
private
|