inspec-core 5.18.14 → 5.21.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +19 -16
  3. data/inspec-core.gemspec +22 -22
  4. data/lib/inspec/base_cli.rb +2 -0
  5. data/lib/inspec/cli.rb +6 -2
  6. data/lib/inspec/dsl.rb +10 -4
  7. data/lib/inspec/enhanced_outcomes.rb +19 -0
  8. data/lib/inspec/env_printer.rb +1 -1
  9. data/lib/inspec/exceptions.rb +2 -0
  10. data/lib/inspec/formatters/base.rb +69 -16
  11. data/lib/inspec/plugin/v2/loader.rb +19 -8
  12. data/lib/inspec/plugin/v2/plugin_types/reporter.rb +1 -0
  13. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +54 -0
  14. data/lib/inspec/reporters/base.rb +1 -0
  15. data/lib/inspec/reporters/cli.rb +94 -3
  16. data/lib/inspec/reporters/json.rb +3 -1
  17. data/lib/inspec/reporters/yaml.rb +3 -1
  18. data/lib/inspec/reporters.rb +2 -1
  19. data/lib/inspec/resources/file.rb +1 -1
  20. data/lib/inspec/resources/http.rb +2 -2
  21. data/lib/inspec/resources/lxc.rb +65 -9
  22. data/lib/inspec/resources/oracledb_session.rb +13 -4
  23. data/lib/inspec/resources/podman.rb +353 -0
  24. data/lib/inspec/resources/podman_container.rb +84 -0
  25. data/lib/inspec/resources/podman_image.rb +108 -0
  26. data/lib/inspec/resources/podman_network.rb +81 -0
  27. data/lib/inspec/resources/podman_pod.rb +101 -0
  28. data/lib/inspec/resources/podman_volume.rb +87 -0
  29. data/lib/inspec/resources/service.rb +1 -1
  30. data/lib/inspec/rule.rb +54 -17
  31. data/lib/inspec/run_data/control.rb +6 -0
  32. data/lib/inspec/run_data/statistics.rb +8 -2
  33. data/lib/inspec/runner.rb +18 -8
  34. data/lib/inspec/runner_rspec.rb +3 -2
  35. data/lib/inspec/schema/exec_json.rb +78 -2
  36. data/lib/inspec/schema/output_schema.rb +4 -1
  37. data/lib/inspec/schema/profile_json.rb +46 -0
  38. data/lib/inspec/schema.rb +91 -0
  39. data/lib/inspec/utils/convert.rb +8 -0
  40. data/lib/inspec/utils/podman.rb +24 -0
  41. data/lib/inspec/utils/waivers/csv_file_reader.rb +34 -0
  42. data/lib/inspec/utils/waivers/excel_file_reader.rb +39 -0
  43. data/lib/inspec/utils/waivers/json_file_reader.rb +15 -0
  44. data/lib/inspec/version.rb +1 -1
  45. data/lib/inspec/waiver_file_reader.rb +61 -0
  46. data/lib/matchers/matchers.rb +7 -1
  47. data/lib/plugins/inspec-init/templates/profiles/alicloud/README.md +27 -0
  48. data/lib/plugins/inspec-init/templates/profiles/alicloud/controls/example.rb +10 -0
  49. data/lib/plugins/inspec-init/templates/profiles/alicloud/inputs.yml +1 -0
  50. data/lib/plugins/inspec-init/templates/profiles/alicloud/inspec.yml +14 -0
  51. data/lib/plugins/inspec-reporter-html2/README.md +1 -1
  52. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +7 -1
  53. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +10 -6
  54. data/lib/plugins/inspec-reporter-html2/templates/default.css +12 -0
  55. data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +7 -1
  56. data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +5 -2
  57. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +39 -13
  58. metadata +25 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba97ee3e25e02fba9b85f797fa1a773d2e8fa7628112be422d187c0e46cfce40
4
- data.tar.gz: a82f51e5c6ba3e1db8c4580f92a33d91bcc2e0c2a8339850e1f168c1569b8818
3
+ metadata.gz: 7f6f86730baadd988c363a823e5e46ba68c318e48b27bbaaba614ce7c33bb71c
4
+ data.tar.gz: f02ca42e9d4e525b82e9cfa61a04b122dc3b09c1e3c96f2ec4440c3fb3053f25
5
5
  SHA512:
6
- metadata.gz: beb78893376f0b92b9cf33741f8fab471f66dd328fa1f28c87b05737da7f73266327eded07ca67f0b91a747625dfcb61011b42c06a25914d01f727b07a962456
7
- data.tar.gz: 193aeef4576e2af4466a176b80e107cd45fe0c0c0f6db290d17696cec1eb7dbf6b58b555bf8c0df4b9bb4a9d5aa8d26f542993b5be1d600a296c3ec50e531d09
6
+ metadata.gz: 597fed943b00ed280a749f05c97d01e29b4d5a85034835e9f242990588b35b740bf56a886b65202777d68b79b5cbd1faf1a48a69c1a4f1f8a00a83ecdece3527
7
+ data.tar.gz: 13aa012d46677b3cd31614dcc118c62b1aa1656f3007d6b105f7822a3c25a45b1b1284eef9fb9e761cf5a03cd8209ffe8518d54ed355c189a2f141788a000694
data/Gemfile CHANGED
@@ -23,9 +23,8 @@ group :omnibus do
23
23
  end
24
24
 
25
25
  group :test do
26
- gem "chefstyle", "~> 2.0.3"
26
+ gem "chefstyle", "~> 2.2.2"
27
27
  gem "concurrent-ruby", "~> 1.0"
28
- gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
29
28
  gem "json_schemer", ">= 0.2.1", "< 0.2.19"
30
29
  gem "m"
31
30
  gem "minitest-sprint", "~> 1.0"
@@ -39,26 +38,30 @@ group :test do
39
38
  gem "simplecov", "~> 0.21"
40
39
  gem "simplecov_json_formatter"
41
40
  gem "webmock", "~> 3.0"
41
+
42
+ if Gem.ruby_version >= Gem::Version.new("3.0.0")
43
+ # html-proofer has a dep on io-event, which is ruby-3 only
44
+ gem "html-proofer", "~> 3.19.4", platforms: :ruby # do not attempt to run proofer on windows. Pinned to 3.19.4 as test is breaking in updated versions.
45
+ end
42
46
  end
43
47
 
44
48
  group :deploy do
45
49
  gem "inquirer"
46
50
  end
47
51
 
48
- # Only include Test Kitchen support if we are on Ruby 2.7 or higher
49
- # as chef-zero support requires Ruby 2.6
50
- # See https://github.com/inspec/inspec/pull/5341
51
- if Gem.ruby_version >= Gem::Version.new("2.7.0")
52
- group :kitchen do
53
- gem "berkshelf"
54
- gem "chef", ">= 16.0" # Required to allow net-ssh > 6
55
- gem "test-kitchen", ">= 2.8"
56
- gem "kitchen-inspec", ">= 2.0"
57
- gem "kitchen-dokken", ">= 2.11"
58
- gem "git"
52
+ group :kitchen do
53
+ gem "berkshelf"
54
+
55
+ # Chef 18 requires ruby 3
56
+ if Gem.ruby_version >= Gem::Version.new("3.0.0")
57
+ gem "chef", ">= 17.0"
58
+ else
59
+ # Ruby 2.7 presumably - TODO remove this when 2.7 is sunsetted
60
+ gem "chef", "~> 16.0"
59
61
  end
60
- end
61
62
 
62
- if Gem.ruby_version < Gem::Version.new("2.7.0")
63
- gem "activesupport", "6.1.4.4"
63
+ gem "test-kitchen", ">= 2.8"
64
+ gem "kitchen-inspec", ">= 2.0"
65
+ gem "kitchen-dokken", ">= 2.11"
66
+ gem "git"
64
67
  end
data/inspec-core.gemspec CHANGED
@@ -18,32 +18,32 @@ Gem::Specification.new do |spec|
18
18
  # the gemfile and gemspec are necessary for appbundler so don't remove it
19
19
  spec.files =
20
20
  Dir.glob("{{lib,etc}/**/*,LICENSE,Gemfile,inspec-core.gemspec}")
21
- .grep_v(%r{(?<!inspec-init/templates/profiles/)(aws|azure|gcp)})
21
+ .grep_v(%r{(?<!inspec-init/templates/profiles/)(aws|azure|gcp|alicloud)})
22
22
  .grep_v(%r{lib/plugins/.*/test/})
23
23
  .reject { |f| File.directory?(f) }
24
24
 
25
25
  # Implementation dependencies
26
- spec.add_dependency "chef-telemetry", "~> 1.0", ">= 1.0.8" # 1.0.8+ removes the http dep
27
- spec.add_dependency "license-acceptance", ">= 0.2.13", "< 3.0"
28
- spec.add_dependency "thor", ">= 0.20", "< 2.0"
29
- spec.add_dependency "method_source", ">= 0.8", "< 2.0"
30
- spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
31
- spec.add_dependency "rspec", ">= 3.9", "<= 3.11"
32
- spec.add_dependency "rspec-its", "~> 1.2"
33
- spec.add_dependency "pry", "~> 0.13"
34
- spec.add_dependency "hashie", ">= 3.4", "< 5.0"
35
- spec.add_dependency "mixlib-log", "~> 3.0"
36
- spec.add_dependency "sslshake", "~> 1.2"
37
- spec.add_dependency "parallel", "~> 1.9"
38
- spec.add_dependency "faraday", ">= 0.9.0", "< 1.5"
39
- spec.add_dependency "faraday_middleware", "~> 1.0"
40
- spec.add_dependency "tty-table", "~> 0.10"
41
- spec.add_dependency "tty-prompt", "~> 0.17"
42
- spec.add_dependency "tomlrb", ">= 1.2", "< 2.1"
43
- spec.add_dependency "addressable", "~> 2.4"
44
- spec.add_dependency "parslet", ">= 1.5", "< 2.0" # Pinned < 2.0, see #5389
45
- spec.add_dependency "semverse", "~> 3.0"
46
- spec.add_dependency "multipart-post", "~> 2.0"
26
+ spec.add_dependency "chef-telemetry", "~> 1.0", ">= 1.0.8" # 1.0.8+ removes the http dep
27
+ spec.add_dependency "license-acceptance", ">= 0.2.13", "< 3.0"
28
+ spec.add_dependency "thor", ">= 0.20", "< 2.0"
29
+ spec.add_dependency "method_source", ">= 0.8", "< 2.0"
30
+ spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
31
+ spec.add_dependency "rspec", ">= 3.9", "<= 3.11"
32
+ spec.add_dependency "rspec-its", "~> 1.2"
33
+ spec.add_dependency "pry", "~> 0.13"
34
+ spec.add_dependency "hashie", ">= 3.4", "< 5.0"
35
+ spec.add_dependency "mixlib-log", "~> 3.0"
36
+ spec.add_dependency "sslshake", "~> 1.2"
37
+ spec.add_dependency "parallel", "~> 1.9"
38
+ spec.add_dependency "faraday", ">= 1", "< 3"
39
+ spec.add_dependency "faraday-follow_redirects", "~> 0.3"
40
+ spec.add_dependency "tty-table", "~> 0.10"
41
+ spec.add_dependency "tty-prompt", "~> 0.17"
42
+ spec.add_dependency "tomlrb", ">= 1.2", "< 2.1"
43
+ spec.add_dependency "addressable", "~> 2.4"
44
+ spec.add_dependency "parslet", ">= 1.5", "< 2.0" # Pinned < 2.0, see #5389
45
+ spec.add_dependency "semverse", "~> 3.0"
46
+ spec.add_dependency "multipart-post", "~> 2.0"
47
47
 
48
48
  spec.add_dependency "train-core", "~> 3.10"
49
49
  end
@@ -205,6 +205,8 @@ module Inspec
205
205
  long_desc: "Maximum seconds to allow commands to run during execution. A timed out command is considered an error."
206
206
  option :reporter_include_source, type: :boolean, default: false,
207
207
  desc: "Include full source code of controls in the CLI report"
208
+ option :enhanced_outcomes, type: :boolean,
209
+ desc: "Show enhanced outcomes in output"
208
210
  end
209
211
 
210
212
  def self.help(*args)
data/lib/inspec/cli.rb CHANGED
@@ -415,6 +415,8 @@ class Inspec::InspecCLI < Inspec::BaseCLI
415
415
  desc: "Load one or more input files, a YAML file with values for the shell to use"
416
416
  option :input, type: :array, banner: "name1=value1 name2=value2",
417
417
  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."
418
+ option :enhanced_outcomes, type: :boolean,
419
+ desc: "Show enhanced outcomes in output"
418
420
  def shell_func
419
421
  o = config
420
422
  deprecate_target_id(config)
@@ -461,11 +463,13 @@ class Inspec::InspecCLI < Inspec::BaseCLI
461
463
  pretty_handle_exception(e)
462
464
  end
463
465
 
466
+ option :enhanced_outcomes, type: :boolean,
467
+ desc: "Show enhanced outcomes output"
464
468
  desc "schema NAME", "print the JSON schema", hide: true
465
469
  def schema(name)
466
470
  require "inspec/schema/output_schema"
467
-
468
- puts Inspec::Schema::OutputSchema.json(name)
471
+ o = config
472
+ puts Inspec::Schema::OutputSchema.json(name, o)
469
473
  rescue StandardError => e
470
474
  puts e
471
475
  puts "Valid schemas are #{Inspec::Schema::OutputSchema.names.join(", ")}"
data/lib/inspec/dsl.rb CHANGED
@@ -91,13 +91,19 @@ module Inspec::DSL
91
91
  if profile_version
92
92
  new_profile_id = "#{profile_id}-#{profile_version}"
93
93
  else
94
+ # This scary regex is used to match version following semantic Versioning (SemVer). Thanks to https://ihateregex.io/expr/semver/
95
+ regex_for_semver = /(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?/
94
96
  dependencies.list.keys.each do |key|
95
- # If dep profile does not contain a source version, key does not contain a version as well. In that case new_profile_id will be always nil and instead profile_id would be used to fetch profile from dependency list.
96
- profile_id_key = key.split("-")
97
- profile_id_key.pop
98
- new_profile_id = key if profile_id_key.join("-") == profile_id
97
+ # 1. Fetching VERSION from a profile dependency name which is in a format NAME-VERSION.
98
+ # 2. Matching original profile dependency name with profile name used with include or require control DSL.
99
+ fetching_semver = key.match(regex_for_semver).to_s
100
+ unless fetching_semver.nil? || fetching_semver.empty?
101
+ profile_id_key = key.split("-#{fetching_semver}")[0]
102
+ new_profile_id = key if profile_id_key == profile_id
103
+ end
99
104
  end
100
105
  end
106
+ # If dep profile does not contain a source version, key does not contain a version as well. In that case new_profile_id will be always nil and instead profile_id would be used to fetch profile from dependency list.
101
107
  dep_entry = new_profile_id ? dependencies.list[new_profile_id] : dependencies.list[profile_id]
102
108
 
103
109
  if dep_entry.nil?
@@ -0,0 +1,19 @@
1
+ module Inspec
2
+ module EnhancedOutcomes
3
+
4
+ def self.determine_status(results, impact)
5
+ # No-op exception occurs in case of not_applicable_if
6
+ if results.any? { |r| !r[:exception].nil? && !r[:backtrace].nil? && r[:resource_class] != "noop" }
7
+ "error"
8
+ elsif !impact.nil? && impact.to_f == 0.0
9
+ "not_applicable"
10
+ elsif results.all? { |r| r[:status] == "skipped" }
11
+ "not_reviewed"
12
+ elsif results.any? { |r| r[:status] == "failed" }
13
+ "failed"
14
+ else
15
+ "passed"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -35,7 +35,7 @@ module Inspec
35
35
  private
36
36
 
37
37
  def print_completion_for_shell
38
- erb = ERB.new(File.read(completion_template_path), nil, "-")
38
+ erb = ERB.new(File.read(completion_template_path), trim_mode: "-")
39
39
  puts erb.result(TemplateContext.new(@command_class).get_bindings)
40
40
  end
41
41
 
@@ -10,5 +10,7 @@ module Inspec
10
10
  class SecretsBackendNotFound < ArgumentError; end
11
11
  class ProfileValidationKeyNotFound < ArgumentError; end
12
12
  class ProfileSigningKeyNotFound < ArgumentError; end
13
+ class WaiversFileNotReadable < ArgumentError; end
14
+ class WaiversFileDoesNotExist < ArgumentError; end
13
15
  end
14
16
  end
@@ -1,12 +1,13 @@
1
1
  require "rspec/core"
2
2
  require "rspec/core/formatters/base_formatter"
3
3
  require "set" unless defined?(Set)
4
+ require "inspec/enhanced_outcomes"
4
5
 
5
6
  module Inspec::Formatters
6
7
  class Base < RSpec::Core::Formatters::BaseFormatter
7
8
  RSpec::Core::Formatters.register self, :close, :dump_summary, :stop
8
9
 
9
- attr_accessor :backend, :run_data
10
+ attr_accessor :backend, :run_data, :enhanced_outcomes
10
11
 
11
12
  def initialize(output)
12
13
  super(output)
@@ -17,6 +18,7 @@ module Inspec::Formatters
17
18
  @backend = nil
18
19
  @all_controls_count = nil
19
20
  @control_checks_count_map = {}
21
+ @enhanced_outcomes = nil
20
22
  end
21
23
 
22
24
  # RSpec Override: #dump_summary
@@ -50,7 +52,6 @@ module Inspec::Formatters
50
52
  else
51
53
  hash[:message] = exception_message(e)
52
54
  end
53
-
54
55
  next if e.is_a? RSpec::Expectations::ExpectationNotMetError
55
56
 
56
57
  hash[:exception] = e.class.name
@@ -68,6 +69,8 @@ module Inspec::Formatters
68
69
  # flesh out the profiles key with additional profile information
69
70
  run_data[:profiles] = profiles_info
70
71
 
72
+ add_enhanced_outcomes_to_controls if enhanced_outcomes
73
+
71
74
  # add the platform information for this particular target
72
75
  run_data[:platform] = {
73
76
  name: platform(:name),
@@ -110,6 +113,20 @@ module Inspec::Formatters
110
113
 
111
114
  private
112
115
 
116
+ def add_enhanced_outcomes_to_controls
117
+ all_unique_controls.each do |control|
118
+ control[:status] = determine_control_enhanced_outcome(control)
119
+ end
120
+ end
121
+
122
+ def determine_control_enhanced_outcome(control)
123
+ if control[:results]
124
+ Inspec::EnhancedOutcomes.determine_status(control[:results], control[:impact])
125
+ else
126
+ "passed"
127
+ end
128
+ end
129
+
113
130
  def all_unique_controls
114
131
  unique_controls = Set.new
115
132
  run_data[:profiles].each do |profile|
@@ -120,25 +137,59 @@ module Inspec::Formatters
120
137
  end
121
138
 
122
139
  def statistics
140
+ error = 0
141
+ not_applicable = 0
142
+ not_reviewed = 0
123
143
  failed = 0
124
- skipped = 0
125
144
  passed = 0
145
+ skipped = 0
146
+ enhanced_outcomes_summary = {}
147
+ if enhanced_outcomes
148
+ all_unique_controls.each do |control|
149
+
150
+ if control[:status] == "error"
151
+ error += 1
152
+ elsif control[:status] == "not_applicable"
153
+ not_applicable += 1
154
+ elsif control[:status] == "not_reviewed"
155
+ not_reviewed += 1
156
+ elsif control[:status] == "failed"
157
+ failed += 1
158
+ elsif control[:status] == "passed"
159
+ passed += 1
160
+ end
126
161
 
127
- all_unique_controls.each do |control|
128
- next unless control[:results]
129
-
130
- if control[:results].any? { |r| r[:status] == "failed" }
131
- failed += 1
132
- elsif control[:results].any? { |r| r[:status] == "skipped" }
133
- skipped += 1
134
- else
135
- passed += 1
136
- end
137
- end
162
+ # added this additionally because stats summary is also used for determining exit code in runner rspec
163
+ skipped += 1 if control[:results].any? { |r| r[:status] == "skipped" }
138
164
 
139
- total = failed + passed + skipped
165
+ end
166
+ total = error + not_applicable + not_reviewed + failed + passed
167
+ enhanced_outcomes_summary = {
168
+ not_applicable: {
169
+ total: not_applicable,
170
+ },
171
+ not_reviewed: {
172
+ total: not_reviewed,
173
+ },
174
+ error: {
175
+ total: error,
176
+ },
177
+ }
178
+ else
179
+ all_unique_controls.each do |control|
180
+ next unless control[:results]
140
181
 
141
- {
182
+ if control[:results].any? { |r| r[:status] == "failed" }
183
+ failed += 1
184
+ elsif control[:results].any? { |r| r[:status] == "skipped" }
185
+ skipped += 1
186
+ else
187
+ passed += 1
188
+ end
189
+ end
190
+ total = failed + passed + skipped
191
+ end
192
+ final_summary = {
142
193
  total: total,
143
194
  passed: {
144
195
  total: passed,
@@ -150,6 +201,8 @@ module Inspec::Formatters
150
201
  total: failed,
151
202
  },
152
203
  }
204
+
205
+ final_summary.merge!(enhanced_outcomes_summary)
153
206
  end
154
207
 
155
208
  def exception_message(exception)
@@ -178,7 +178,19 @@ module Inspec::Plugin::V2
178
178
  # TODO: enforce first-level version pinning
179
179
  plugin_deps = [Gem::Dependency.new(plugin_gem_name.to_s, version_constraint)]
180
180
  managed_gem_set = Gem::Resolver::VendorSet.new
181
- list_managed_gems.each { |spec| managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir) }
181
+
182
+ list_managed_gems.each do |spec|
183
+ if Gem::Specification.load spec.gem_dir
184
+ managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
185
+ else
186
+ # In case of invalid gemspec as mentioned in this PR https://github.com/brianmario/yajl-ruby/pull/223
187
+ # the add_vendor_gem breaks. So this is patch to fix the loading issue.
188
+ # Horribly, chdir to gemspec path to honor . in gemspec
189
+ Dir.chdir(spec.gem_dir) do |dir|
190
+ managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
191
+ end
192
+ end
193
+ end
182
194
 
183
195
  # TODO: Next two lines merge our managed gems with the other gems available
184
196
  # in our "local universe" - which may be the system, or it could be in a Bundler microcosm,
@@ -278,7 +290,12 @@ module Inspec::Plugin::V2
278
290
  when :user_gem
279
291
  status.entry_point = status.name.to_s
280
292
  status.version = plugin_entry[:version]
281
- status.description = fetch_plugin_specs(status.name.to_s)&.summary
293
+ # Fetch the summary of the gem from local gemspec file instead of remote call using Gem::SpecFetcher.fetcher.
294
+ unless plugin_entry[:version].nil? # safe check very rare case.
295
+ version_string = plugin_entry[:version].gsub(/[=,~,>,<]/, "").strip
296
+ plugin_name_with_version = "#{status.name}-#{version_string}"
297
+ status.description = fetch_gemspec(File.join(plugin_gem_path, "gems", plugin_name_with_version, "/", status.name.to_s + ".gemspec"))&.summary
298
+ end
282
299
  when :path
283
300
  status.entry_point = plugin_entry[:installation_path]
284
301
  end
@@ -287,12 +304,6 @@ module Inspec::Plugin::V2
287
304
  end
288
305
  end
289
306
 
290
- def fetch_plugin_specs(plugin_name)
291
- fetcher = Gem::SpecFetcher.fetcher
292
- plugin_dependency = Gem::Dependency.new(plugin_name)
293
- fetcher.spec_for_dependency(plugin_dependency).flatten.first
294
- end
295
-
296
307
  def fixup_train_plugin_status(status)
297
308
  status.api_generation = :'train-1'
298
309
  if status.installation_type == :user_gem
@@ -7,6 +7,7 @@ module Inspec::Plugin::V2::PluginType
7
7
  include Inspec::Utils::RunDataFilters
8
8
 
9
9
  attr_reader :run_data
10
+ attr_accessor :enhanced_outcomes
10
11
 
11
12
  def initialize(config)
12
13
  @config = config
@@ -11,6 +11,7 @@ module Inspec::Plugin::V2::PluginType
11
11
  @running_controls_list = []
12
12
  @control_checks_count_map = {}
13
13
  @controls_count = nil
14
+ @notifications = {}
14
15
  end
15
16
 
16
17
  private
@@ -49,5 +50,58 @@ module Inspec::Plugin::V2::PluginType
49
50
  @control_checks_count_map = RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_control_checks_count_map
50
51
  end
51
52
  end
53
+
54
+ def enhanced_outcomes
55
+ @enhanced_outcomes ||= RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.enhanced_outcomes
56
+ end
57
+
58
+ def add_enhanced_outcomes(control_id)
59
+ if control_has_error(@notifications[control_id])
60
+ "error"
61
+ elsif control_has_impact_zero(@notifications[control_id])
62
+ "not_applicable"
63
+ elsif control_has_all_tests_skipped(@notifications[control_id])
64
+ "not_reviewed"
65
+ elsif control_has_any_tests_failed(@notifications[control_id])
66
+ "failed"
67
+ else
68
+ "passed"
69
+ end
70
+ end
71
+
72
+ def control_has_error(notifications)
73
+ notifications.any? do |notification_data|
74
+ notification, _status = notification_data
75
+ !notification.example.exception.nil? && !(notification.example.exception.is_a? RSpec::Expectations::ExpectationNotMetError) && !notification.example.exception.backtrace.nil? && (!notification.description.include? "No-op") # No-op exception occurs in case of not_applicable_if
76
+ end
77
+ end
78
+
79
+ def control_has_all_tests_skipped(notifications)
80
+ notifications.all? do |notification_data|
81
+ _notification, status = notification_data
82
+ status == "skipped"
83
+ end
84
+ end
85
+
86
+ def control_has_any_tests_failed(notifications)
87
+ notifications.any? do |notification_data|
88
+ _notification, status = notification_data
89
+ status == "failed"
90
+ end
91
+ end
92
+
93
+ def control_has_impact_zero(notifications)
94
+ notification_data = notifications.first
95
+ notification_impact = notification_data.first.example.metadata[:impact]
96
+ notification_data && !notification_impact.nil? && notification_impact.to_f == 0.0
97
+ end
98
+
99
+ def collect_notifications(notification, control_id, status)
100
+ if @notifications[control_id].nil?
101
+ @notifications[control_id] = [[notification, status]]
102
+ else
103
+ @notifications[control_id].push([notification, status])
104
+ end
105
+ end
52
106
  end
53
107
  end
@@ -5,6 +5,7 @@ module Inspec::Reporters
5
5
  include Inspec::Utils::RunDataFilters
6
6
 
7
7
  attr_reader :run_data
8
+ attr_accessor :enhanced_outcomes
8
9
 
9
10
  def initialize(config)
10
11
  @config = config