inspec-core 5.22.65 → 6.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/Chef-EULA +9 -0
  3. data/Gemfile +24 -32
  4. data/etc/features.sig +6 -0
  5. data/etc/features.yaml +94 -0
  6. data/inspec-core.gemspec +15 -14
  7. data/lib/inspec/backend.rb +2 -0
  8. data/lib/inspec/base_cli.rb +80 -4
  9. data/lib/inspec/cached_fetcher.rb +24 -3
  10. data/lib/inspec/cli.rb +292 -235
  11. data/lib/inspec/config.rb +24 -11
  12. data/lib/inspec/dependencies/cache.rb +33 -0
  13. data/lib/inspec/dependencies/dependency_set.rb +2 -2
  14. data/lib/inspec/dsl.rb +1 -1
  15. data/lib/inspec/enhanced_outcomes.rb +1 -0
  16. data/lib/inspec/errors.rb +5 -0
  17. data/lib/inspec/exceptions.rb +2 -0
  18. data/lib/inspec/feature/config.rb +75 -0
  19. data/lib/inspec/feature/runner.rb +26 -0
  20. data/lib/inspec/feature.rb +34 -0
  21. data/lib/inspec/fetcher/git.rb +5 -0
  22. data/lib/inspec/fetcher/url.rb +7 -29
  23. data/lib/inspec/globals.rb +6 -0
  24. data/lib/inspec/input_registry.rb +1 -5
  25. data/lib/inspec/plugin/v1/plugin_types/fetcher.rb +7 -0
  26. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +30 -2
  27. data/lib/inspec/profile.rb +46 -3
  28. data/lib/inspec/reporters/cli.rb +1 -1
  29. data/lib/inspec/reporters.rb +67 -54
  30. data/lib/inspec/resources/nftables.rb +1 -14
  31. data/lib/inspec/resources/oracledb_session.rb +3 -9
  32. data/lib/inspec/resources/postgres_session.rb +1 -1
  33. data/lib/inspec/resources/sybase_session.rb +2 -11
  34. data/lib/inspec/resources/virtualization.rb +1 -1
  35. data/lib/inspec/rule.rb +9 -14
  36. data/lib/inspec/run_data.rb +7 -5
  37. data/lib/inspec/runner.rb +35 -6
  38. data/lib/inspec/runner_rspec.rb +12 -9
  39. data/lib/inspec/secrets/yaml.rb +9 -3
  40. data/lib/inspec/shell.rb +10 -0
  41. data/lib/inspec/ui.rb +4 -0
  42. data/lib/inspec/utils/licensing_config.rb +9 -0
  43. data/lib/inspec/utils/profile_ast_helpers.rb +2 -1
  44. data/lib/inspec/utils/waivers/csv_file_reader.rb +1 -1
  45. data/lib/inspec/utils/waivers/excel_file_reader.rb +1 -1
  46. data/lib/inspec/version.rb +1 -1
  47. data/lib/inspec/waiver_file_reader.rb +68 -27
  48. data/lib/inspec.rb +2 -1
  49. data/lib/matchers/matchers.rb +3 -3
  50. data/lib/plugins/inspec-compliance/README.md +1 -11
  51. data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +189 -170
  52. data/lib/plugins/inspec-habitat/lib/inspec-habitat/cli.rb +10 -3
  53. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
  54. data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +23 -21
  55. data/lib/plugins/inspec-init/lib/inspec-init/cli_profile.rb +15 -13
  56. data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +15 -13
  57. data/lib/plugins/inspec-license/README.md +16 -0
  58. data/lib/plugins/inspec-license/inspec-license.gemspec +6 -0
  59. data/lib/plugins/inspec-license/lib/inspec-license/cli.rb +26 -0
  60. data/lib/plugins/inspec-license/lib/inspec-license.rb +14 -0
  61. data/lib/plugins/inspec-parallel/README.md +27 -0
  62. data/lib/plugins/inspec-parallel/inspec-parallel.gemspec +6 -0
  63. data/lib/plugins/inspec-parallel/lib/inspec-parallel/child_status_reporter.rb +61 -0
  64. data/lib/plugins/inspec-parallel/lib/inspec-parallel/cli.rb +39 -0
  65. data/lib/plugins/inspec-parallel/lib/inspec-parallel/command.rb +219 -0
  66. data/lib/plugins/inspec-parallel/lib/inspec-parallel/runner.rb +265 -0
  67. data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/base.rb +24 -0
  68. data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/silent.rb +7 -0
  69. data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/status.rb +124 -0
  70. data/lib/plugins/inspec-parallel/lib/inspec-parallel/super_reporter/text.rb +23 -0
  71. data/lib/plugins/inspec-parallel/lib/inspec-parallel/validator.rb +170 -0
  72. data/lib/plugins/inspec-parallel/lib/inspec-parallel.rb +18 -0
  73. data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +10 -11
  74. data/lib/plugins/inspec-sign/lib/inspec-sign/cli.rb +11 -4
  75. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +6 -13
  76. data/lib/source_readers/inspec.rb +1 -1
  77. metadata +45 -19
@@ -4,76 +4,89 @@ require "inspec/reporters/json"
4
4
  require "inspec/reporters/json_automate"
5
5
  require "inspec/reporters/automate"
6
6
  require "inspec/reporters/yaml"
7
+ require "inspec/feature"
7
8
 
8
9
  module Inspec::Reporters
9
10
  # rubocop:disable Metrics/CyclomaticComplexity
10
11
  def self.render(reporter, run_data, enhanced_outcomes = false)
11
12
  name, config = reporter.dup
12
- config[:run_data] = run_data
13
- case name
14
- when "cli"
15
- reporter = Inspec::Reporters::CLI.new(config)
16
- when "json"
17
- reporter = Inspec::Reporters::Json.new(config)
18
- # This reporter is only used for Chef internal. We reserve the
19
- # right to introduce breaking changes to this reporter at any time.
20
- when "json-automate"
21
- reporter = Inspec::Reporters::JsonAutomate.new(config)
22
- when "automate"
23
- reporter = Inspec::Reporters::Automate.new(config)
24
- when "yaml"
25
- reporter = Inspec::Reporters::Yaml.new(config)
26
- else
27
- # If we made it here, it must be a plugin, and we know it exists (because we validated it in config.rb)
28
- activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
29
- activator.activate!
30
- reporter = activator.implementation_class.new(config)
31
- end
32
- reporter.enhanced_outcomes = enhanced_outcomes
13
+ Inspec.with_feature("inspec-reporter-#{name}") {
14
+ config[:run_data] = run_data
15
+ case name
16
+ when "cli"
17
+ reporter = Inspec::Reporters::CLI.new(config)
18
+ when "json"
19
+ reporter = Inspec::Reporters::Json.new(config)
20
+ # This reporter is only used for Chef internal. We reserve the
21
+ # right to introduce breaking changes to this reporter at any time.
22
+ when "json-automate"
23
+ reporter = Inspec::Reporters::JsonAutomate.new(config)
24
+ when "automate"
25
+ reporter = Inspec::Reporters::Automate.new(config)
26
+ when "yaml"
27
+ reporter = Inspec::Reporters::Yaml.new(config)
28
+ else
29
+ # If we made it here, it must be a plugin, and we know it exists (because we validated it in config.rb)
30
+ activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
31
+ activator.activate!
32
+ reporter = activator.implementation_class.new(config)
33
+ end
33
34
 
34
- # optional send_report method on reporter
35
- return reporter.send_report if defined?(reporter.send_report)
35
+ if enhanced_outcomes
36
+ Inspec.with_feature("inspec-enhanced-outcomes") {
37
+ reporter.enhanced_outcomes = enhanced_outcomes
38
+ }
39
+ else
40
+ reporter.enhanced_outcomes = enhanced_outcomes
41
+ end
36
42
 
37
- reporter.render
38
- output = reporter.rendered_output
43
+ # optional send_report method on reporter
44
+ return reporter.send_report if defined?(reporter.send_report)
39
45
 
40
- if config["file"]
41
- # create destination directory if it does not exist
42
- dirname = File.dirname(config["file"])
43
- FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
46
+ reporter.render
47
+ output = reporter.rendered_output
48
+ config_file = config["file"]
49
+ if config_file
50
+ config_file.gsub!("CHILD_PID", Process.pid.to_s)
51
+ # create destination directory if it does not exist
52
+ dirname = File.dirname(config_file)
53
+ FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
44
54
 
45
- File.write(config["file"], output)
46
- elsif config["stdout"] == true
47
- print output
48
- $stdout.flush
49
- end
55
+ File.write(config_file, output)
56
+ elsif config["stdout"] == true
57
+ print output
58
+ $stdout.flush
59
+ end
60
+ }
50
61
  end
51
62
 
52
63
  def self.report(reporter, run_data)
53
64
  name, config = reporter.dup
54
- config[:run_data] = run_data
55
- case name
56
- when "json"
57
- reporter = Inspec::Reporters::Json.new(config)
58
- when "json-automate"
59
- reporter = Inspec::Reporters::JsonAutomate.new(config)
60
- when "yaml"
61
- reporter = Inspec::Reporters::Yaml.new(config)
62
- else
63
- # If we made it here, it might be a plugin
64
- begin
65
- activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
66
- activator.activate!
67
- reporter = activator.implementation_class.new(config)
68
- unless reporter.respond_to(:report?)
65
+ Inspec.with_feature("inspec-reporter-#{name}") {
66
+ config[:run_data] = run_data
67
+ case name
68
+ when "json"
69
+ reporter = Inspec::Reporters::Json.new(config)
70
+ when "json-automate"
71
+ reporter = Inspec::Reporters::JsonAutomate.new(config)
72
+ when "yaml"
73
+ reporter = Inspec::Reporters::Yaml.new(config)
74
+ else
75
+ # If we made it here, it might be a plugin
76
+ begin
77
+ activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
78
+ activator.activate!
79
+ reporter = activator.implementation_class.new(config)
80
+ unless reporter.respond_to(:report?)
81
+ return run_data
82
+ end
83
+ rescue Inspec::Plugin::V2::LoadError
84
+ # Must not have been a plugin - just return the run_data
69
85
  return run_data
70
86
  end
71
- rescue Inspec::Plugin::V2::LoadError
72
- # Must not have been a plugin - just return the run_data
73
- return run_data
74
87
  end
75
- end
76
88
 
77
- reporter.report
89
+ reporter.report
90
+ }
78
91
  end
79
92
  end
@@ -135,20 +135,7 @@ module Inspec::Resources
135
135
  cmd = inspec.command(nftables_cmd)
136
136
  return [] if cmd.exit_status.to_i != 0
137
137
 
138
- # https://github.com/inspec/inspec/security/code-scanning/10
139
- # Update @nftables_cache with sanitized command output
140
- @nftables_cache[idx] = cmd.stdout.gsub("\t", "").split("\n")
141
- .reject { |line| line =~ /^(table|set|type|size|flags|typeof|auto-merge)/ || line =~ /^}$/ } # Reject lines that match certain patterns
142
- .map { |line| line.gsub("elements = {", "").gsub("}", "").split(",") } # Use gsub to replace all occurrences of specified strings
143
- .flatten # Flatten the array of arrays into a single array
144
- .map(&:strip) # Remove leading and trailing whitespace from each element
145
- .map { |element| sanitize_input(element) } # Sanitize each element to prevent injection attacks
146
- end
147
-
148
- # Method to sanitize input
149
- def sanitize_input(input)
150
- # Replace potentially dangerous characters with their escaped counterparts
151
- input.gsub(/([\\'";])/, '\\\\\1')
138
+ @nftables_cache[idx] = cmd.stdout.gsub("\t", "").split("\n").reject { |line| line =~ /^(table|set|type|size|flags|typeof|auto-merge)/ || line =~ /^}$/ }.map { |line| line.sub("elements = {", "").sub("}", "").split(",") }.flatten.map(&:strip)
152
139
  end
153
140
 
154
141
  def retrieve_chain_rules
@@ -57,7 +57,7 @@ module Inspec::Resources
57
57
  inspec_cmd = inspec.command(command)
58
58
  out = inspec_cmd.stdout + "\n" + inspec_cmd.stderr
59
59
 
60
- if inspec_cmd.exit_status != 0 || out.downcase =~ /^error.*/
60
+ if inspec_cmd.exit_status != 0 || !inspec_cmd.stderr.empty? || out.downcase =~ /^error.*/
61
61
  raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
62
62
  else
63
63
  begin
@@ -96,7 +96,8 @@ module Inspec::Resources
96
96
  if @db_role.nil? || @su_user.nil?
97
97
  verified_query = verify_query(query)
98
98
  else
99
- escaped_query = escape_query(query)
99
+ escaped_query = query.gsub(/\\\\/, "\\").gsub(/"/, '\\"')
100
+ escaped_query = escaped_query.gsub("$", '\\$') unless escaped_query.include? "\\$"
100
101
  verified_query = verify_query(escaped_query)
101
102
  end
102
103
 
@@ -133,17 +134,10 @@ module Inspec::Resources
133
134
  query
134
135
  end
135
136
 
136
- def escape_query(query)
137
- escaped_query = query.gsub(/\\\\/, "\\").gsub(/"/, '\\"')
138
- escaped_query = escaped_query.gsub("$", '\\$') unless escaped_query.include? "\\$"
139
- escaped_query
140
- end
141
-
142
137
  def parse_csv_result(stdout)
143
138
  output = stdout.split("oracle_query_string")[-1]
144
139
  # comma_query_sub replaces the csv delimiter "," in the output.
145
140
  # Handles CSV parsing of data like this (DROP,3) etc
146
-
147
141
  output = output.sub(/\r/, "").strip.gsub(",", "comma_query_sub")
148
142
  converter = ->(header) { header.downcase }
149
143
  CSV.parse(output, headers: true, header_converters: converter).map do |row|
@@ -55,7 +55,7 @@ module Inspec::Resources
55
55
  psql_cmd = create_psql_cmd(query, db)
56
56
  cmd = inspec.command(psql_cmd, redact_regex: %r{(:\/\/[a-z]*:).*(@)})
57
57
  out = cmd.stdout + "\n" + cmd.stderr
58
- if cmd.exit_status != 0 && ( out =~ /could not connect to/ || out =~ /password authentication failed/ ) && (out.downcase =~ /error:/ || out.downcase =~ /fatal:/)
58
+ if cmd.exit_status != 0 && ( out =~ /could not connect to/ || out =~ /password authentication failed/ ) && out.downcase =~ /error:/
59
59
  raise Inspec::Exceptions::ResourceFailed, "PostgreSQL connection error: #{out}"
60
60
  elsif cmd.exit_status != 0 && out.downcase =~ /error:/
61
61
  Lines.new(out, "PostgreSQL query with error: #{query}", cmd.exit_status)
@@ -44,19 +44,10 @@ module Inspec::Resources
44
44
  # try to get a temp path
45
45
  sql_file_path = upload_sql_file(sql)
46
46
 
47
- # TODO: Find if there is better way to get the current shell
48
- current_shell = inspec.command("echo $SHELL")
49
-
50
- res = current_shell.exit_status
51
-
52
47
  # isql reuires that we have a matching locale set, but does not support C.UTF-8. en_US.UTF-8 is the least evil.
53
- if res == 0 && ( current_shell.stdout&.include?("/csh") || current_shell.stdout&.include?("/tcsh") )
54
- command = "source #{sybase_home}/SYBASE.csh; setenv LANG en_US.UTF-8; #{bin} -s\"#{col_sep}\" -w80000 -S #{server} -U #{username} -D #{database} -P \"#{password}\" < #{sql_file_path}"
55
- else
56
- command = "LANG=en_US.UTF-8 SYBASE=#{sybase_home} #{bin} -s\"#{col_sep}\" -w80000 -S #{server} -U #{username} -D #{database} -P \"#{password}\" < #{sql_file_path}"
57
- end
58
-
48
+ command = "LANG=en_US.UTF-8 SYBASE=#{sybase_home} #{bin} -s\"#{col_sep}\" -w80000 -S #{server} -U #{username} -D #{database} -P \"#{password}\" < #{sql_file_path}"
59
49
  isql_cmd = inspec.command(command)
50
+
60
51
  # Check for isql errors
61
52
  res = isql_cmd.exit_status
62
53
  raise Inspec::Exceptions::ResourceFailed.new("isql exited with code #{res} and stderr '#{isql_cmd.stderr}', stdout '#{isql_cmd.stdout}'") unless res == 0
@@ -223,7 +223,7 @@ module Inspec::Resources
223
223
  elsif cgroup_content =~ %r{^\d+:[^:]+:/(kubepods)/.+$}
224
224
  @virtualization_data[:system] = $1
225
225
  @virtualization_data[:role] = "guest"
226
- elsif /container=podman/.match?(inspec.file("/proc/1/environ").content)
226
+ elsif /container=podman/.match?(file_read("/proc/1/environ"))
227
227
  @virtualization_data[:system] = "podman"
228
228
  @virtualization_data[:role] = "guest"
229
229
  elsif lxc_version_exists? && cgroup_content =~ %r{\d:[^:]+:/$}
data/lib/inspec/rule.rb CHANGED
@@ -375,24 +375,19 @@ module Inspec
375
375
  # only_if mechanism)
376
376
  # Double underscore: not intended to be called as part of the DSL
377
377
  def __apply_waivers
378
- @__waiver_data = nil
379
378
  control_id = @__rule_id # TODO: control ID slugging
380
-
381
379
  waiver_files = Inspec::Config.cached.final_options["waiver_file"] if Inspec::Config.cached.respond_to?(:final_options)
382
- unless waiver_files.nil? || waiver_files.empty?
383
- waiver_data_by_profile = Inspec::WaiverFileReader.fetch_waivers_by_profile(__profile_id, waiver_files)
384
- return unless waiver_data_by_profile && waiver_data_by_profile[control_id] && waiver_data_by_profile[control_id].is_a?(Hash)
385
380
 
386
- @__waiver_data = waiver_data_by_profile[control_id]
387
- else
388
- # Support for input registry is provided for backward compatibilty with compliance phase of chef-client
389
- # Chef-client sends waiver information in inputs hash
390
- input_registry = Inspec::InputRegistry.instance
391
- waiver_data_via_input = input_registry.inputs_by_profile.dig(__profile_id, control_id)
392
- return unless waiver_data_via_input && waiver_data_via_input.has_value? && waiver_data_via_input.value.is_a?(Hash)
381
+ waiver_data_by_profile = Inspec::WaiverFileReader.fetch_waivers_by_profile(__profile_id, waiver_files) unless waiver_files.nil?
393
382
 
394
- @__waiver_data = waiver_data_via_input.value
395
- end
383
+ return unless waiver_data_by_profile && waiver_data_by_profile[control_id] && waiver_data_by_profile[control_id].is_a?(Hash)
384
+
385
+ # An InSpec Input is a datastructure that tracks a profile parameter
386
+ # over time. Its value can be set by many sources, and it keeps a
387
+ # log of each "set" event so that when it is collapsed to a value,
388
+ # it can determine the correct (highest priority) value.
389
+ # Store in an instance variable for.. later reading???
390
+ @__waiver_data = waiver_data_by_profile[control_id]
396
391
 
397
392
  __waiver_data["skipped_due_to_waiver"] = false
398
393
  __waiver_data["message"] = ""
@@ -27,11 +27,13 @@ module Inspec
27
27
  ) do
28
28
  include HashLikeStruct
29
29
  def initialize(raw_run_data)
30
- self.controls = raw_run_data[:controls].map { |c| Inspec::RunData::Control.new(c) }
31
- self.profiles = raw_run_data[:profiles].map { |p| Inspec::RunData::Profile.new(p) }
32
- self.statistics = Inspec::RunData::Statistics.new(raw_run_data[:statistics])
33
- self.platform = Inspec::RunData::Platform.new(raw_run_data[:platform])
34
- self.version = raw_run_data[:version]
30
+ @raw_run_data = raw_run_data
31
+
32
+ self.controls = @raw_run_data[:controls].map { |c| Inspec::RunData::Control.new(c) }
33
+ self.profiles = @raw_run_data[:profiles].map { |p| Inspec::RunData::Profile.new(p) }
34
+ self.statistics = Inspec::RunData::Statistics.new(@raw_run_data[:statistics])
35
+ self.platform = Inspec::RunData::Platform.new(@raw_run_data[:platform])
36
+ self.version = @raw_run_data[:version]
35
37
  end
36
38
  end
37
39
 
data/lib/inspec/runner.rb CHANGED
@@ -11,6 +11,7 @@ require "inspec/dependencies/cache"
11
11
  require "inspec/dist"
12
12
  require "inspec/reporters"
13
13
  require "inspec/runner_rspec"
14
+ require "chef-licensing"
14
15
  # spec requirements
15
16
 
16
17
  module Inspec
@@ -60,11 +61,13 @@ module Inspec
60
61
  end
61
62
 
62
63
  if @conf[:waiver_file]
63
- @conf[:waiver_file].each do |file|
64
- unless File.file?(file)
65
- raise Inspec::Exceptions::WaiversFileDoesNotExist, "Waiver file #{file} does not exist."
64
+ Inspec.with_feature("inspec-waivers") {
65
+ @conf[:waiver_file].each do |file|
66
+ unless File.file?(file)
67
+ raise Inspec::Exceptions::WaiversFileDoesNotExist, "Waiver file #{file} does not exist."
68
+ end
66
69
  end
67
- end
70
+ }
68
71
  end
69
72
 
70
73
  # About reading inputs:
@@ -142,7 +145,7 @@ module Inspec
142
145
  get_check_example(m, a, b)
143
146
  end.compact
144
147
 
145
- examples.map { |example| total_checks += example.descendant_filtered_examples.count }
148
+ examples.map { |example| total_checks += example.examples.count }
146
149
 
147
150
  unless control_describe_checks.empty?
148
151
  # controls with empty tests are avoided
@@ -159,16 +162,42 @@ module Inspec
159
162
  end
160
163
 
161
164
  def run(with = nil)
165
+ ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
166
+
167
+ # Validate if profiles are signed and verified
168
+ # Additional check is required to provide error message in case of inspec exec command (exec command can use multiple profiles as well)
169
+ # Only runs this block when preview flag CHEF_PREVIEW_MANDATORY_PROFILE_SIGNING is set
170
+ Inspec.with_feature("inspec-mandatory-profile-signing") {
171
+ unless @conf.allow_unsigned_profiles?
172
+ verify_target_profiles_if_signed(@target_profiles)
173
+ end
174
+ }
175
+
162
176
  Inspec::Log.debug "Starting run with targets: #{@target_profiles.map(&:to_s)}"
163
177
  load
164
178
  run_tests(with)
179
+ rescue ChefLicensing::SoftwareNotEntitled
180
+ Inspec::Log.error "License is not entitled to use InSpec."
181
+ Inspec::UI.new.exit(:license_not_entitled)
182
+ rescue ChefLicensing::Error => e
183
+ Inspec::Log.error e.message
184
+ Inspec::UI.new.exit(:usage_error)
185
+ end
186
+
187
+ def verify_target_profiles_if_signed(target_profiles)
188
+ unsigned_profiles = []
189
+ target_profiles.each do |profile|
190
+ unsigned_profiles << profile.name unless profile.verify_if_signed
191
+ end
192
+ raise Inspec::ProfileSignatureRequired, "Signature required for profile/s: #{unsigned_profiles.join(", ")}. Please provide a signed profile. Or set CHEF_ALLOW_UNSIGNED_PROFILES in the environment. Or use `--allow-unsigned-profiles` flag with InSpec CLI. " unless unsigned_profiles.empty?
165
193
  end
166
194
 
167
195
  def render_output(run_data)
168
196
  return if @conf["reporter"].nil?
169
197
 
170
198
  @conf["reporter"].each do |reporter|
171
- result = Inspec::Reporters.render(reporter, run_data, @conf["enhanced_outcomes"])
199
+ enhanced_outcome_flag = @conf["enhanced_outcomes"]
200
+ result = Inspec::Reporters.render(reporter, run_data, enhanced_outcome_flag)
172
201
  raise Inspec::ReporterError, "Error generating reporter '#{reporter[0]}'" if result == false
173
202
  end
174
203
  end
@@ -177,16 +177,18 @@ module Inspec
177
177
  next unless streaming_reporters.include? streaming_reporter_name
178
178
 
179
179
  # Activate the plugin so the formatter ID gets registered with RSpec, presumably
180
- activator = reg.find_activator(plugin_type: :streaming_reporter, activator_name: streaming_reporter_name.to_sym)
181
- activator.activate!
182
180
 
183
- # We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
184
- if file_target&.[]("file").nil?
185
- RSpec.configuration.add_formatter(activator.implementation_class)
186
- else
187
- RSpec.configuration.add_formatter(activator.implementation_class, file_target["file"])
188
- end
189
- @conf["reporter"].delete(streaming_reporter_name)
181
+ Inspec.with_feature("inspec-reporter-#{streaming_reporter_name}") {
182
+ activator = reg.find_activator(plugin_type: :streaming_reporter, activator_name: streaming_reporter_name.to_sym)
183
+ activator.activate!
184
+ # We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
185
+ if file_target&.[]("file").nil?
186
+ RSpec.configuration.add_formatter(activator.implementation_class)
187
+ else
188
+ RSpec.configuration.add_formatter(activator.implementation_class, file_target["file"])
189
+ end
190
+ @conf["reporter"].delete(streaming_reporter_name)
191
+ }
190
192
  end
191
193
  end
192
194
 
@@ -196,6 +198,7 @@ module Inspec
196
198
  def configure_output
197
199
  RSpec.configuration.output_stream = $stdout
198
200
  @formatter = RSpec.configuration.add_formatter(Inspec::Formatters::Base)
201
+
199
202
  @formatter.enhanced_outcomes = @conf.final_options["enhanced_outcomes"]
200
203
  RSpec.configuration.add_formatter(Inspec::Formatters::ShowProgress, $stderr) if @conf[:show_progress]
201
204
  set_optional_formatters
@@ -24,12 +24,18 @@ module Secrets
24
24
  @inputs = ::YAML.load_file(target)
25
25
  end
26
26
 
27
- if @inputs == false || !@inputs.is_a?(Hash)
28
- Inspec::Log.warn("#{self.class} unable to parse #{target}: invalid YAML or contents is not a Hash")
27
+ # In case of empty yaml file raise the warning else raise the parsing error.
28
+ if !@inputs || @inputs.empty?
29
+ Inspec::Log.warn("Unable to parse #{target}: YAML file is empty.")
29
30
  @inputs = nil
31
+ elsif !@inputs.is_a?(Hash)
32
+ # Exits with usage error.
33
+ Inspec::Log.error("Unable to parse #{target}: invalid YAML or contents is not a Hash")
34
+ Inspec::UI.new.exit(:usage_error)
30
35
  end
31
36
  rescue => e
32
- raise "Error reading InSpec inputs: #{e}"
37
+ # Any other error related to Yaml parsing will be raised here.
38
+ raise "Error reading YAML file #{target}: #{e}"
33
39
  end
34
40
  end
35
41
  end
data/lib/inspec/shell.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require "chef-licensing"
2
+ require "inspec/dist"
3
+
1
4
  autoload :Pry, "pry"
2
5
 
3
6
  module Inspec
@@ -10,6 +13,7 @@ module Inspec
10
13
  end
11
14
 
12
15
  def start
16
+ ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
13
17
  # This will hold a single evaluation binding context as opened within
14
18
  # the instance_eval context of the anonymous class that the profile
15
19
  # context creates to evaluate each individual test file. We want to
@@ -18,6 +22,12 @@ module Inspec
18
22
  @ctx_binding = @runner.eval_with_virtual_profile("binding")
19
23
  configure_pry
20
24
  @ctx_binding.pry
25
+ rescue ChefLicensing::SoftwareNotEntitled
26
+ Inspec::Log.error "License is not entitled to use InSpec."
27
+ Inspec::UI.new.exit(:license_not_entitled)
28
+ rescue ChefLicensing::Error => e
29
+ Inspec::Log.error e.message
30
+ Inspec::UI.new.exit(:usage_error)
21
31
  end
22
32
 
23
33
  def configure_pry # rubocop:disable Metrics/AbcSize
data/lib/inspec/ui.rb CHANGED
@@ -32,9 +32,13 @@ module Inspec
32
32
  EXIT_FATAL_DEPRECATION = 3
33
33
  EXIT_GEM_DEPENDENCY_LOAD_ERROR = 4
34
34
  EXIT_BAD_SIGNATURE = 5
35
+ EXIT_SIGNATURE_REQUIRED = 6
35
36
  EXIT_LICENSE_NOT_ACCEPTED = 172
37
+ EXIT_LICENSE_NOT_ENTITLED = 173
38
+ EXIT_LICENSE_NOT_SET = 174
36
39
  EXIT_FAILED_TESTS = 100
37
40
  EXIT_SKIPPED_TESTS = 101
41
+ EXIT_TERMINATED_BY_CTL_C = 130
38
42
 
39
43
  attr_reader :io
40
44
 
@@ -0,0 +1,9 @@
1
+ require_relative "../log"
2
+ require "chef-licensing"
3
+ ChefLicensing.configure do |config|
4
+ config.chef_product_name = "InSpec"
5
+ config.chef_entitlement_id = "3ff52c37-e41f-4f6c-ad4d-365192205968"
6
+ config.chef_executable_name = "inspec"
7
+ config.license_server_url = "https://services.chef.io/licensing"
8
+ config.logger = Inspec::Log
9
+ end
@@ -3,7 +3,8 @@ require "rubocop-ast"
3
3
  module Inspec
4
4
  class Profile
5
5
  class AstHelper
6
- class CollectorBase < Parser::AST::Processor
6
+ class CollectorBase
7
+ include Parser::AST::Processor::Mixin
7
8
  include RuboCop::AST::Traversal
8
9
 
9
10
  attr_reader :memo
@@ -19,7 +19,7 @@ module Waivers
19
19
  row_hash.delete("control_id")
20
20
  row_hash.delete_if { |k, v| k.nil? || v.nil? }
21
21
 
22
- waiver_data_hash[control_id] = row_hash if control_id && !(row_hash.nil? || row_hash.empty?)
22
+ waiver_data_hash[control_id] = row_hash if control_id && !row_hash.blank?
23
23
  end
24
24
 
25
25
  waiver_data_hash
@@ -25,7 +25,7 @@ module Waivers
25
25
  row_hash.delete_if { |k, v| k.nil? || v.nil? }
26
26
  end
27
27
 
28
- waiver_data_hash[control_id] = row_hash if control_id && !(row_hash.nil? || row_hash.empty?)
28
+ waiver_data_hash[control_id] = row_hash if control_id && !row_hash.blank?
29
29
  end
30
30
  waiver_data_hash
31
31
  rescue Exception => e
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "5.22.65".freeze
2
+ VERSION = "6.6.0".freeze
3
3
  end