inspec-core 6.8.24 → 7.0.38.beta

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -6
  3. data/etc/deprecations.json +15 -6
  4. data/lib/inspec/base_cli.rb +3 -0
  5. data/lib/inspec/cached_fetcher.rb +16 -1
  6. data/lib/inspec/dependencies/cache.rb +48 -4
  7. data/lib/inspec/dsl.rb +40 -11
  8. data/lib/inspec/exceptions.rb +1 -0
  9. data/lib/inspec/fetcher/gem.rb +99 -0
  10. data/lib/inspec/fetcher/local.rb +1 -1
  11. data/lib/inspec/fetcher.rb +1 -0
  12. data/lib/inspec/file_provider.rb +46 -1
  13. data/lib/inspec/input_registry.rb +1 -1
  14. data/lib/inspec/plugin/v2/concerns/gem_spec_helper.rb +30 -0
  15. data/lib/inspec/plugin/v2/gem_source_manager.rb +43 -0
  16. data/lib/inspec/plugin/v2/installer.rb +42 -16
  17. data/lib/inspec/plugin/v2/loader.rb +34 -5
  18. data/lib/inspec/plugin/v2/plugin_types/resource_pack.rb +8 -0
  19. data/lib/inspec/plugin/v2.rb +1 -0
  20. data/lib/inspec/profile.rb +10 -0
  21. data/lib/inspec/profile_context.rb +10 -0
  22. data/lib/inspec/reporters/automate.rb +2 -2
  23. data/lib/inspec/resources/auditd.rb +1 -1
  24. data/lib/inspec/resources/groups.rb +52 -0
  25. data/lib/inspec/resources/port.rb +2 -2
  26. data/lib/inspec/resources/postgres_session.rb +5 -9
  27. data/lib/inspec/resources/yum.rb +1 -1
  28. data/lib/inspec/resources.rb +0 -14
  29. data/lib/inspec/runner.rb +7 -15
  30. data/lib/inspec/source_reader.rb +2 -0
  31. data/lib/inspec/ui.rb +1 -0
  32. data/lib/inspec/utils/deprecation/config_file.rb +39 -3
  33. data/lib/inspec/utils/deprecation/deprecator.rb +10 -3
  34. data/lib/inspec/utils/licensing_config.rb +1 -15
  35. data/lib/inspec/utils/parser.rb +9 -19
  36. data/lib/inspec/utils/telemetry.rb +1 -3
  37. data/lib/inspec/version.rb +1 -1
  38. data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +2 -4
  39. data/lib/source_readers/gem.rb +67 -0
  40. data/lib/source_readers/inspec.rb +1 -1
  41. metadata +9 -32
  42. data/lib/inspec/resources/docker.rb +0 -274
  43. data/lib/inspec/resources/docker_container.rb +0 -116
  44. data/lib/inspec/resources/docker_image.rb +0 -141
  45. data/lib/inspec/resources/docker_object.rb +0 -52
  46. data/lib/inspec/resources/docker_plugin.rb +0 -68
  47. data/lib/inspec/resources/docker_service.rb +0 -95
  48. data/lib/inspec/resources/elasticsearch.rb +0 -165
  49. data/lib/inspec/resources/ibmdb2_conf.rb +0 -65
  50. data/lib/inspec/resources/ibmdb2_session.rb +0 -78
  51. data/lib/inspec/resources/mongodb.rb +0 -69
  52. data/lib/inspec/resources/mongodb_conf.rb +0 -44
  53. data/lib/inspec/resources/mongodb_session.rb +0 -98
  54. data/lib/inspec/resources/podman.rb +0 -353
  55. data/lib/inspec/resources/podman_container.rb +0 -84
  56. data/lib/inspec/resources/podman_image.rb +0 -108
  57. data/lib/inspec/resources/podman_network.rb +0 -81
  58. data/lib/inspec/resources/podman_pod.rb +0 -101
  59. data/lib/inspec/resources/podman_volume.rb +0 -87
  60. data/lib/inspec/resources/rabbitmq_conf.rb +0 -2
  61. data/lib/inspec/resources/rabbitmq_config.rb +0 -56
  62. data/lib/inspec/resources/ssh_config.rb +0 -215
  63. data/lib/inspec/resources/ssh_key.rb +0 -124
  64. data/lib/inspec/resources/sshd_active_config.rb +0 -2
  65. data/lib/inspec/resources/sshd_config.rb +0 -2
  66. data/lib/inspec/resources/sybase_conf.rb +0 -41
  67. data/lib/inspec/resources/sybase_session.rb +0 -124
  68. data/lib/inspec/utils/deprecated_core_resources_list.rb +0 -25
  69. data/lib/inspec/utils/podman.rb +0 -24
@@ -2,6 +2,7 @@ require "inspec/log"
2
2
  require "inspec/version"
3
3
  require "inspec/plugin/v2/config_file"
4
4
  require "inspec/plugin/v2/filter"
5
+ require "inspec/plugin/v2/concerns/gem_spec_helper"
5
6
 
6
7
  module Inspec::Plugin::V2
7
8
  class Loader
@@ -10,6 +11,7 @@ module Inspec::Plugin::V2
10
11
  # For {inspec|train}_plugin_name?
11
12
  include Inspec::Plugin::V2::FilterPredicates
12
13
  extend Inspec::Plugin::V2::FilterPredicates
14
+ include Inspec::Plugin::V2::GemSpecHelper
13
15
 
14
16
  def initialize(options = {})
15
17
  @options = options
@@ -157,6 +159,33 @@ module Inspec::Plugin::V2
157
159
  self.class.list_managed_gems
158
160
  end
159
161
 
162
+ def self.find_gem_directory(gem_name, version = nil)
163
+ selected_gemspec = find_gemspec_of(gem_name, version)
164
+ selected_gemspec&.full_gem_path
165
+ end
166
+
167
+ def self.find_gemspec_directory(gem_name, version = nil)
168
+ selected_gemspec = find_gemspec_of(gem_name, version)
169
+ selected_gemspec&.loaded_from
170
+ end
171
+
172
+ def self.find_gemspec_of(gem_name, version = nil)
173
+ version = Gem::Version.new(version) if version && !version.is_a?(Gem::Version)
174
+
175
+ list_managed_gems
176
+ .select { |g| g.name == gem_name }
177
+ .sort_by(&:version)
178
+ .yield_self { |gems| version ? gems.find { |g| g.version == version } : gems.last }
179
+ end
180
+
181
+ def find_gemspec_directory(gem_name, version = nil)
182
+ self.class.find_gemspec_directory(gem_name, version)
183
+ end
184
+
185
+ def find_gem_directory(gem_name, version = nil)
186
+ self.class.find_gem_directory(gem_name, version)
187
+ end
188
+
160
189
  # Lists all plugin gems found in the plugin_gem_path.
161
190
  # This is simply all gems that begin with train- or inspec-
162
191
  # and are not on the exclusion list.
@@ -169,8 +198,6 @@ module Inspec::Plugin::V2
169
198
  self.class.list_managed_gems
170
199
  end
171
200
 
172
- private
173
-
174
201
  # 'Activating' a gem adds it to the load path, so 'require "gemname"' will work.
175
202
  # Given a gem name, this activates the gem and all of its dependencies, respecting
176
203
  # version pinning needs.
@@ -208,13 +235,15 @@ module Inspec::Plugin::V2
208
235
  raise ex
209
236
  end
210
237
  solution.each do |activation_request|
211
- next if activation_request.full_spec.activated?
238
+ requested_gemspec = activation_request.full_spec
239
+ next if requested_gemspec.activated?
212
240
 
213
- activation_request.full_spec.activate
214
- # TODO: If we are under Bundler, inform it that we loaded a gem
241
+ requested_gemspec.activate unless loaded_recent_most_version_of?(requested_gemspec)
215
242
  end
216
243
  end
217
244
 
245
+ private
246
+
218
247
  def annotate_status_after_loading(plugin_name)
219
248
  status = registry[plugin_name]
220
249
  return if status.api_generation == 2 # Gen2 have self-annotating superclasses
@@ -0,0 +1,8 @@
1
+ module Inspec::Plugin::V2::PluginType
2
+ class ResourcePack < Inspec::Plugin::V2::PluginBase
3
+ register_plugin_type(:resource_pack)
4
+
5
+ # TODO: Any DSL definitions would go here
6
+
7
+ end
8
+ end
@@ -13,6 +13,7 @@ module Inspec
13
13
  end
14
14
 
15
15
  class InstallError < Inspec::Plugin::V2::GemActionError; end
16
+ class InstallRequiredError < Inspec::Plugin::V2::InstallError; end
16
17
 
17
18
  class PluginExcludedError < Inspec::Plugin::V2::InstallError
18
19
  attr_accessor :details
@@ -391,6 +391,16 @@ module Inspec
391
391
  included_tags
392
392
  end
393
393
 
394
+ # InSpec 7 introduced gem-based resource packs, so some "profiles" are now gem-based
395
+ # In this case, they are backed by a gem that contains an inspec.yml and a lib/PATH/plugin.rb
396
+ # which contains activator code which needs to be fired.
397
+ def activate_plugin_if_gem_based
398
+ return unless source_reader.is_a?(SourceReaders::GemReader)
399
+
400
+ reg = Inspec::Plugin::V2::Registry.instance
401
+ reg.find_activator(plugin_name: name.to_sym).activate!
402
+ end
403
+
394
404
  def load_libraries
395
405
  return @runner_context if @libraries_loaded
396
406
 
@@ -121,6 +121,7 @@ module Inspec
121
121
  @control_subcontexts << context
122
122
  end
123
123
 
124
+ # Expects arrays of arrays of [[content, path, line]]
124
125
  def load_libraries(libs)
125
126
  lib_prefix = "libraries" + File::SEPARATOR
126
127
  autoloads = []
@@ -130,11 +131,20 @@ module Inspec
130
131
  next unless source.end_with?(".rb")
131
132
 
132
133
  path = source
134
+ # Create a list of files (presumably resources) to autoload by stripping the prefixes
135
+ # InSpec < 6: libraries/*.rb
136
+ # In InSpec 7, libraries can be installed under (for example)
137
+ # lib/inspec-test-resources/resources/demo_resource.rb
138
+
133
139
  if source.start_with?(lib_prefix)
134
140
  path = source.sub(lib_prefix, "")
135
141
  no_subdir = File.dirname(path) == "."
136
142
 
137
143
  autoloads.push(path) if no_subdir
144
+ elsif source.match(%r{^lib/.+/resources/.*\.rb})
145
+ # Gem Resource Pack
146
+ path = source.sub(%r{^lib/}, "")
147
+ autoloads.push(path)
138
148
  end
139
149
 
140
150
  @require_loader.add(path, content, source, line)
@@ -66,9 +66,9 @@ module Inspec::Reporters
66
66
  # Then it downgrades the 160bit SHA1 to a 128bit
67
67
  # then we format it as a valid UUIDv5.
68
68
  def uuid_from_string(string)
69
- hash = Digest::SHA256.new
69
+ hash = Digest::SHA1.new
70
70
  hash.update(string)
71
- ary = hash.digest[0, 16].unpack("NnnnnN")
71
+ ary = hash.digest.unpack("NnnnnN")
72
72
  ary[2] = (ary[2] & 0x0FFF) | (5 << 12)
73
73
  ary[3] = (ary[3] & 0x3FFF) | 0x8000
74
74
  # rubocop:disable Style/FormatString
@@ -193,7 +193,7 @@ module Inspec::Resources
193
193
  #
194
194
  # @return [Array[String,String]]
195
195
  def action_list_for(line)
196
- action_list = line.scan(/-a ([^,\s]+),([^,\s]+)(?:\s|$)/).flatten
196
+ action_list = line.scan(/-a ([^,]+),([^ ]+)\s?/).flatten
197
197
 
198
198
  # Actions and lists can be in either order
199
199
  valid_actions = %w{never always}
@@ -200,8 +200,60 @@ module Inspec::Resources
200
200
  # implements generic unix groups via /etc/group
201
201
  class UnixGroup < GroupInfo
202
202
  def groups
203
+ get_group_info
204
+ end
205
+
206
+ private
207
+
208
+ def get_group_info
209
+ # First, try to fetch group info using getent
210
+ group_info = fetch_group_info_using_getent
211
+
212
+ return group_info unless group_info.empty?
213
+
214
+ # If getent fails, fallback to reading group info from /etc/group using inspec.etc_group.entries
215
+ Inspec::Log.debug("Falling back to reading group info from /etc/group as getent is unavailable or failed.")
203
216
  inspec.etc_group.entries
204
217
  end
218
+
219
+ # Fetches group information using the getent utility
220
+ def fetch_group_info_using_getent
221
+ # Find getent utility on the system
222
+ bin = find_getent_utility
223
+
224
+ # If getent is available, fetch group info
225
+ return [] unless bin
226
+
227
+ cmd = inspec.command("#{bin} group")
228
+ return parse_group_info(cmd) if cmd.exit_status.to_i == 0
229
+
230
+ # If getent fails, log the error and return an empty array
231
+ Inspec::Log.debug("Failed to execute #{bin} group: #{cmd.stderr}.")
232
+ []
233
+ end
234
+
235
+ # Parses group info from the command output
236
+ def parse_group_info(cmd)
237
+ cmd.stdout.strip.split("\n").map do |line|
238
+ name, password, gid, members = line.split(":")
239
+ {
240
+ "name" => name,
241
+ "password" => password,
242
+ "gid" => gid.to_i,
243
+ "members" => members,
244
+ }
245
+ end
246
+ end
247
+
248
+ # Checks if getent exists on the system
249
+ def find_getent_utility
250
+ %w{/usr/bin/getent /bin/getent getent}.each do |cmd|
251
+ return cmd if inspec.command(cmd).exist?
252
+ end
253
+ # Log debug information if getent is not found
254
+ Inspec::Log.debug("Could not find `getent` on your system.")
255
+ nil # Return nil if getent is not found
256
+ end
205
257
  end
206
258
 
207
259
  # OSX uses opendirectory for groups, so `/etc/group` may not be fully accurate
@@ -300,7 +300,7 @@ module Inspec::Resources
300
300
  def parse_netstat_line(line)
301
301
  # parse each line
302
302
  # 1 - Socket, 2 - Proto, 3 - Receive-Q, 4 - Send-Q, 5 - Local address, 6 - Foreign Address, 7 - State
303
- parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)(?:\s+(\S+))?\s+(\S+)$/.match(line)
303
+ parsed = /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)?\s+(\S+)/.match(line)
304
304
  return {} if parsed.nil?
305
305
 
306
306
  # parse ip4 and ip6 addresses
@@ -488,7 +488,7 @@ module Inspec::Resources
488
488
  # 1 - Proto, 2 - Recv-Q, 3 - Send-Q, 4 - Local Address, 5 - Foreign Address, 6 - State, 7 - User, 8 - Inode, 9 - PID/Program name
489
489
  # * UDP lines have an empty State column and the Busybox variant lacks
490
490
  # the User and Inode columns.
491
- reg = /^(?<proto>\S+)\s+(\S+)\s+(\S+)\s+(?<local_addr>\S+)\s+(?<foreign_addr>\S+)\s+(?:\S+\s+){0,2}(?<pid_prog>\S+)$/
491
+ reg = /^(?<proto>\S+)\s+(\S+)\s+(\S+)\s+(?<local_addr>\S+)\s+(?<foreign_addr>\S+)\s+(\S+)?\s+((\S+)\s+(\S+)\s+)?(?<pid_prog>\S+)/
492
492
  parsed = reg.match(line)
493
493
 
494
494
  return {} if parsed.nil? || line.match(/^proto/i)
@@ -1,7 +1,7 @@
1
1
  # copyright: 2015, Vulcano Security GmbH
2
2
 
3
3
  require "shellwords" unless defined?(Shellwords)
4
- require "cgi" unless defined?(CGI)
4
+
5
5
  module Inspec::Resources
6
6
  class Lines
7
7
  attr_reader :output, :exit_status
@@ -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)
@@ -74,10 +74,6 @@ module Inspec::Resources
74
74
  Shellwords.escape(query)
75
75
  end
76
76
 
77
- def encoded_password(password)
78
- CGI.escape(password)
79
- end
80
-
81
77
  def create_psql_cmd(query, db = [])
82
78
  dbs = db.map { |x| "#{x}" }.join(" ")
83
79
 
@@ -86,14 +82,14 @@ module Inspec::Resources
86
82
  # Socket connection only enabled for non-windows platforms
87
83
  # Windows does not support unix domain sockets
88
84
  option_port = @port.nil? ? "" : "-p #{@port}" # add explicit port if specified
89
- "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
85
+ "psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
90
86
  else
91
87
  # Host in connection string establishes tcp/ip connection
92
88
  if inspec.os.windows?
93
89
  warn "Socket based connection not supported in windows, connecting using host" if @socket_path
94
- "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
90
+ "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
95
91
  else
96
- "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
92
+ "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
97
93
  end
98
94
  end
99
95
  end
@@ -121,7 +121,7 @@ module Inspec::Resources
121
121
  # extracts the shortname from a repo id
122
122
  # e.g. extras/7/x86_64 -> extras
123
123
  def shortname(id)
124
- val = %r{^([^/]+)/.*$}.match(id)
124
+ val = %r{^\s*([^/]*?)/(.*?)\s*$}.match(id)
125
125
  val.nil? ? nil : val[1]
126
126
  end
127
127
 
@@ -30,12 +30,6 @@ require "inspec/resources/cron"
30
30
  require "inspec/resources/timezone"
31
31
  require "inspec/resources/dh_params"
32
32
  require "inspec/resources/directory"
33
- require "inspec/resources/docker"
34
- require "inspec/resources/docker_container"
35
- require "inspec/resources/docker_image"
36
- require "inspec/resources/docker_plugin"
37
- require "inspec/resources/docker_service"
38
- require "inspec/resources/elasticsearch"
39
33
  require "inspec/resources/etc_fstab"
40
34
  require "inspec/resources/etc_group"
41
35
  require "inspec/resources/etc_hosts_allow_deny"
@@ -48,8 +42,6 @@ require "inspec/resources/groups"
48
42
  require "inspec/resources/grub_conf"
49
43
  require "inspec/resources/host"
50
44
  require "inspec/resources/http"
51
- require "inspec/resources/ibmdb2_conf"
52
- require "inspec/resources/ibmdb2_session"
53
45
  require "inspec/resources/iis_app"
54
46
  require "inspec/resources/iis_app_pool"
55
47
  require "inspec/resources/iis_site"
@@ -64,9 +56,6 @@ require "inspec/resources/key_rsa"
64
56
  require "inspec/resources/ksh"
65
57
  require "inspec/resources/limits_conf"
66
58
  require "inspec/resources/login_defs"
67
- require "inspec/resources/mongodb"
68
- require "inspec/resources/mongodb_conf"
69
- require "inspec/resources/mongodb_session"
70
59
  require "inspec/resources/mount"
71
60
  require "inspec/resources/mssql_session"
72
61
  require "inspec/resources/mssql_sys_conf"
@@ -102,15 +91,12 @@ require "inspec/resources/postgres_ident_conf"
102
91
  require "inspec/resources/postgres_session"
103
92
  require "inspec/resources/powershell"
104
93
  require "inspec/resources/processes"
105
- require "inspec/resources/rabbitmq_config"
106
94
  require "inspec/resources/registry_key"
107
95
  require "inspec/resources/security_identifier"
108
96
  require "inspec/resources/security_policy"
109
97
  require "inspec/resources/selinux"
110
98
  require "inspec/resources/service"
111
99
  require "inspec/resources/shadow"
112
- require "inspec/resources/ssh_config"
113
- require "inspec/resources/ssh_key"
114
100
  require "inspec/resources/ssl"
115
101
  require "inspec/resources/sys_info"
116
102
  require "inspec/resources/toml"
data/lib/inspec/runner.rb CHANGED
@@ -115,7 +115,8 @@ module Inspec
115
115
  next unless profile.supports_platform?
116
116
 
117
117
  write_lockfile(profile) if @create_lockfile
118
- profile.locked_dependencies
118
+ # TODO: InSpec 8: Replace with Profile OnLoad event handling
119
+ profile.locked_dependencies # Only need to do this once, this recurses down
119
120
  profile.load_gem_dependencies
120
121
  profile_context = profile.load_libraries
121
122
 
@@ -125,6 +126,9 @@ module Inspec
125
126
  " on unsupported platform: '#{@backend.platform.name}/#{@backend.platform.release}'."
126
127
  next
127
128
  end
129
+ # TODO: InSpec 8: Replace with Profile OnLoad event handling
130
+ requirement.profile.load_gem_dependencies
131
+ requirement.profile.load_libraries
128
132
  @test_collector.add_profile(requirement.profile)
129
133
  end
130
134
 
@@ -168,16 +172,7 @@ module Inspec
168
172
  end
169
173
 
170
174
  def run(with = nil)
171
- product_dist_name = Inspec::Dist::PRODUCT_NAME
172
- if Inspec::Dist::EXEC_NAME == "inspec"
173
- if Inspec::Telemetry::RunContextProbe.guess_run_context == "test-kitchen"
174
- product_dist_name = "Chef Workstation"
175
- configure_licensing_config_for_kitchen(@conf)
176
- # Persist the license key in file when passed via test-kitchen
177
- ChefLicensing.fetch_and_persist if @conf[:chef_license_key]
178
- end
179
- ChefLicensing.check_software_entitlement!
180
- end
175
+ ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
181
176
 
182
177
  # Validate if profiles are signed and verified
183
178
  # Additional check is required to provide error message in case of inspec exec command (exec command can use multiple profiles as well)
@@ -192,11 +187,8 @@ module Inspec
192
187
  Inspec::Telemetry.run_starting(runner: self, conf: @conf)
193
188
  load
194
189
  run_tests(with)
195
- rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError
196
- Inspec::Log.error "#{product_dist_name} cannot execute without valid licenses."
197
- Inspec::UI.new.exit(:license_not_set)
198
190
  rescue ChefLicensing::SoftwareNotEntitled
199
- Inspec::Log.error "License is not entitled to use #{product_dist_name}."
191
+ Inspec::Log.error "License is not entitled to use InSpec."
200
192
  Inspec::UI.new.exit(:license_not_entitled)
201
193
  rescue ChefLicensing::Error => e
202
194
  Inspec::Log.error e.message
@@ -24,3 +24,5 @@ end
24
24
 
25
25
  require "source_readers/inspec"
26
26
  require "source_readers/flat"
27
+ require "source_readers/gem"
28
+
data/lib/inspec/ui.rb CHANGED
@@ -39,6 +39,7 @@ module Inspec
39
39
  EXIT_FAILED_TESTS = 100
40
40
  EXIT_SKIPPED_TESTS = 101
41
41
  EXIT_TERMINATED_BY_CTL_C = 130
42
+ EXIT_GEM_DEPENDENCY_NOT_FOUND = 201
42
43
 
43
44
  attr_reader :io
44
45
 
@@ -7,6 +7,7 @@ module Inspec
7
7
  module Deprecation
8
8
  class ConfigFile
9
9
  GroupEntry = Struct.new(:name, :action, :prefix, :suffix, :exit_status)
10
+ FallbackEntry = Struct.new(:resource_name_regex, :gem_name, :message)
10
11
 
11
12
  # What actions may you specify to be taken when a deprecation is encountered?
12
13
  VALID_ACTIONS = [
@@ -20,7 +21,7 @@ module Inspec
20
21
  # and pass validation.
21
22
  VALID_GROUP_FIELDS = %w{action suffix prefix exit_status comment}.freeze
22
23
 
23
- attr_reader :groups, :unknown_group_action
24
+ attr_reader :fallback_resource_packs, :groups, :unknown_group_action
24
25
 
25
26
  def initialize(io = nil)
26
27
  io ||= open_default_config_io
@@ -31,6 +32,7 @@ module Inspec
31
32
  end
32
33
 
33
34
  @groups = {}
35
+ @fallback_resource_packs = []
34
36
  @unknown_group_action = :warn
35
37
  validate!
36
38
  silence_deprecations_from_cli
@@ -83,14 +85,25 @@ module Inspec
83
85
  @raw_data["groups"].each do |group_name, group_info|
84
86
  validate_group_entry(group_name, group_info)
85
87
  end
88
+
89
+ unless @raw_data.key?("fallback_resource_packs")
90
+ raise Inspec::Deprecation::InvalidConfigFileError, "Missing fallback_resource_packs field"
91
+ end
92
+ unless @raw_data["fallback_resource_packs"].is_a?(Hash)
93
+ raise Inspec::Deprecation::InvalidConfigFileError, "fallback_resource_packs field must be a Hash"
94
+ end
95
+
96
+ @raw_data["fallback_resource_packs"].each do |fallback_pat, fallback_info|
97
+ validate_fallback(fallback_pat, fallback_info)
98
+ end
86
99
  end
87
100
 
88
101
  def validate_file_version
89
102
  unless @raw_data.key?("file_version")
90
103
  raise Inspec::Deprecation::InvalidConfigFileError, "Missing file_version field"
91
104
  end
92
- unless @raw_data["file_version"] == "1.0.0"
93
- raise Inspec::Deprecation::InvalidConfigFileError, "Unrecognized file_version '#{@raw_data["file_version"]}' - supported versions: 1.0.0"
105
+ unless @raw_data["file_version"] == "2.0.0"
106
+ raise Inspec::Deprecation::InvalidConfigFileError, "Unrecognized file_version '#{@raw_data["file_version"]}' - supported versions: 2.0.0"
94
107
  end
95
108
  end
96
109
 
@@ -125,6 +138,29 @@ module Inspec
125
138
 
126
139
  groups[name.to_sym] = entry
127
140
  end
141
+
142
+ def validate_fallback(pattern, raw_info)
143
+ fallback = FallbackEntry.new
144
+ begin
145
+ fallback.resource_name_regex = Regexp.new(pattern)
146
+ rescue RegexpError
147
+ raise Inspec::Deprecation::InvalidConfigFileError, "Invalid regular expression in resource pack fallback definition '#{pattern}'"
148
+ end
149
+
150
+ unless raw_info["gem"]
151
+ raise Inspec::Deprecation::InvalidConfigFileError, "fallback_resource_packs missing gem name for pattern '#{pattern}'"
152
+ end
153
+
154
+ fallback.gem_name = raw_info["gem"]
155
+
156
+ unless raw_info["message"]
157
+ raise Inspec::Deprecation::InvalidConfigFileError, "fallback_resource_packs missing message for pattern '#{pattern}'"
158
+ end
159
+
160
+ fallback.message = raw_info["message"]
161
+
162
+ fallback_resource_packs.push fallback
163
+ end
128
164
  end
129
165
  end
130
166
  end
@@ -4,11 +4,12 @@ require "inspec/log"
4
4
  module Inspec
5
5
  module Deprecation
6
6
  class Deprecator
7
- attr_reader :config, :groups
7
+ attr_reader :config, :fallback_resource_packs, :groups
8
8
 
9
9
  def initialize(opts = {})
10
10
  @config = Inspec::Deprecation::ConfigFile.new(opts[:config_io])
11
11
  @groups = @config.groups
12
+ @fallback_resource_packs = @config.fallback_resource_packs
12
13
  end
13
14
 
14
15
  def handle_deprecation(group_name, message, opts = {})
@@ -21,6 +22,13 @@ module Inspec
21
22
  send(action_method, group_name.to_sym, assembled_message, group)
22
23
  end
23
24
 
25
+ # Given a resource name, suggest a gem nam to load and or install
26
+ def match_gem_for_fallback_resource_name(resource_name)
27
+ fallback = fallback_resource_packs.find { |fb| fb.resource_name_regex.match(resource_name) }
28
+ # We have a message here but can't pass it back?
29
+ fallback&.gem_name
30
+ end
31
+
24
32
  private
25
33
 
26
34
  def create_group_entry_for_unknown_group(group_name)
@@ -61,8 +69,7 @@ module Inspec
61
69
 
62
70
  suffix += (" (used at " + opts[:used_at_stack_frame].path + ":" + opts[:used_at_stack_frame].lineno.to_s + ")") if opts.key?(:used_at_stack_frame)
63
71
 
64
- keyword = group.name.to_s == "core_resource_moved_to_rp" ? "CHANGE NOTICE: " : "DEPRECATION: "
65
- keyword + prefix + message + suffix
72
+ "DEPRECATION: " + prefix + message + suffix
66
73
  end
67
74
 
68
75
  def called_from_control?
@@ -4,20 +4,6 @@ ChefLicensing.configure do |config|
4
4
  config.chef_product_name = "InSpec"
5
5
  config.chef_entitlement_id = "3ff52c37-e41f-4f6c-ad4d-365192205968"
6
6
  config.chef_executable_name = "inspec"
7
- config.license_server_url = ENV["CHEF_LICENSE_SERVER"] || "https://services.chef.io/licensing"
7
+ config.license_server_url = "https://services.chef.io/licensing"
8
8
  config.logger = Inspec::Log
9
9
  end
10
-
11
- def configure_licensing_config_for_kitchen(opts = {})
12
- ChefLicensing.configure do |config|
13
- # Reset entitlement ID to the ID of Chef Workstation
14
- config.chef_entitlement_id = "x6f3bc76-a94f-4b6c-bc97-4b7ed2b045c0"
15
- # Reset Chef License server via kitchen when passed in kitchen.yml
16
- opts["chef_license_server"] = opts["chef_license_server"].join(",") if opts["chef_license_server"].is_a? Array
17
- unless opts["chef_license_server"].nil? || opts["chef_license_server"].empty?
18
- ENV["CHEF_LICENSE_SERVER"] = opts["chef_license_server"]
19
- end
20
- end
21
- # Reset Chef License key via kitchen when passed in kitchen.yml
22
- ENV["CHEF_LICENSE_KEY"] = opts["chef_license_key"] if opts["chef_license_key"]
23
- end
@@ -72,23 +72,15 @@ module Inspec
72
72
  if includes_whitespaces?(mount_line)
73
73
  # Device-/Sharenames and Mountpoints including whitespaces require special treatment:
74
74
  # We use the keyword ' type ' to split up and rebuild the desired array of fields
75
- # Split the mount line by the keyword ' type '
76
- fs_path, other_opts = mount_line.split(" type ", 2)
77
-
78
- # Manually split fs_path into the filesystem and path parts
79
- fs, path = fs_path.split(" on ", 2)
80
-
81
- # Start building the mount array
75
+ type_split = mount_line.split(" type ")
76
+ fs_path = type_split[0]
77
+ other_opts = type_split[1]
78
+ fs, path = fs_path.match(%r{^(.+?)\son\s(/.+?)$}).captures
82
79
  mount = [fs, "on", path, "type"]
83
-
84
- # Split the remaining options by spaces
85
- other_opts = other_opts.split(/\s+/)
86
-
87
- # Concatenate the options to the mount array
88
- mount.concat(other_opts)
80
+ mount.concat(other_opts.scan(/\S+/))
89
81
  else
90
- # If no whitespace, simply split by spaces
91
- mount = mount_line.split(/\s+/)
82
+ # ... otherwise we just split the fields by whitespaces
83
+ mount = mount_line.scan(/\S+/)
92
84
  end
93
85
 
94
86
  # parse device and type
@@ -117,10 +109,8 @@ module Inspec
117
109
 
118
110
  # Device-/Sharename or Mountpoint includes whitespaces?
119
111
  def includes_whitespaces?(mount_line)
120
- # Split the mount_line by " on "
121
- parts = mount_line.split(" on ")
122
- # Check if either part contains spaces
123
- parts.any? { |part| part.include?(" ") }
112
+ ws = mount_line.match(/^(.+)\son\s(.+)\stype\s.*$/)
113
+ ws.captures[0].include?(" ") || ws.captures[1].include?(" ")
124
114
  end
125
115
  end
126
116
 
@@ -18,12 +18,10 @@ module Inspec
18
18
  # Don't perform telemetry action for other InSpec distros
19
19
  # Don't perform telemetry action if running under Automate - Automate does LDC tracking for us
20
20
  # Don't perform telemetry action if license is a commercial license
21
- # Don't perform telemetry action if running under Test Kitchen
22
21
 
23
22
  if Inspec::Dist::EXEC_NAME != "inspec" ||
24
23
  Inspec::Telemetry::RunContextProbe.under_automate? ||
25
- license&.license_type&.downcase == "commercial" ||
26
- Inspec::Telemetry::RunContextProbe.guess_run_context == "test-kitchen"
24
+ license&.license_type&.downcase == "commercial"
27
25
 
28
26
  Inspec::Log.debug "Determined telemetry operation is not applicable and hence aborting it."
29
27
  return Inspec::Telemetry::Null
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "6.8.24".freeze
2
+ VERSION = "7.0.38.beta".freeze
3
3
  end
@@ -425,10 +425,8 @@ module InspecPlugins
425
425
  "our apologies for the misunderstanding, and open an issue " \
426
426
  "at https://github.com/inspec/inspec/issues/new")
427
427
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
428
- rescue Inspec::Plugin::V2::InstallError => e
429
- # This change is compatible with various versions of Ruby, including Ruby 3.3
430
- # Using Inspec::Log::level breaks with error `undefined method nil` in Ruby log library
431
- Inspec::Log.debug e.backtrace
428
+ rescue Inspec::Plugin::V2::InstallError
429
+ raise if Inspec::Log.level == :debug
432
430
 
433
431
  results = installer.search(plugin_name, exact: true)
434
432
  source_host = URI(options[:source] || "https://rubygems.org/").host