inspec-core 5.22.29 → 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 +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
|