inspec-core 4.20.6 → 4.22.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/inspec-core.gemspec +1 -1
  4. data/lib/inspec/base_cli.rb +1 -1
  5. data/lib/inspec/cli.rb +6 -5
  6. data/lib/inspec/config.rb +2 -6
  7. data/lib/inspec/exceptions.rb +1 -0
  8. data/lib/inspec/input_registry.rb +2 -1
  9. data/lib/inspec/metadata.rb +6 -1
  10. data/lib/inspec/profile.rb +30 -9
  11. data/lib/inspec/reporters.rb +3 -0
  12. data/lib/{plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter.rb → inspec/reporters/cli.rb} +61 -53
  13. data/lib/inspec/reporters/json.rb +9 -4
  14. data/lib/inspec/resources/apt.rb +2 -0
  15. data/lib/inspec/resources/interface.rb +55 -0
  16. data/lib/inspec/resources/interfaces.rb +119 -0
  17. data/lib/inspec/resources/service.rb +1 -1
  18. data/lib/inspec/run_data.rb +1 -1
  19. data/lib/inspec/run_data/profile.rb +4 -4
  20. data/lib/inspec/runner.rb +8 -2
  21. data/lib/inspec/runner_rspec.rb +4 -1
  22. data/lib/inspec/schema.rb +2 -0
  23. data/lib/inspec/schema/exec_json.rb +4 -3
  24. data/lib/inspec/schema/primitives.rb +1 -1
  25. data/lib/inspec/utils/telemetry/run_context_probe.rb +48 -0
  26. data/lib/inspec/version.rb +1 -1
  27. data/lib/plugins/inspec-reporter-html2/README.md +53 -0
  28. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2.rb +18 -0
  29. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/reporter.rb +24 -0
  30. data/lib/plugins/inspec-reporter-html2/lib/inspec-reporter-html2/version.rb +8 -0
  31. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +46 -0
  32. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +77 -0
  33. data/lib/plugins/inspec-reporter-html2/templates/default.css +107 -0
  34. data/lib/plugins/inspec-reporter-html2/templates/default.js +79 -0
  35. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +23 -0
  36. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +15 -0
  37. data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +8 -0
  38. metadata +24 -8
  39. data/lib/plugins/inspec-reporter-cli/README.md +0 -12
  40. data/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli.rb +0 -13
  41. data/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/version.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bad597d54eeb47c2f634b9c2bba2fcec8afa0d507e0b321244caee264c3b59cf
4
- data.tar.gz: 966803761b3601c83b1d2474b3405b863b245396f8e4962fc950484ed87ee9ea
3
+ metadata.gz: 2b4f096b34b4707a39ac4392118bdeadf0ab3b15b2ebea8faf8661902dbf8409
4
+ data.tar.gz: 60ed138d131e605f8257a541a655757bf819c6e72b169a2c1034a1626db7c4d1
5
5
  SHA512:
6
- metadata.gz: 2ea62a2de16846b6d3bd1075868e070e41a14d9a8dce9a711155e7d75519eb56fa23238fa4cc3b53a97480396c4bd7a1b20a98251918268a66278c970ab0cda1
7
- data.tar.gz: a420f3368a7ae4b6f264f15901848e7615bd6e7fefac559dda3c955d83b7059dd59464e685cef5e4310da2d503e61f72c254739c4a054e7b6f76c7bd5f61ef37
6
+ metadata.gz: 910a8739e4f375d3d573a734f46350e3e609a72b2376d8d9e04757e06e2274da1f728b612ab11312b08f90fafd5baf68f90a179fc90edaac9366ca49701680eb
7
+ data.tar.gz: 25320c374c74ee45a8ebdcfce19c7fd481a1888c7d7f3250c5a091a3e556096dd42191b570e58572ae382dea7f99661c901ae3822438c52268b76ccef286572f
data/Gemfile CHANGED
@@ -31,6 +31,7 @@ group :test do
31
31
  gem "m"
32
32
  gem "pry", "~> 0.10"
33
33
  gem "pry-byebug"
34
+ gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
34
35
  end
35
36
 
36
37
  group :integration do
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency "chef-telemetry", "~> 1.0"
27
27
  spec.add_dependency "license-acceptance", ">= 0.2.13", "< 2.0"
28
28
  spec.add_dependency "thor", ">= 0.20", "< 2.0"
29
- spec.add_dependency "json_schemer", "~> 0.2.1"
29
+ spec.add_dependency "json_schemer", ">= 0.2.1", "< 0.2.12"
30
30
  spec.add_dependency "method_source", ">= 0.8", "< 2.0"
31
31
  spec.add_dependency "rubyzip", "~> 1.2", ">= 1.2.2"
32
32
  spec.add_dependency "rspec", "~> 3.9"
@@ -231,7 +231,7 @@ module Inspec
231
231
 
232
232
  private
233
233
 
234
- ALL_OF_OUR_REPORTERS = %w{json json-min json-rspec json-automate junit html yaml documentation progress}.freeze # BUT WHY?!?!
234
+ ALL_OF_OUR_REPORTERS = %w{json json-min json-rspec json-automate junit html html2 yaml documentation progress}.freeze # BUT WHY?!?!
235
235
 
236
236
  def suppress_log_output?(opts)
237
237
  return false if opts["reporter"].nil?
@@ -375,6 +375,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
375
375
  puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
376
376
  end
377
377
 
378
+ desc "run_context", "used to test run-context detection", hide: true
379
+ def run_context
380
+ require "inspec/utils/telemetry/run_context_probe"
381
+ puts Inspec::Telemetry::RunContextProbe.guess_run_context
382
+ end
383
+
378
384
  desc "version", "prints the version of this tool"
379
385
  option :format, type: :string
380
386
  def version
@@ -387,11 +393,6 @@ class Inspec::InspecCLI < Inspec::BaseCLI
387
393
  end
388
394
  map %w{-v --version} => :version
389
395
 
390
- desc "nothing", "does nothing"
391
- def nothing
392
- puts "you did nothing"
393
- end
394
-
395
396
  private
396
397
 
397
398
  def run_command(opts)
@@ -341,6 +341,7 @@ module Inspec
341
341
  # Tracked on https://github.com/inspec/inspec/issues/3667
342
342
  inspec_reporters_that_are_not_yet_plugins = %w{
343
343
  automate
344
+ cli
344
345
  json
345
346
  json-automate
346
347
  junit
@@ -354,12 +355,7 @@ module Inspec
354
355
  .find_activators(plugin_type: :reporter)\
355
356
  .map(&:activator_name).map(&:to_s)
356
357
 
357
- # Include CLI explicitly, because it is the default reporter and will usually not be
358
- # present on the command line, and thus its plugin will not appear on the list.
359
- valid_types = rspec_built_in_formatters + \
360
- inspec_reporters_that_are_not_yet_plugins + \
361
- plugin_reporters + \
362
- [ "cli" ]
358
+ valid_types = rspec_built_in_formatters + inspec_reporters_that_are_not_yet_plugins + plugin_reporters
363
359
 
364
360
  reporters.each do |reporter_name, reporter_config|
365
361
  raise NotImplementedError, "'#{reporter_name}' is not a valid reporter type." unless valid_types.include?(reporter_name)
@@ -4,6 +4,7 @@ module Inspec
4
4
  module Exceptions
5
5
  class InputsFileDoesNotExist < ArgumentError; end
6
6
  class InputsFileNotReadable < ArgumentError; end
7
+ class ProfileLoadFailed < StandardError; end
7
8
  class ResourceFailed < StandardError; end
8
9
  class ResourceSkipped < StandardError; end
9
10
  class SecretsBackendNotFound < ArgumentError; end
@@ -165,7 +165,8 @@ module Inspec
165
165
  raise ArgumentError, "ERROR: An '=' is required when using --input. Usage: --input input_name1=input_value1 input2=value2"
166
166
  end
167
167
  end
168
- input_name, input_value = pair.split("=")
168
+ pair = pair.match(/(.*?)=(.*)/)
169
+ input_name, input_value = pair[1], pair[2]
169
170
  input_value = parse_cli_input_value(input_name, input_value)
170
171
  evt = Inspec::Input::Event.new(
171
172
  value: input_value,
@@ -9,7 +9,12 @@ require "inspec/version"
9
9
  require "inspec/utils/spdx"
10
10
 
11
11
  module Inspec
12
- # Extract metadata.rb information
12
+ # The Metadata class represents a profile's metadata.
13
+ # This includes the metadata stored in the profile's metadata.rb file, as well as inferred
14
+ # metadata like if this profile supports the current runtime and the intended target.
15
+ # This class does NOT represent the runtime state of a profile during execution.
16
+ # See lib/inspec/profile.rb for the runtime representation of a profile.
17
+ #
13
18
  # A Metadata object may be created and finalized with invalid data.
14
19
  # This allows the check CLI command to analyse the issues.
15
20
  # Use valid? to determine if the metadata is coherent.
@@ -94,6 +94,7 @@ module Inspec
94
94
  @input_values = options[:inputs]
95
95
  @tests_collected = false
96
96
  @libraries_loaded = false
97
+ @state = :loaded
97
98
  @check_mode = options[:check_mode] || false
98
99
  @parent_profile = options[:parent_profile]
99
100
  @legacy_profile_path = options[:profiles_path] || false
@@ -146,7 +147,12 @@ module Inspec
146
147
  options[:profile_context] ||
147
148
  Inspec::ProfileContext.for_profile(self, @backend)
148
149
 
149
- @supports_platform = metadata.supports_platform?(@backend)
150
+ if metadata.supports_platform?(@backend)
151
+ @supports_platform = true
152
+ else
153
+ @supports_platform = false
154
+ @state = :skipped
155
+ end
150
156
  @supports_runtime = metadata.supports_runtime?
151
157
  end
152
158
 
@@ -162,6 +168,10 @@ module Inspec
162
168
  @writable
163
169
  end
164
170
 
171
+ def failed?
172
+ @state == :failed
173
+ end
174
+
165
175
  #
166
176
  # Is this profile is supported on the current platform of the
167
177
  # backend machine and the current inspec version.
@@ -197,7 +207,7 @@ module Inspec
197
207
  end
198
208
 
199
209
  def collect_tests(include_list = @controls)
200
- unless @tests_collected
210
+ unless @tests_collected || failed?
201
211
  return unless supports_platform?
202
212
 
203
213
  locked_dependencies.each(&:collect_tests)
@@ -206,7 +216,12 @@ module Inspec
206
216
  next if content.nil? || content.empty?
207
217
 
208
218
  abs_path = source_reader.target.abs_path(path)
209
- @runner_context.load_control_file(content, abs_path, nil)
219
+ begin
220
+ @runner_context.load_control_file(content, abs_path, nil)
221
+ rescue => e
222
+ @state = :failed
223
+ raise Inspec::Exceptions::ProfileLoadFailed, "Failed to load source for #{path}: #{e}"
224
+ end
210
225
  end
211
226
  @tests_collected = true
212
227
  end
@@ -249,12 +264,13 @@ module Inspec
249
264
  d = dep.profile
250
265
  # this will force a dependent profile load so we are only going to add
251
266
  # this metadata if the parent profile is supported.
252
- if supports_platform? && !d.supports_platform?
267
+ if @supports_platform && !d.supports_platform?
253
268
  # since ruby 1.9 hashes are ordered so we can just use index values here
254
269
  # TODO: NO! this is a violation of encapsulation to an extreme
255
270
  metadata.dependencies[i][:status] = "skipped"
256
271
  msg = "Skipping profile: '#{d.name}' on unsupported platform: '#{d.backend.platform.name}/#{d.backend.platform.release}'."
257
- metadata.dependencies[i][:skip_message] = msg
272
+ metadata.dependencies[i][:status_message] = msg
273
+ metadata.dependencies[i][:skip_message] = msg # Repeat as skip_message for backward compatibility
258
274
  next
259
275
  elsif metadata.dependencies[i]
260
276
  # Currently wrapper profiles will load all dependencies, and then we
@@ -324,12 +340,13 @@ module Inspec
324
340
  res[:sha256] = sha256
325
341
  res[:parent_profile] = parent_profile unless parent_profile.nil?
326
342
 
327
- if !supports_platform?
343
+ if @supports_platform
344
+ res[:status_message] = @status_message || ""
345
+ res[:status] = failed? ? "failed" : "loaded"
346
+ else
328
347
  res[:status] = "skipped"
329
348
  msg = "Skipping profile: '#{name}' on unsupported platform: '#{backend.platform.name}/#{backend.platform.release}'."
330
- res[:skip_message] = msg
331
- else
332
- res[:status] = "loaded"
349
+ res[:status_message] = msg
333
350
  end
334
351
 
335
352
  # convert legacy os-* supports to their platform counterpart
@@ -455,6 +472,10 @@ module Inspec
455
472
  params[:controls].values.length
456
473
  end
457
474
 
475
+ def set_status_message(msg)
476
+ @status_message = msg.to_s
477
+ end
478
+
458
479
  # generates a archive of a folder profile
459
480
  # assumes that the profile was checked before
460
481
  def archive(opts)
@@ -1,4 +1,5 @@
1
1
  require "inspec/reporters/base"
2
+ require "inspec/reporters/cli"
2
3
  require "inspec/reporters/json"
3
4
  require "inspec/reporters/json_automate"
4
5
  require "inspec/reporters/junit"
@@ -11,6 +12,8 @@ module Inspec::Reporters
11
12
  name, config = reporter.dup
12
13
  config[:run_data] = run_data
13
14
  case name
15
+ when "cli"
16
+ reporter = Inspec::Reporters::CLI.new(config)
14
17
  when "json"
15
18
  reporter = Inspec::Reporters::Json.new(config)
16
19
  # This reporter is only used for Chef internal. We reserve the
@@ -1,8 +1,5 @@
1
- require "forwardable"
2
-
3
- module InspecPlugins::CliReporter
4
- class Reporter < Inspec.plugin(2, :reporter)
5
-
1
+ module Inspec::Reporters
2
+ class CLI < Base
6
3
  case RUBY_PLATFORM
7
4
  when /windows|mswin|msys|mingw|cygwin/
8
5
  # Most currently available Windows terminals have poor support
@@ -43,15 +40,11 @@ module InspecPlugins::CliReporter
43
40
 
44
41
  MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60
45
42
 
46
- def self.run_data_schema_constraints
47
- "~> 0.0"
48
- end
49
-
50
43
  def render
51
- run_data.profiles.each do |profile|
52
- if profile.status == "skipped"
53
- platform = run_data.platform
54
- output("Skipping profile: '#{profile.name}' on unsupported platform: '#{platform.name}/#{platform.release}'.")
44
+ run_data[:profiles].each do |profile|
45
+ if profile[:status] == "skipped"
46
+ platform = run_data[:platform]
47
+ output("Skipping profile: '#{profile[:name]}' on unsupported platform: '#{platform[:name]}/#{platform[:release]}'.")
55
48
  next
56
49
  end
57
50
  @control_count = 0
@@ -77,9 +70,10 @@ module InspecPlugins::CliReporter
77
70
  def print_profile_header(profile)
78
71
  header = {
79
72
  "Profile" => format_profile_name(profile),
80
- "Version" => profile.version || "(not specified)",
73
+ "Version" => profile[:version] || "(not specified)",
81
74
  }
82
- header["Target"] = run_data.platform.target unless run_data.platform.target.nil?
75
+ header["Failure Message"] = profile[:status_message] if profile[:status] == "failed"
76
+ header["Target"] = run_data[:platform][:target] unless run_data[:platform][:target].nil?
83
77
  header["Target ID"] = @config["target_id"] unless @config["target_id"].nil?
84
78
 
85
79
  pad = header.keys.max_by(&:length).length + 1
@@ -91,8 +85,8 @@ module InspecPlugins::CliReporter
91
85
 
92
86
  def print_standard_control_results(profile)
93
87
  standard_controls_from_profile(profile).each do |control_from_profile|
94
- control = ControlForCliDisplay.new(control_from_profile)
95
- next if control.results.empty?
88
+ control = Control.new(control_from_profile)
89
+ next if control.results.nil?
96
90
 
97
91
  output(format_control_header(control))
98
92
  control.results.each do |result|
@@ -105,8 +99,8 @@ module InspecPlugins::CliReporter
105
99
 
106
100
  def print_anonymous_control_results(profile)
107
101
  anonymous_controls_from_profile(profile).each do |control_from_profile|
108
- control = ControlForCliDisplay.new(control_from_profile)
109
- next if control.results.empty?
102
+ control = Control.new(control_from_profile)
103
+ next if control.results.nil?
110
104
 
111
105
  output(format_control_header(control))
112
106
  control.results.each do |result|
@@ -117,10 +111,10 @@ module InspecPlugins::CliReporter
117
111
  end
118
112
 
119
113
  def format_profile_name(profile)
120
- if profile.title.nil?
121
- (profile.name || "unknown").to_s
114
+ if profile[:title].nil?
115
+ (profile[:name] || "unknown").to_s
122
116
  else
123
- "#{profile.title} (#{profile.name || "unknown"})"
117
+ "#{profile[:title]} (#{profile[:name] || "unknown"})"
124
118
  end
125
119
  end
126
120
 
@@ -136,16 +130,16 @@ module InspecPlugins::CliReporter
136
130
  def format_result(control, result, type)
137
131
  impact = control.impact_string_for_result(result)
138
132
 
139
- message = if result.status == "skipped"
140
- result.skip_message
133
+ message = if result[:status] == "skipped"
134
+ result[:skip_message]
141
135
  elsif type == :anonymous
142
- result.expectation_message
136
+ result[:expectation_message]
143
137
  else
144
- result.code_desc
138
+ result[:code_desc]
145
139
  end
146
140
 
147
141
  # append any failure details to the message if they exist
148
- message += "\n#{result.message}" if result.message
142
+ message += "\n#{result[:message]}" if result[:message]
149
143
 
150
144
  format_message(
151
145
  color: impact,
@@ -177,7 +171,9 @@ module InspecPlugins::CliReporter
177
171
 
178
172
  def all_unique_controls
179
173
  @unique_controls ||= begin
180
- run_data.profiles.flat_map(&:controls).uniq
174
+ run_data[:profiles].flat_map do |profile|
175
+ profile[:controls]
176
+ end.uniq
181
177
  end
182
178
  end
183
179
 
@@ -187,12 +183,12 @@ module InspecPlugins::CliReporter
187
183
  passed = 0
188
184
 
189
185
  all_unique_controls.each do |control|
190
- next if control.id.start_with? "(generated from "
191
- next if control.results.empty?
186
+ next if control[:id].start_with? "(generated from "
187
+ next unless control[:results]
192
188
 
193
- if control.results.any? { |r| r.status == "failed" }
189
+ if control[:results].any? { |r| r[:status] == "failed" }
194
190
  failed += 1
195
- elsif control.results.any? { |r| r.status == "skipped" }
191
+ elsif control[:results].any? { |r| r[:status] == "skipped" }
196
192
  skipped += 1
197
193
  else
198
194
  passed += 1
@@ -216,12 +212,12 @@ module InspecPlugins::CliReporter
216
212
  passed = 0
217
213
 
218
214
  all_unique_controls.each do |control|
219
- next if control.results.empty?
215
+ next unless control[:results]
220
216
 
221
- control.results.each do |result|
222
- if result.status == "failed"
217
+ control[:results].each do |result|
218
+ if result[:status] == "failed"
223
219
  failed += 1
224
- elsif result.status == "skipped"
220
+ elsif result[:status] == "skipped"
225
221
  skipped += 1
226
222
  else
227
223
  passed += 1
@@ -278,30 +274,42 @@ module InspecPlugins::CliReporter
278
274
  end
279
275
 
280
276
  def standard_controls_from_profile(profile)
281
- profile.controls.reject { |c| is_anonymous_control?(c) }
277
+ profile[:controls].reject { |c| is_anonymous_control?(c) }
282
278
  end
283
279
 
284
280
  def anonymous_controls_from_profile(profile)
285
- profile.controls.select { |c| is_anonymous_control?(c) && !c[:results].nil? }
281
+ profile[:controls].select { |c| is_anonymous_control?(c) && !c[:results].nil? }
286
282
  end
287
283
 
288
284
  def is_anonymous_control?(control)
289
- control.id.start_with?("(generated from ")
285
+ control[:id].start_with?("(generated from ")
290
286
  end
291
287
 
292
288
  def indent_lines(message, indentation)
293
289
  message.lines.map { |line| " " * indentation + line }.join
294
290
  end
295
291
 
296
- class ControlForCliDisplay
292
+ class Control
293
+ attr_reader :data
297
294
 
298
- extend Forwardable
295
+ def initialize(control_hash)
296
+ @data = control_hash
297
+ end
299
298
 
300
- attr_reader :control_obj
301
- def_delegators :@control_obj, :id, :impact, :results, :title
299
+ def id
300
+ data[:id]
301
+ end
302
+
303
+ def title
304
+ data[:title]
305
+ end
306
+
307
+ def results
308
+ data[:results]
309
+ end
302
310
 
303
- def initialize(control_obj)
304
- @control_obj = control_obj
311
+ def impact
312
+ data[:impact]
305
313
  end
306
314
 
307
315
  def anonymous?
@@ -310,9 +318,9 @@ module InspecPlugins::CliReporter
310
318
 
311
319
  def title_for_report
312
320
  # if this is an anonymous control, just grab the resource title from any result entry
313
- return results.first.resource_title if anonymous?
321
+ return results.first[:resource_title] if anonymous?
314
322
 
315
- title_for_report = "#{id}: #{title || results.first.resource_title}"
323
+ title_for_report = "#{id}: #{title || results.first[:resource_title]}"
316
324
 
317
325
  # we will not add any additional data to the title if there's only
318
326
  # zero or one test for this control.
@@ -330,9 +338,9 @@ module InspecPlugins::CliReporter
330
338
  nil
331
339
  elsif impact.nil?
332
340
  "unknown"
333
- elsif results&.find { |r| r.status == "skipped" }
341
+ elsif results&.find { |r| r[:status] == "skipped" }
334
342
  "skipped"
335
- elsif results.empty? || results.all? { |r| r.status == "passed" }
343
+ elsif results.nil? || results.empty? || results.all? { |r| r[:status] == "passed" }
336
344
  "passed"
337
345
  else
338
346
  "failed"
@@ -340,9 +348,9 @@ module InspecPlugins::CliReporter
340
348
  end
341
349
 
342
350
  def impact_string_for_result(result)
343
- if result.status == "skipped"
351
+ if result[:status] == "skipped"
344
352
  "skipped"
345
- elsif result.status == "passed"
353
+ elsif result[:status] == "passed"
346
354
  "passed"
347
355
  elsif impact.nil?
348
356
  "unknown"
@@ -352,11 +360,11 @@ module InspecPlugins::CliReporter
352
360
  end
353
361
 
354
362
  def failure_count
355
- results.select { |r| r.status == "failed" }.size
363
+ results.select { |r| r[:status] == "failed" }.size
356
364
  end
357
365
 
358
366
  def skipped_count
359
- results.select { |r| r.status == "skipped" }.size
367
+ results.select { |r| r[:status] == "skipped" }.size
360
368
  end
361
369
  end
362
370
  end