inspec-core 4.22.22 → 4.24.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +20 -28
  3. data/inspec-core.gemspec +3 -4
  4. data/lib/inspec/base_cli.rb +10 -0
  5. data/lib/inspec/cli.rb +4 -2
  6. data/lib/inspec/config.rb +19 -0
  7. data/lib/inspec/formatters/base.rb +16 -0
  8. data/lib/inspec/globals.rb +8 -2
  9. data/lib/inspec/input.rb +4 -3
  10. data/lib/inspec/input_registry.rb +7 -1
  11. data/lib/inspec/plugin/v2/loader.rb +5 -0
  12. data/lib/inspec/plugin/v2/plugin_types/reporter.rb +4 -31
  13. data/lib/inspec/reporters/base.rb +7 -29
  14. data/lib/inspec/reporters/json.rb +2 -0
  15. data/lib/inspec/resource.rb +2 -0
  16. data/lib/inspec/resources/apt.rb +5 -5
  17. data/lib/inspec/resources/grub_conf.rb +2 -1
  18. data/lib/inspec/resources/package.rb +1 -1
  19. data/lib/inspec/resources/platform.rb +11 -1
  20. data/lib/inspec/resources/postgres_session.rb +5 -3
  21. data/lib/inspec/resources/processes.rb +1 -1
  22. data/lib/inspec/resources/wmi.rb +15 -7
  23. data/lib/inspec/rule.rb +8 -8
  24. data/lib/inspec/run_data.rb +1 -1
  25. data/lib/inspec/run_data/profile.rb +3 -2
  26. data/lib/inspec/run_data/result.rb +2 -0
  27. data/lib/inspec/schema.rb +2 -0
  28. data/lib/inspec/schema/exec_json.rb +1 -1
  29. data/lib/inspec/shell.rb +3 -3
  30. data/lib/inspec/utils/run_data_filters.rb +104 -0
  31. data/lib/inspec/version.rb +1 -1
  32. data/lib/plugins/inspec-init/templates/profiles/aws/README.md +1 -1
  33. data/lib/plugins/inspec-reporter-html2/README.md +1 -1
  34. data/lib/plugins/inspec-reporter-junit/README.md +9 -7
  35. data/lib/plugins/inspec-reporter-junit/lib/inspec-reporter-junit.rb +10 -1
  36. data/lib/plugins/inspec-reporter-junit/lib/inspec-reporter-junit/reporter.rb +93 -11
  37. data/lib/plugins/shared/core_plugin_test_helper.rb +0 -16
  38. metadata +13 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: feb9a92b579da111caf36845c7ba22e6d0831233d59c5f6f5de0212aa8ef529c
4
- data.tar.gz: 945341a0aa073b969ce15e35d058246af5584d3ddfb94a5b7ffbd86cb8162254
3
+ metadata.gz: 40b226d810bf523c7b914a00d3e3e0556d23eb78b944f12fe7af7fac35a279f4
4
+ data.tar.gz: ff6cafe82a9e7234814575a3723098ccb1238fb88754cb4891288547e9c3a47b
5
5
  SHA512:
6
- metadata.gz: 148281428e3b5d2855a2c89eccb3a29e4b159933b025049d9852eab4336b9ffb0f267bb48701b208c06fc71ce2c173fe175466622b3ec535ddb4a2692d3d927f
7
- data.tar.gz: ac2e46f5dc21b7359b76df729d6b47c0f51f1f8bd272872121477204f3422d49028982a39a01df60a4ae796f03ccb41f6a448a994e22e2feb7e4d946b574cc27
6
+ metadata.gz: c663121d4e9dba5764ba321d391b4779f3b9236b827fc7dca58aa2a6a3b9d76a5749205635c38ca6a28f614364f19fef1c7c790321067fef2ae1e1eb9a1dbd74
7
+ data.tar.gz: da255c1b0637e48aa1f83ea42607829767450bd03fd5f970e527afa81898ba215b7ac4ec66c508d23ef2de74ebb9e3dc26893427c76ab4176e67ffaf5df42c54
data/Gemfile CHANGED
@@ -11,6 +11,11 @@ gem "inspec-bin", path: "./inspec-bin"
11
11
 
12
12
  gem "ffi", ">= 1.9.14", "!= 1.13.0"
13
13
 
14
+ if Gem.ruby_version.to_s.start_with?("2.5")
15
+ # 16.7.23 required ruby 2.6+
16
+ gem "chef-utils", "< 16.7.23" # TODO: remove when we drop ruby 2.5
17
+ end
18
+
14
19
  group :omnibus do
15
20
  gem "rb-readline"
16
21
  gem "appbundler"
@@ -20,44 +25,31 @@ end
20
25
 
21
26
  group :test do
22
27
  gem "chefstyle", "~> 1.2.1"
23
- gem "minitest", "~> 5.5"
24
- gem "minitest-sprint", "~> 1.0"
25
- gem "rake", ">= 10"
26
- gem "simplecov", ["~> 0.10", "<=0.18.2"]
27
28
  gem "concurrent-ruby", "~> 1.0"
29
+ gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
30
+ gem "json_schemer", ">= 0.2.1", "< 0.2.12"
31
+ gem "m"
32
+ gem "minitest-sprint", "~> 1.0"
33
+ gem "minitest", "~> 5.5"
28
34
  gem "mocha", "~> 1.1"
35
+ gem "nokogiri", "~> 1.9"
36
+ gem "pry-byebug"
37
+ gem "pry", "~> 0.10"
38
+ gem "rake", ">= 10"
29
39
  gem "ruby-progressbar", "~> 1.8"
40
+ gem "simplecov", ["~> 0.10", "<=0.18.2"]
30
41
  gem "webmock", "~> 3.0"
31
- gem "m"
32
- gem "pry", "~> 0.10"
33
- gem "pry-byebug"
34
- gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
35
42
  end
36
43
 
37
44
  group :integration do
38
45
  gem "berkshelf"
39
- gem "test-kitchen"
40
- gem "kitchen-vagrant"
41
- gem "chef", "< 15"
42
- gem "chef-zero", "< 15"
43
- gem "kitchen-inspec"
44
- gem "kitchen-ec2"
45
- gem "kitchen-dokken"
46
+ gem "test-kitchen", ">= 2.8"
47
+ gem "kitchen-vagrant", ">= 1.7"
48
+ gem "kitchen-inspec", ">= 2.0"
49
+ gem "kitchen-dokken", ">= 2.11"
46
50
  gem "git"
47
51
  end
48
52
 
49
- # gems for Maintainers.md generation
50
- group :maintenance do
51
- gem "tomlrb"
52
-
53
- # To sync maintainers with github
54
- gem "octokit"
55
- gem "netrc"
56
- end
57
-
58
53
  group :deploy do
59
54
  gem "inquirer"
60
- end
61
-
62
- # add these additional dependencies into Gemfile.local
63
- eval_gemfile(__FILE__ + ".local") if File.exist?(__FILE__ + ".local")
55
+ end
@@ -24,19 +24,18 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  # Implementation dependencies
26
26
  spec.add_dependency "chef-telemetry", "~> 1.0"
27
- spec.add_dependency "license-acceptance", ">= 0.2.13", "< 2.0"
27
+ spec.add_dependency "license-acceptance", ">= 0.2.13", "< 3.0"
28
28
  spec.add_dependency "thor", ">= 0.20", "< 2.0"
29
- spec.add_dependency "json_schemer", ">= 0.2.1", "< 0.2.12"
30
29
  spec.add_dependency "method_source", ">= 0.8", "< 2.0"
31
30
  spec.add_dependency "rubyzip", "~> 1.2", ">= 1.2.2"
32
- spec.add_dependency "rspec", "~> 3.9"
31
+ spec.add_dependency "rspec", "~> 3.9.0"
33
32
  spec.add_dependency "rspec-its", "~> 1.2"
34
33
  spec.add_dependency "pry", "~> 0.13"
35
34
  spec.add_dependency "hashie", "~> 3.4"
36
35
  spec.add_dependency "mixlib-log", "~> 3.0"
37
36
  spec.add_dependency "sslshake", "~> 1.2"
38
37
  spec.add_dependency "parallel", "~> 1.9"
39
- spec.add_dependency "faraday", ">= 0.9.0"
38
+ spec.add_dependency "faraday", ">= 0.9.0", "< 1.1"
40
39
  spec.add_dependency "tty-table", "~> 0.10"
41
40
  spec.add_dependency "tty-prompt", "~> 0.17"
42
41
  spec.add_dependency "tomlrb", "~> 1.2.0"
@@ -158,6 +158,16 @@ module Inspec
158
158
  option :silence_deprecations, type: :array,
159
159
  banner: "[all]|[GROUP GROUP...]",
160
160
  desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'."
161
+ option :diff, type: :boolean, default: true,
162
+ desc: "Use --no-diff to suppress 'diff' output of failed textual test results."
163
+ option :sort_results_by, type: :string, default: "file", banner: "--sort-results-by=none|control|file|random",
164
+ desc: "After normal execution order, results are sorted by control ID, or by file (default), or randomly. None uses legacy unsorted mode."
165
+ end
166
+
167
+ def self.help(*args)
168
+ super(*args)
169
+ puts "\nAbout #{Inspec::Dist::PRODUCT_NAME}:"
170
+ puts " Patents: chef.io/patents\n\n"
161
171
  end
162
172
 
163
173
  def self.format_platform_info(params: {}, indent: 0, color: 39)
@@ -48,7 +48,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
48
48
  desc: "Allow or disable user interaction"
49
49
 
50
50
  class_option :disable_core_plugins, type: :string, banner: "", # Actually a boolean, but this suppresses the creation of a --no-disable...
51
- desc: "Disable loading all plugins that are shipped in the lib/plugins directory of InSpec. Useful in development."
51
+ desc: "Disable loading all plugins that are shipped in the lib/plugins directory of InSpec. Useful in development.",
52
+ hide: true
52
53
 
53
54
  class_option :disable_user_plugins, type: :string, banner: "",
54
55
  desc: "Disable loading all plugins that the user installed."
@@ -194,7 +195,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
194
195
  pretty_handle_exception(e)
195
196
  end
196
197
 
197
- desc "exec LOCATIONS", <<~EOT
198
+ desc "exec LOCATIONS", "Run all tests at LOCATIONS."
199
+ long_desc <<~EOT
198
200
  Run all test files at the specified LOCATIONS.
199
201
 
200
202
  Loads the given profile(s) and fetches their dependencies if needed. Then
@@ -405,6 +405,18 @@ module Inspec
405
405
  @plugin_cfg = data
406
406
  end
407
407
 
408
+ def validate_sort_results_by!(option_value)
409
+ expected = %w{
410
+ none
411
+ control
412
+ file
413
+ random
414
+ }
415
+ return if expected.include? option_value
416
+
417
+ raise Inspec::ConfigError::Invalid, "--sort-results-by must be one of #{expected.join(", ")}"
418
+ end
419
+
408
420
  #-----------------------------------------------------------------------#
409
421
  # Merging Options
410
422
  #-----------------------------------------------------------------------#
@@ -435,6 +447,7 @@ module Inspec
435
447
  finalize_parse_reporters(options)
436
448
  finalize_handle_sudo(options)
437
449
  finalize_compliance_login(options)
450
+ finalize_sort_results(options)
438
451
 
439
452
  Thor::CoreExt::HashWithIndifferentAccess.new(options)
440
453
  end
@@ -509,6 +522,12 @@ module Inspec
509
522
  end
510
523
  end
511
524
 
525
+ def finalize_sort_results(options)
526
+ if options.key?("sort_results_by")
527
+ validate_sort_results_by!(options["sort_results_by"])
528
+ end
529
+ end
530
+
512
531
  class Defaults
513
532
  DEFAULTS = {
514
533
  exec: {
@@ -159,6 +159,14 @@ module Inspec::Formatters
159
159
  resource_title: example.metadata[:described_class] || example.metadata[:example_group][:description],
160
160
  expectation_message: format_expectation_message(example),
161
161
  waiver_data: example.metadata[:waiver_data],
162
+ # This enforces the resource name as expected based off of the class
163
+ # name. However, if we wanted the `name` attribute against the class
164
+ # to be canonical for this case (consider edge cases!) we would use
165
+ # example.metadata[:described_class].instance_variable_get(:@__resource_name__)&.to_s
166
+ resource_class: example.metadata[:described_class].class.superclass.name,
167
+ # This is a raw grep of the text passed to the resource in any format,
168
+ # and is used to enforce near-uniqueness against the resource.
169
+ resource_params: find_resource_params(example.metadata[:described_class]),
162
170
  }
163
171
 
164
172
  unless (pid = example.metadata[:profile_id]).nil?
@@ -174,6 +182,14 @@ module Inspec::Formatters
174
182
  res
175
183
  end
176
184
 
185
+ def find_resource_params(example)
186
+ if example.class.ancestors.include?(Inspec::Resource)
187
+ example.instance_variable_get(:@resource_params)
188
+ else
189
+ []
190
+ end
191
+ end
192
+
177
193
  def format_expectation_message(example)
178
194
  if (example.metadata[:example_group][:description_args].first == example.metadata[:example_group][:described_class]) ||
179
195
  example.metadata[:example_group][:described_class].nil?
@@ -1,15 +1,21 @@
1
1
  require_relative "utils/install_context"
2
2
 
3
3
  module Inspec
4
-
5
4
  extend Inspec::InstallContextHelpers
6
5
 
7
6
  def self.config_dir
8
- ENV["INSPEC_CONFIG_DIR"] ? ENV["INSPEC_CONFIG_DIR"] : File.join(Dir.home, ".inspec")
7
+ ENV["INSPEC_CONFIG_DIR"] || File.join(home_path, ".inspec")
9
8
  end
10
9
 
11
10
  def self.src_root
12
11
  @src_root ||= File.expand_path(File.join(__FILE__, "../../.."))
13
12
  end
14
13
 
14
+ def self.home_path
15
+ Dir.home
16
+ rescue ArgumentError, NoMethodError
17
+ # If ENV['HOME'] is not set, Dir.home will fail due to expanding the ~. Fallback to Etc.
18
+ require "etc" unless defined?(Etc)
19
+ Etc.getpwuid.dir
20
+ end
15
21
  end
@@ -171,7 +171,7 @@ module Inspec
171
171
  # are free to go higher.
172
172
  DEFAULT_PRIORITY_FOR_VALUE_SET = 60
173
173
 
174
- attr_reader :description, :events, :identifier, :name, :required, :title, :type
174
+ attr_reader :description, :events, :identifier, :name, :required, :sensitive, :title, :type
175
175
 
176
176
  def initialize(name, options = {})
177
177
  @name = name
@@ -264,6 +264,7 @@ module Inspec
264
264
  @required = options[:required] if options.key?(:required)
265
265
  @identifier = options[:identifier] if options.key?(:identifier) # TODO: determine if this is ever used
266
266
  @type = options[:type] if options.key?(:type)
267
+ @sensitive = options[:sensitive] if options.key?(:sensitive)
267
268
  end
268
269
 
269
270
  def make_creation_event(options)
@@ -320,7 +321,7 @@ module Inspec
320
321
 
321
322
  def to_hash
322
323
  as_hash = { name: name, options: {} }
323
- %i{description title identifier type required value}.each do |field|
324
+ %i{description title identifier type required value sensitive}.each do |field|
324
325
  val = send(field)
325
326
  next if val.nil?
326
327
 
@@ -334,7 +335,7 @@ module Inspec
334
335
  #--------------------------------------------------------------------------#
335
336
 
336
337
  def to_s
337
- "Input #{name} with #{current_value}"
338
+ "Input #{name} with value " + (sensitive ? "*** (senstive)" : "#{current_value}")
338
339
  end
339
340
 
340
341
  #--------------------------------------------------------------------------#
@@ -29,6 +29,8 @@ module Inspec
29
29
  def_delegator :inputs_by_profile, :select
30
30
  def_delegator :profile_aliases, :key?, :profile_alias?
31
31
 
32
+ attr_accessor :cache_inputs
33
+
32
34
  def initialize
33
35
  # Keyed on String profile_name => Hash of String input_name => Input object
34
36
  @inputs_by_profile = {}
@@ -43,6 +45,9 @@ module Inspec
43
45
  activator.activate!
44
46
  activator.implementation_class.new
45
47
  end
48
+
49
+ # Activate caching for inputs by default
50
+ @cache_inputs = true
46
51
  end
47
52
 
48
53
  #-------------------------------------------------------------#
@@ -84,7 +89,7 @@ module Inspec
84
89
 
85
90
  # Find or create the input
86
91
  inputs_by_profile[profile_name] ||= {}
87
- if inputs_by_profile[profile_name].key?(input_name)
92
+ if inputs_by_profile[profile_name].key?(input_name) && cache_inputs
88
93
  inputs_by_profile[profile_name][input_name].update(options)
89
94
  else
90
95
  inputs_by_profile[profile_name][input_name] = Inspec::Input.new(input_name, options)
@@ -316,6 +321,7 @@ module Inspec
316
321
  profile_name,
317
322
  type: input_options[:type],
318
323
  required: input_options[:required],
324
+ sensitive: input_options[:sensitive],
319
325
  event: evt
320
326
  )
321
327
  end
@@ -50,6 +50,11 @@ module Inspec::Plugin::V2
50
50
  # we want to allow "sidecar loading", in which case a plugin may add an entry to the registry.
51
51
  registry.plugin_names.dup.each do |plugin_name|
52
52
  plugin_details = registry[plugin_name]
53
+
54
+ # Under some conditions (kitchen-inspec with multiple test suites, for example), this may be
55
+ # called multple times. Don't reload anything.
56
+ next if plugin_details.loaded
57
+
53
58
  # We want to capture literally any possible exception here, since we are storing them.
54
59
  # rubocop: disable Lint/RescueException
55
60
  begin
@@ -1,18 +1,20 @@
1
1
  require_relative "../../../run_data"
2
+ require_relative "../../../utils/run_data_filters"
2
3
 
3
4
  module Inspec::Plugin::V2::PluginType
4
5
  class Reporter < Inspec::Plugin::V2::PluginBase
5
6
  register_plugin_type(:reporter)
7
+ include Inspec::Utils::RunDataFilters
6
8
 
7
9
  attr_reader :run_data
8
10
 
9
11
  def initialize(config)
10
12
  @config = config
11
13
 
12
- # Trim the run_data while still a Hash; if it is huge, this
14
+ # Filter the run_data while still a Hash; if it is huge, this
13
15
  # saves on conversion time
14
16
  @run_data = config[:run_data] || {}
15
- apply_report_resize_options
17
+ apply_run_data_filters_to_hash
16
18
 
17
19
  unless Inspec::RunData.compatible_schema?(self.class.run_data_schema_constraints)
18
20
  # Best we can do is warn here, the InSpec run has finished
@@ -24,26 +26,6 @@ module Inspec::Plugin::V2::PluginType
24
26
  @output = ""
25
27
  end
26
28
 
27
- # This is a temporary duplication of code from lib/inspec/reporters/base.rb
28
- # To be DRY'd up once the core reporters become plugins...
29
- # Apply options such as message truncation and removal of backtraces
30
- def apply_report_resize_options
31
- runtime_config = Inspec::Config.cached.respond_to?(:final_options) ? Inspec::Config.cached.final_options : {}
32
-
33
- message_truncation = runtime_config[:reporter_message_truncation] || "ALL"
34
- @trunc = message_truncation == "ALL" ? -1 : message_truncation.to_i
35
- include_backtrace = runtime_config[:reporter_backtrace_inclusion].nil? ? true : runtime_config[:reporter_backtrace_inclusion]
36
-
37
- @run_data[:profiles]&.each do |p|
38
- p[:controls].each do |c|
39
- c[:results]&.map! do |r|
40
- r.delete(:backtrace) unless include_backtrace
41
- process_message_truncation(r)
42
- end
43
- end
44
- end
45
- end
46
-
47
29
  def output(str, newline = true)
48
30
  @output << str
49
31
  @output << "\n" if newline
@@ -61,14 +43,5 @@ module Inspec::Plugin::V2::PluginType
61
43
  def self.run_data_schema_constraints
62
44
  raise NotImplementedError, "#{self.class} must implement a `run_data_schema_constraints` class method to declare its compatibiltity with the RunData API."
63
45
  end
64
-
65
- private
66
-
67
- def process_message_truncation(result)
68
- if result.key?(:message) && result[:message] != "" && @trunc > -1 && result[:message].length > @trunc
69
- result[:message] = result[:message][0...@trunc] + "[Truncated to #{@trunc} characters]"
70
- end
71
- result
72
- end
73
46
  end
74
47
  end
@@ -1,30 +1,17 @@
1
+ require_relative "../utils/run_data_filters"
2
+
1
3
  module Inspec::Reporters
2
4
  class Base
5
+ include Inspec::Utils::RunDataFilters
6
+
3
7
  attr_reader :run_data
4
8
 
5
9
  def initialize(config)
6
10
  @config = config
7
- @run_data = config[:run_data]
8
- apply_report_resize_options unless @run_data.nil?
9
- @output = ""
10
- end
11
-
12
- # Apply options such as message truncation and removal of backtraces
13
- def apply_report_resize_options
14
- runtime_config = Inspec::Config.cached.respond_to?(:final_options) ? Inspec::Config.cached.final_options : {}
11
+ @run_data = config[:run_data] || {}
12
+ apply_run_data_filters_to_hash
15
13
 
16
- message_truncation = runtime_config[:reporter_message_truncation] || "ALL"
17
- @trunc = message_truncation == "ALL" ? -1 : message_truncation.to_i
18
- include_backtrace = runtime_config[:reporter_backtrace_inclusion].nil? ? true : runtime_config[:reporter_backtrace_inclusion]
19
-
20
- @run_data[:profiles]&.each do |p|
21
- p[:controls].each do |c|
22
- c[:results]&.map! do |r|
23
- r.delete(:backtrace) unless include_backtrace
24
- process_message_truncation(r)
25
- end
26
- end
27
- end
14
+ @output = ""
28
15
  end
29
16
 
30
17
  def output(str, newline = true)
@@ -40,14 +27,5 @@ module Inspec::Reporters
40
27
  def render
41
28
  raise NotImplementedError, "#{self.class} must implement a `#render` method to format its output."
42
29
  end
43
-
44
- private
45
-
46
- def process_message_truncation(result)
47
- if result.key?(:message) && result[:message] != "" && @trunc > -1 && result[:message].length > @trunc
48
- result[:message] = result[:message][0...@trunc] + "[Truncated to #{@trunc} characters]"
49
- end
50
- result
51
- end
52
30
  end
53
31
  end
@@ -40,6 +40,8 @@ module Inspec::Reporters
40
40
  message: r[:message],
41
41
  exception: r[:exception],
42
42
  backtrace: r[:backtrace],
43
+ resource_class: r[:resource_class],
44
+ resource_params: r[:resource_params].to_s,
43
45
  }.reject { |_k, v| v.nil? }
44
46
  }
45
47
  end
@@ -108,6 +108,7 @@ module Inspec
108
108
  # Infrastructure / Bookkeeping
109
109
 
110
110
  def self.__register(name, resource_klass)
111
+ # This has bitten us and should be a great candidate to remove in InSpec5
111
112
  cl = Class.new(resource_klass) do # TODO: remove
112
113
  # As best I can figure out, this anonymous class only exists
113
114
  # because we're trying to avoid having resources with
@@ -116,6 +117,7 @@ module Inspec
116
117
  # documentation.
117
118
  def initialize(backend, name, *args)
118
119
  supersuper_initialize(backend, name) do
120
+ @resource_params = args
119
121
  super(*args)
120
122
  end
121
123
  end
@@ -87,13 +87,13 @@ module Inspec::Resources
87
87
  active = raw_line == line
88
88
 
89
89
  # formats:
90
- # deb "http://archive.ubuntu.com/ubuntu/" wily main restricted ...
91
- # deb http://archive.ubuntu.com/ubuntu/ wily main restricted ...
92
- # deb [trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted ...
90
+ # deb "http://archive.ubuntu.com/ubuntu/" wily main restricted ...
91
+ # deb http://archive.ubuntu.com/ubuntu/ wily main restricted ...
92
+ # deb [trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted ...
93
+ # deb [arch=amd64 trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted ...
93
94
  # deb cdrom:[Ubuntu 15.10 _Wily Werewolf_ - Release amd64 (20151021)]/ wily main restricted ...
94
95
 
95
- words = line.split
96
- words.delete_at 1 if words[1] && words[1].start_with?("[")
96
+ words = line.sub(/^(deb|deb-src)\s+\[.+?\]/, '\1').split
97
97
  type, url, distro, *components = words
98
98
  url = url.delete('"') if url
99
99
 
@@ -29,7 +29,7 @@ module Inspec::Resources
29
29
  @content = read_file(@conf_path)
30
30
  @kernel = kernel || "default"
31
31
  rescue UnknownGrubConfig
32
- skip_resource "The `grub_config` resource is not supported on your OS yet."
32
+ skip_resource "The `grub_conf` resource is not yet supported on the target OS #{inspec.os[:name]}."
33
33
  end
34
34
 
35
35
  def config_for_platform(path)
@@ -77,6 +77,7 @@ module Inspec::Resources
77
77
 
78
78
  def grub2_parse_kernel_lines(content, conf)
79
79
  menu_entries = extract_menu_entries(content)
80
+ return {} if menu_entries.empty?
80
81
 
81
82
  if @kernel == "default"
82
83
  default_menu_entry(menu_entries, conf["GRUB_DEFAULT"])
@@ -314,7 +314,7 @@ module Inspec::Resources
314
314
  # Find the package
315
315
  cmd = inspec.command <<-EOF.gsub(/^\s*/, "")
316
316
  Get-ItemProperty (@("#{search_paths.join('", "')}") | Where-Object { Test-Path $_ }) |
317
- Where-Object { $_.DisplayName -match "^\s*#{package_name.shellescape}\.*" -or $_.PSChildName -match "^\s*#{package_name.shellescape}\.*" } |
317
+ Where-Object { $_.DisplayName -like "#{package_name}" -or $_.PSChildName -like "#{package_name}" } |
318
318
  Select-Object -Property DisplayName,DisplayVersion | ConvertTo-Json
319
319
  EOF
320
320
 
@@ -81,7 +81,7 @@ module Inspec::Resources
81
81
  when :os, :platform then
82
82
  platform?(v)
83
83
  when :os_name, :platform_name then
84
- name == v
84
+ check_name(v)
85
85
  when :release then
86
86
  check_release(v)
87
87
  end
@@ -99,6 +99,16 @@ module Inspec::Resources
99
99
 
100
100
  private
101
101
 
102
+ def check_name(value)
103
+ # allow wild card matching
104
+ if value.include?("*")
105
+ cleaned = Regexp.escape(value).gsub('\*', ".*?")
106
+ name =~ /#{cleaned}/
107
+ else
108
+ name == value
109
+ end
110
+ end
111
+
102
112
  def check_release(value)
103
113
  # allow wild card matching
104
114
  if value.include?("*")
@@ -26,12 +26,13 @@ module Inspec::Resources
26
26
  supports platform: "windows"
27
27
  desc "Use the postgres_session InSpec audit resource to test SQL commands run against a PostgreSQL database."
28
28
  example <<~EXAMPLE
29
- sql = postgres_session('username', 'password', 'host')
29
+ sql = postgres_session('username', 'password', 'host', 'port')
30
30
  query('sql_query', ['database_name'])` contains the query and (optional) database to execute
31
31
 
32
32
  # default values:
33
33
  # username: 'postgres'
34
34
  # host: 'localhost'
35
+ # port: 5432
35
36
  # db: databse == db_user running the sql query
36
37
 
37
38
  describe sql.query('SELECT * FROM pg_shadow WHERE passwd IS NULL;') do
@@ -39,10 +40,11 @@ module Inspec::Resources
39
40
  end
40
41
  EXAMPLE
41
42
 
42
- def initialize(user, pass, host = nil)
43
+ def initialize(user, pass, host = nil, port = nil)
43
44
  @user = user || "postgres"
44
45
  @pass = pass
45
46
  @host = host || "localhost"
47
+ @port = port || 5432
46
48
  end
47
49
 
48
50
  def query(query, db = [])
@@ -64,7 +66,7 @@ module Inspec::Resources
64
66
 
65
67
  def create_psql_cmd(query, db = [])
66
68
  dbs = db.map { |x| "-d #{x}" }.join(" ")
67
- "PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -A -t -c #{escaped_query(query)}"
69
+ "PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -p #{@port} -A -t -c #{escaped_query(query)}"
68
70
  end
69
71
  end
70
72
  end
@@ -138,7 +138,7 @@ module Inspec::Resources
138
138
  command: 8,
139
139
  }
140
140
  else
141
- command = "ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command"
141
+ command = "ps wwaxo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command"
142
142
  regex = /^(.+?)\s+(\d+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
143
143
  field_map = {
144
144
  label: 1,
@@ -16,7 +16,10 @@ module Inspec::Resources
16
16
  namespace: 'root\\rsop\\computer',
17
17
  filter: 'KeyName = \'MinimumPasswordAge\' And precedence=1'
18
18
  }) do
19
- its('Setting') { should eq true }
19
+ its('Setting') { should cmp true }
20
+ end
21
+ describe wmi({namespace: "root\\cimv2", query: "SELECT installstate FROM win32_optionalfeature"}) do
22
+ its("installstate") { should include 2 }
20
23
  end
21
24
  EXAMPLE
22
25
 
@@ -66,13 +69,18 @@ module Inspec::Resources
66
69
 
67
70
  # run wmi command and filter empty wmi
68
71
  script = <<-EOH
69
- Filter Aggregate
70
- {
71
- $arr = @{}
72
- $_.properties | % {
73
- $arr.Add($_.name, $_.value)
72
+ Function Aggregate {
73
+ $propsHash = @{}
74
+ ForEach ($wmiObj in $Input) {
75
+ ForEach ($wmiProp in $wmiObj.properties) {
76
+ If($propsHash.ContainsKey($wmiProp.name)) {
77
+ $propsHash[$wmiProp.name].add($wmiProp.value) | Out-Null
78
+ } Else {
79
+ $propsHash[$wmiProp.name] = [System.Collections.ArrayList]@($wmiProp.value)
80
+ }
74
81
  }
75
- $arr
82
+ }
83
+ $propsHash
76
84
  }
77
85
  Get-WmiObject #{params} | Aggregate | ConvertTo-Json
78
86
  EOH
@@ -343,14 +343,8 @@ module Inspec
343
343
  __waiver_data["skipped_due_to_waiver"] = false
344
344
  __waiver_data["message"] = ""
345
345
 
346
- # Waivers should have a hash value with keys possibly including "run" and
347
- # expiration_date. We only care here if it has a "run" key and it
348
- # is false-like, since all non-skipped waiver operations are handled
349
- # during reporting phase.
350
- return unless __waiver_data.key?("run") && !__waiver_data["run"]
351
-
352
- # OK, the intent is to skip. Does it have an expiration date, and
353
- # if so, is it in the future?
346
+ # Does it have an expiration date, and if so, is it in the future?
347
+ # This sets a waiver message before checking `run: true`
354
348
  expiry = __waiver_data["expiration_date"]
355
349
  if expiry
356
350
  # YAML will automagically give us a Date or a Time.
@@ -370,6 +364,12 @@ module Inspec
370
364
  end
371
365
  end
372
366
 
367
+ # Waivers should have a hash value with keys possibly including "run" and
368
+ # expiration_date. We only care here if it has a "run" key and it
369
+ # is false-like, since all non-skipped waiver operations are handled
370
+ # during reporting phase.
371
+ return unless __waiver_data.key?("run") && !__waiver_data["run"]
372
+
373
373
  # OK, apply a skip.
374
374
  @__skip_rule[:result] = true
375
375
  @__skip_rule[:type] = :waiver
@@ -47,7 +47,7 @@ module Inspec
47
47
  # core reporters have been migrated to plugins. It is probable that new data elements
48
48
  # and new Hash compatibility behavior will be added during the core reporter plugin
49
49
  # conversion process.
50
- SCHEMA_VERSION = "0.2.0".freeze
50
+ SCHEMA_VERSION = "0.3.0".freeze
51
51
 
52
52
  def self.compatible_schema?(constraints)
53
53
  reqs = Gem::Requirement.create(constraints)
@@ -96,11 +96,12 @@ module Inspec
96
96
  # There are probably others
97
97
  :value,
98
98
  :type,
99
- :required
99
+ :required,
100
+ :sensitive
100
101
  ) do
101
102
  include HashLikeStruct
102
103
  def initialize(raw_opts_data)
103
- %i{value type required}.each { |f| self[f] = raw_opts_data[f] }
104
+ %i{value type required sensitive}.each { |f| self[f] = raw_opts_data[f] }
104
105
  end
105
106
  end
106
107
  end
@@ -8,6 +8,7 @@ module Inspec
8
8
  :run_time, # Float seconds execution time
9
9
  :skip_message, # String
10
10
  :start_time, # DateTime
11
+ :resource_params, # What is passed to the resource as a raw grep
11
12
  :status, # String
12
13
  :resource_title, # Ugly internals
13
14
  # :waiver_data, # Undocumented tramp data / not exposed in this API
@@ -34,6 +35,7 @@ module Inspec
34
35
  end
35
36
 
36
37
  self.resource_name = raw_res_data[:resource_title].instance_variable_get(:@__resource_name__)&.to_s
38
+ self.resource_params = raw_res_data[:resource_title].instance_variable_get(:@grep)&.to_s
37
39
  end
38
40
  end
39
41
  end
@@ -56,6 +56,7 @@ module Inspec
56
56
  "code_desc" => { "type" => "string" },
57
57
  "run_time" => { "type" => "number" },
58
58
  "start_time" => { "type" => "string" },
59
+ "resource_class" => { "type" => "string", "optional" => true },
59
60
  "skip_message" => { "type" => "string", "optional" => true },
60
61
  "resource" => { "type" => "string", "optional" => true },
61
62
  "message" => { "type" => "string", "optional" => true },
@@ -194,6 +195,7 @@ module Inspec
194
195
  "profile_sha256" => { "type" => "string" },
195
196
  "status" => { "type" => "string" },
196
197
  "code_desc" => { "type" => "string" },
198
+ "resource_class" => { "type" => "string", "optional" => true },
197
199
  "skip_message" => { "type" => "string", "optional" => true },
198
200
  "resource" => { "type" => "string", "optional" => true },
199
201
  "message" => { "type" => "string", "optional" => true },
@@ -74,7 +74,7 @@ module Inspec
74
74
  },
75
75
  }, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT])
76
76
 
77
- # Based loosely on https://www.inspec.io/docs/reference/profiles/ as of July 3, 2019
77
+ # Based loosely on https://docs.chef.io/inspec/profiles/ as of July 3, 2019
78
78
  # However, concessions were made to the reality of current reporters, specifically
79
79
  # with how description is omitted and version/inspec_version aren't as advertised online
80
80
  PROFILE = Primitives::SchemaType.new("Exec JSON Profile", {
@@ -1,4 +1,4 @@
1
- require "pry"
1
+ autoload :Pry, "pry"
2
2
 
3
3
  module Inspec
4
4
  # A pry based shell for inspec. Given a runner (with a configured backend and
@@ -137,7 +137,7 @@ module Inspec
137
137
  end
138
138
 
139
139
  info += "#{mark "Web Reference:"}\n\n"
140
- info += "https://www.inspec.io/docs/reference/resources/#{topic}\n\n"
140
+ info += "https://docs.chef.io/inspec/resources/#{topic}\n\n"
141
141
  puts info
142
142
  else
143
143
  begin
@@ -208,7 +208,7 @@ module Inspec
208
208
 
209
209
  its('content') { should_not match /^MyKey:\\s+some value/ }
210
210
 
211
- For more examples, see: https://www.inspec.io/docs/reference/matchers/
211
+ For more examples, see: https://docs.chef.io/inspec/matchers/
212
212
 
213
213
  EOL
214
214
  end
@@ -0,0 +1,104 @@
1
+ module Inspec
2
+ module Utils
3
+ # RunDataFilters is a mixin for core Reporters and plugin reporters.
4
+ # The methods operate on the run_data Hash (prior to any conversion to a
5
+ # full RunData object).
6
+ # All methods here operate using the run_data accessor and modify
7
+ # its contents in place (if needed).
8
+ module RunDataFilters
9
+
10
+ # Long name, but we want to be clear this operates on the Hash
11
+ # This is the only method that client libraries need to call; any future
12
+ # feature growth should be handled internally here.
13
+ def apply_run_data_filters_to_hash
14
+ @config[:runtime_config] = Inspec::Config.cached || {}
15
+ apply_report_resize_options
16
+ redact_sensitive_inputs
17
+ suppress_diff_output
18
+ sort_controls
19
+ end
20
+
21
+ # Apply options such as message truncation and removal of backtraces
22
+ def apply_report_resize_options
23
+ runtime_config = @config[:runtime_config]
24
+
25
+ message_truncation = runtime_config[:reporter_message_truncation] || "ALL"
26
+ @trunc = message_truncation == "ALL" ? -1 : message_truncation.to_i
27
+ include_backtrace = runtime_config[:reporter_backtrace_inclusion].nil? ? true : runtime_config[:reporter_backtrace_inclusion]
28
+
29
+ @run_data[:profiles]&.each do |p|
30
+ p[:controls].each do |c|
31
+ c[:results]&.map! do |r|
32
+ r.delete(:backtrace) unless include_backtrace
33
+ process_message_truncation(r)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ # Find any inputs with :sensitive = true and replace their values with "***"
40
+ def redact_sensitive_inputs
41
+ @run_data[:profiles]&.each do |p|
42
+ p[:inputs]&.each do |i|
43
+ next unless i[:options][:sensitive]
44
+
45
+ i[:options][:value] = "***"
46
+ end
47
+ end
48
+ end
49
+
50
+ # Optionally suppress diff output in the message field
51
+ def suppress_diff_output
52
+ return if @config[:runtime_config][:diff]
53
+
54
+ @run_data[:profiles]&.each do |p|
55
+ p[:controls]&.each do |c|
56
+ c[:results]&.each do |r|
57
+ next unless r[:message] # :message only set on failure
58
+
59
+ pos = r[:message].index("\n\nDiff:")
60
+ next unless pos # Only textual tests get Diffs
61
+
62
+ r[:message] = r[:message].slice(0, pos)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ # Optionally sort controls within each profile in report
69
+ def sort_controls
70
+ sort_type = @config[:runtime_config][:sort_results_by]
71
+ return unless sort_type
72
+ return if sort_type == "none"
73
+
74
+ @run_data[:profiles]&.each do |p|
75
+ p[:controls] ||= []
76
+ p[:groups] ||= []
77
+
78
+ case sort_type
79
+ when "control"
80
+ p[:controls].sort_by! { |c| c[:id] }
81
+ when "random"
82
+ p[:controls].shuffle!
83
+ when "file"
84
+ # Sort the controls by file, but preserve order within the file.
85
+ # Files are called "groups" in the run_data, and the filename is in the id.
86
+ sorted_control_ids = p[:groups].sort_by { |g| g[:id] }.map { |g| g[:controls] }.flatten
87
+ controls_by_id = {}
88
+ p[:controls].each { |c| controls_by_id[c[:id]] = c }
89
+ p[:controls] = sorted_control_ids.map { |cid| controls_by_id[cid] }
90
+ end
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def process_message_truncation(result)
97
+ if result.key?(:message) && result[:message] != "" && @trunc > -1 && result[:message].length > @trunc
98
+ result[:message] = result[:message][0...@trunc] + "[Truncated to #{@trunc} characters]"
99
+ end
100
+ result
101
+ end
102
+ end
103
+ end
104
+ end
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.22.22".freeze
2
+ VERSION = "4.24.8".freeze
3
3
  end
@@ -26,7 +26,7 @@ Creating new profile at /Users/spaterson/my-profile
26
26
  aws_vpc_id: 'custom-vpc-id'
27
27
  ```
28
28
 
29
- The related control will simply be skipped if this is not provided. See the [InSpec DSL documentation](https://www.inspec.io/docs/reference/dsl_inspec/) for more details on conditional execution using `only_if`.
29
+ The related control will simply be skipped if this is not provided. See the [InSpec DSL documentation](https://docs.chef.io/inspec/dsl_inspec/) for more details on conditional execution using `only_if`.
30
30
 
31
31
  ## Run the tests
32
32
 
@@ -24,7 +24,7 @@ Note the `2` in the reporter name. If you omit it and run `--reporter html` inst
24
24
 
25
25
  ## Configuring the Plugin
26
26
 
27
- The `html2` reporter requires no configuration to function. However, two options--`alternate_css_file` and `alternate_js_file`--are available for customization. The options are set in the JSON-formatted configuration file that Chef InSpec consumes. For details, see [our configuration file documentation](https://www.inspec.io/docs/reference/config/).
27
+ The `html2` reporter requires no configuration to function. However, two options--`alternate_css_file` and `alternate_js_file`--are available for customization. The options are set in the JSON-formatted configuration file that Chef InSpec consumes. For details, see [our configuration file documentation](https://docs.chef.io/inspec/config/).
28
28
 
29
29
  For example:
30
30
 
@@ -1,15 +1,17 @@
1
- # junit reporter
1
+ # junit and junit2 reporters
2
2
 
3
- This is the implementation of the junit XML reporter.
3
+ This is the implementation of the junit and junit2 XML reporters.
4
4
 
5
- ## To Install This Plugin
5
+ ## Installation
6
6
 
7
- This plugin is included with inspec. There is no need to install it separately.
7
+ This plugin ships with Chef InSpec and requires no additional installation.
8
8
 
9
- ## What This Plugin Does
9
+ ## What These Plugins Do
10
10
 
11
- This reporter generates an XML report in Apache Ant JUnit format.
11
+ `junit` is the legacy Chef InSpec JUnit reporter, which is retained for backwards compatibility. It generates an XML report in Apache Ant JUnit format. The output format is considered nonstandard in several ways. New users are advised to use `junit2`.
12
+
13
+ `junit2` is an updated reporter that provides JUnit output according to the schema published by [Windy Road](https://github.com/windyroad/JUnit-Schema).
12
14
 
13
15
  ## Implementation Note
14
16
 
15
- This reporter uses the REXML XML generator, but may use more advanced XML systems for testing. This is to keep packaging requirements for CHef InSpec lightweight and free of compiled dependencies.
17
+ This reporter uses the REXML XML generator at runtime, but uses Nokogiri, a more heavyweight XML library, for testing. This design keeps packaging requirements lightweight and free of compiled dependencies.
@@ -3,10 +3,19 @@ module InspecPlugins
3
3
  module JUnitReporter
4
4
  class Plugin < ::Inspec.plugin(2)
5
5
  plugin_name :'inspec-reporter-junit'
6
+
7
+ # Legacy JUnit reporter, which generates subtly incorrect XML.
6
8
  reporter :junit do
7
9
  require_relative "inspec-reporter-junit/reporter"
8
- InspecPlugins::JUnitReporter::Reporter
10
+ InspecPlugins::JUnitReporter::ReporterV1
9
11
  end
12
+
13
+ # v2 reporter, which generates valid JUnit XML.
14
+ reporter :junit2 do
15
+ require_relative "inspec-reporter-junit/reporter"
16
+ InspecPlugins::JUnitReporter::ReporterV2
17
+ end
18
+
10
19
  end
11
20
  end
12
21
  end
@@ -12,8 +12,8 @@ module InspecPlugins::JUnitReporter
12
12
  testsuites = REXML::Element.new("testsuites")
13
13
  xml_output.add(testsuites)
14
14
 
15
- run_data.profiles.each do |profile|
16
- testsuites.add(build_profile_xml(profile))
15
+ run_data.profiles.each_with_index do |profile, idx|
16
+ testsuites.add(build_profile_xml(profile, idx))
17
17
  end
18
18
 
19
19
  formatter = REXML::Formatters::Pretty.new
@@ -22,7 +22,42 @@ module InspecPlugins::JUnitReporter
22
22
  output(formatter.write(xml_output.root, ""))
23
23
  end
24
24
 
25
- def build_profile_xml(profile)
25
+ def count_profile_tests(profile)
26
+ profile.controls.reduce(0) do |acc, elem|
27
+ acc + elem.results.count
28
+ end
29
+ end
30
+
31
+ def count_profile_failed_tests(profile)
32
+ profile.controls.reduce(0) do |acc, elem|
33
+ acc + elem.results.reduce(0) do |fail_test_total, test_case|
34
+ test_case.status == "failed" ? fail_test_total + 1 : fail_test_total
35
+ end
36
+ end
37
+ end
38
+
39
+ def count_profile_skipped_tests(profile)
40
+ profile.controls.reduce(0) do |acc, elem|
41
+ acc + elem.results.reduce(0) do |skip_test_total, test_case|
42
+ test_case.status == "skipped" ? skip_test_total + 1 : skip_test_total
43
+ end
44
+ end
45
+ end
46
+
47
+ def count_profile_errored_tests(profile)
48
+ profile.controls.reduce(0) do |acc, elem|
49
+ acc + elem.results.reduce(0) do |err_test_total, test_case|
50
+ test_case.backtrace.nil? ? err_test_total : err_test_total + 1
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # This is the "Legacy" JUnit reporter. It produces XML which is not
57
+ # correct according to the JUnit standard. It is retained for backwards
58
+ # compatibility.
59
+ class ReporterV1 < Reporter
60
+ def build_profile_xml(profile, _idx)
26
61
  profile_xml = REXML::Element.new("testsuite")
27
62
  profile_xml.add_attribute("name", profile.name)
28
63
  profile_xml.add_attribute("tests", count_profile_tests(profile))
@@ -55,19 +90,66 @@ module InspecPlugins::JUnitReporter
55
90
 
56
91
  result_xml
57
92
  end
93
+ end
58
94
 
59
- def count_profile_tests(profile)
60
- profile.controls.reduce(0) do |acc, elem|
61
- acc + elem.results.count
95
+ # This is the "Corrected" JUnit reporter. It produces XML which is intended
96
+ # to be valid. It should be used whenever possible.
97
+ class ReporterV2 < Reporter
98
+ def build_profile_xml(profile, idx)
99
+ profile_xml = REXML::Element.new("testsuite")
100
+ profile_xml.add_attribute("name", profile.name)
101
+ profile_xml.add_attribute("tests", count_profile_tests(profile))
102
+ profile_xml.add_attribute("id", idx + 1)
103
+
104
+ # junit2 counts failures and errors separately
105
+ errors = count_profile_errored_tests(profile)
106
+ profile_xml.add_attribute("errors", errors)
107
+ profile_xml.add_attribute("failures", count_profile_failed_tests(profile) - errors)
108
+ profile_xml.add_attribute("skipped", count_profile_skipped_tests(profile))
109
+
110
+ profile_xml.add_attribute("hostname", run_data.platform.target.nil? ? "" : run_data.platform.target.to_s)
111
+ # Author of the schema specified 8601, then went on to add
112
+ # a regex that requires no TZ
113
+ profile_xml.add_attribute("timestamp", Time.now.iso8601.slice(0, 19))
114
+
115
+ # These are empty but are just here to satisfy the schema
116
+ profile_xml.add_attribute("package", "")
117
+ profile_xml.add(REXML::Element.new("properties"))
118
+
119
+ profile_time = 0.0
120
+ profile.controls.each do |control|
121
+ control.results.each do |result|
122
+ profile_time += result.run_time
123
+ profile_xml.add(build_result_xml(profile.name, control, result))
124
+ end
62
125
  end
126
+ profile_xml.add_attribute("time", "%.6f" % profile_time)
127
+
128
+ profile_xml.add(REXML::Element.new("system-out"))
129
+ profile_xml.add(REXML::Element.new("system-err"))
130
+
131
+ profile_xml
63
132
  end
64
133
 
65
- def count_profile_failed_tests(profile)
66
- profile.controls.reduce(0) do |acc, elem|
67
- acc + elem.results.reduce(0) do |fail_test_total, test_case|
68
- test_case.status == "failed" ? fail_test_total + 1 : fail_test_total
69
- end
134
+ def build_result_xml(profile_name, control, result)
135
+ result_xml = REXML::Element.new("testcase")
136
+ result_xml.add_attribute("name", result.code_desc)
137
+ result_xml.add_attribute("classname", control.title.nil? ? "#{profile_name}.Anonymous" : "#{profile_name}.#{control.id}")
138
+
139
+ # <Nokogiri::XML::SyntaxError: 20:0: ERROR: Element 'testcase', attribute 'time': '4.9e-05' is not a valid value of the atomic type 'xs:decimal'.
140
+ # So, we format it.
141
+ result_xml.add_attribute("time", "%.6f" % result.run_time)
142
+
143
+ if result.status == "failed"
144
+ failure_element = REXML::Element.new("failure")
145
+ failure_element.add_attribute("message", result.message)
146
+ failure_element.add_attribute("type", result.resource_title&.to_s || "")
147
+ result_xml.add(failure_element)
148
+ elsif result.status == "skipped"
149
+ result_xml.add_element("skipped")
70
150
  end
151
+
152
+ result_xml
71
153
  end
72
154
  end
73
155
  end
@@ -50,22 +50,6 @@ module CorePluginFunctionalHelper
50
50
  include CorePluginBaseHelper
51
51
  include FunctionalHelper
52
52
 
53
- # TODO: so much duplication! Remove everything we can!
54
- require "train"
55
- TRAIN_CONNECTION = Train.create("local", command_runner: :generic).connection
56
-
57
- # TODO: remove me! it's in test/functional/helper.rb
58
- def run_inspec_process(command_line, opts = {})
59
- prefix = ""
60
- if opts.key?(:prefix)
61
- prefix = opts[:prefix]
62
- elsif opts.key?(:env)
63
- prefix = assemble_env_prefix opts[:env]
64
- end
65
-
66
- TRAIN_CONNECTION.run_command("#{prefix} #{exec_inspec} #{command_line}")
67
- end
68
-
69
53
  # This helper does some fancy footwork to make InSpec think a plugin
70
54
  # under development is temporarily installed.
71
55
  # @param String command_line Invocation, without the word 'inspec'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.22.22
4
+ version: 4.24.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef InSpec Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-26 00:00:00.000000000 Z
11
+ date: 2020-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-telemetry
@@ -33,7 +33,7 @@ dependencies:
33
33
  version: 0.2.13
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
- version: '2.0'
36
+ version: '3.0'
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 0.2.13
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.0'
46
+ version: '3.0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: thor
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -64,26 +64,6 @@ dependencies:
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
66
  version: '2.0'
67
- - !ruby/object:Gem::Dependency
68
- name: json_schemer
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 0.2.1
74
- - - "<"
75
- - !ruby/object:Gem::Version
76
- version: 0.2.12
77
- type: :runtime
78
- prerelease: false
79
- version_requirements: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: 0.2.1
84
- - - "<"
85
- - !ruby/object:Gem::Version
86
- version: 0.2.12
87
67
  - !ruby/object:Gem::Dependency
88
68
  name: method_source
89
69
  requirement: !ruby/object:Gem::Requirement
@@ -130,14 +110,14 @@ dependencies:
130
110
  requirements:
131
111
  - - "~>"
132
112
  - !ruby/object:Gem::Version
133
- version: '3.9'
113
+ version: 3.9.0
134
114
  type: :runtime
135
115
  prerelease: false
136
116
  version_requirements: !ruby/object:Gem::Requirement
137
117
  requirements:
138
118
  - - "~>"
139
119
  - !ruby/object:Gem::Version
140
- version: '3.9'
120
+ version: 3.9.0
141
121
  - !ruby/object:Gem::Dependency
142
122
  name: rspec-its
143
123
  requirement: !ruby/object:Gem::Requirement
@@ -229,6 +209,9 @@ dependencies:
229
209
  - - ">="
230
210
  - !ruby/object:Gem::Version
231
211
  version: 0.9.0
212
+ - - "<"
213
+ - !ruby/object:Gem::Version
214
+ version: '1.1'
232
215
  type: :runtime
233
216
  prerelease: false
234
217
  version_requirements: !ruby/object:Gem::Requirement
@@ -236,6 +219,9 @@ dependencies:
236
219
  - - ">="
237
220
  - !ruby/object:Gem::Version
238
221
  version: 0.9.0
222
+ - - "<"
223
+ - !ruby/object:Gem::Version
224
+ version: '1.1'
239
225
  - !ruby/object:Gem::Dependency
240
226
  name: tty-table
241
227
  requirement: !ruby/object:Gem::Requirement
@@ -638,6 +624,7 @@ files:
638
624
  - lib/inspec/utils/object_traversal.rb
639
625
  - lib/inspec/utils/parser.rb
640
626
  - lib/inspec/utils/pkey_reader.rb
627
+ - lib/inspec/utils/run_data_filters.rb
641
628
  - lib/inspec/utils/simpleconfig.rb
642
629
  - lib/inspec/utils/spdx.rb
643
630
  - lib/inspec/utils/spdx.txt