inspec-core 7.0.38.beta → 7.0.95

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/etc/deprecations.json +29 -0
  4. data/inspec-core.gemspec +14 -7
  5. data/lib/inspec/archive/tar.rb +1 -0
  6. data/lib/inspec/backend.rb +2 -0
  7. data/lib/inspec/base_cli.rb +12 -2
  8. data/lib/inspec/cached_fetcher.rb +2 -1
  9. data/lib/inspec/cli.rb +2 -0
  10. data/lib/inspec/dependencies/cache.rb +9 -13
  11. data/lib/inspec/dsl.rb +6 -1
  12. data/lib/inspec/fetcher/gem.rb +41 -23
  13. data/lib/inspec/fetcher/git.rb +21 -1
  14. data/lib/inspec/file_provider.rb +1 -0
  15. data/lib/inspec/input_registry.rb +1 -1
  16. data/lib/inspec/metadata.rb +2 -0
  17. data/lib/inspec/plugin/v2/gem_source_manager.rb +8 -1
  18. data/lib/inspec/plugin/v2/installer.rb +23 -2
  19. data/lib/inspec/plugin/v2/loader.rb +3 -1
  20. data/lib/inspec/profile.rb +12 -3
  21. data/lib/inspec/reporters/automate.rb +2 -2
  22. data/lib/inspec/resources/audit_policy.rb +8 -2
  23. data/lib/inspec/resources/auditd.rb +1 -1
  24. data/lib/inspec/resources/port.rb +2 -2
  25. data/lib/inspec/resources/postgres_session.rb +9 -5
  26. data/lib/inspec/resources/ssh_config.rb +215 -0
  27. data/lib/inspec/resources/ssh_key.rb +124 -0
  28. data/lib/inspec/resources/sshd_active_config.rb +2 -0
  29. data/lib/inspec/resources/sshd_config.rb +2 -0
  30. data/lib/inspec/resources/yum.rb +1 -1
  31. data/lib/inspec/resources.rb +2 -2
  32. data/lib/inspec/rule.rb +2 -0
  33. data/lib/inspec/runner.rb +16 -2
  34. data/lib/inspec/utils/deprecated_core_resources_list.rb +25 -0
  35. data/lib/inspec/utils/licensing_config.rb +15 -1
  36. data/lib/inspec/utils/parser.rb +19 -9
  37. data/lib/inspec/utils/simpleconfig.rb +2 -0
  38. data/lib/inspec/utils/telemetry/run_context_probe.rb +5 -2
  39. data/lib/inspec/utils/telemetry.rb +3 -1
  40. data/lib/inspec/version.rb +1 -1
  41. data/lib/inspec/waiver_file_reader.rb +35 -18
  42. data/lib/inspec.rb +2 -0
  43. data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +4 -2
  44. data/lib/plugins/shared/core_plugin_test_helper.rb +1 -1
  45. data/lib/source_readers/inspec.rb +1 -1
  46. metadata +84 -22
  47. data/lib/inspec/resources/opa.rb +0 -26
  48. data/lib/inspec/resources/opa_api.rb +0 -49
  49. data/lib/inspec/resources/opa_cli.rb +0 -57
@@ -1,7 +1,7 @@
1
1
  # copyright: 2015, Vulcano Security GmbH
2
2
 
3
3
  require "shellwords" unless defined?(Shellwords)
4
-
4
+ require "cgi" unless defined?(CGI)
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:/
58
+ if cmd.exit_status != 0 && ( out =~ /could not connect to/ || out =~ /password authentication failed/ ) && (out.downcase =~ /error:/ || out.downcase =~ /fatal:/)
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,6 +74,10 @@ 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
+
77
81
  def create_psql_cmd(query, db = [])
78
82
  dbs = db.map { |x| "#{x}" }.join(" ")
79
83
 
@@ -82,14 +86,14 @@ module Inspec::Resources
82
86
  # Socket connection only enabled for non-windows platforms
83
87
  # Windows does not support unix domain sockets
84
88
  option_port = @port.nil? ? "" : "-p #{@port}" # add explicit port if specified
85
- "psql -d postgresql://#{@user}:#{@pass}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
89
+ "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@/#{dbs}?host=#{@socket_path} #{option_port} -A -t -w -c #{escaped_query(query)}"
86
90
  else
87
91
  # Host in connection string establishes tcp/ip connection
88
92
  if inspec.os.windows?
89
93
  warn "Socket based connection not supported in windows, connecting using host" if @socket_path
90
- "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
94
+ "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c \"#{query}\""
91
95
  else
92
- "psql -d postgresql://#{@user}:#{@pass}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
96
+ "psql -d postgresql://#{@user}:#{encoded_password(@pass)}@#{@host}:#{@port}/#{dbs} -A -t -w -c #{escaped_query(query)}"
93
97
  end
94
98
  end
95
99
  end
@@ -0,0 +1,215 @@
1
+ # copyright: 2015, Vulcano Security GmbH
2
+
3
+ require "inspec/utils/simpleconfig"
4
+ require "inspec/utils/file_reader"
5
+
6
+ module Inspec::Resources
7
+ class SshConfig < Inspec.resource(1)
8
+ name "ssh_config"
9
+ supports platform: "unix"
10
+ supports platform: "windows"
11
+ desc "Use the `ssh_config` InSpec audit resource to test OpenSSH client configuration data located at `/etc/ssh/ssh_config` on Linux and Unix platforms."
12
+ example <<~EXAMPLE
13
+ describe ssh_config do
14
+ its('cipher') { should contain '3des' }
15
+ its('port') { should eq '22' }
16
+ its('hostname') { should include('example.com') }
17
+ end
18
+ EXAMPLE
19
+
20
+ include FileReader
21
+
22
+ def initialize(conf_path = nil, type = nil)
23
+ @conf_path = conf_path || ssh_config_file("ssh_config")
24
+ typename = (@conf_path.include?("sshd") ? "Server" : "Client")
25
+ @type = type || "SSH #{typename} configuration #{conf_path}"
26
+ read_content
27
+ end
28
+
29
+ def content
30
+ read_content
31
+ end
32
+
33
+ def params(*opts)
34
+ opts.inject(read_params) do |res, nxt|
35
+ res.respond_to?(:key) ? res[nxt] : nil
36
+ end
37
+ end
38
+
39
+ def convert_hash(hash)
40
+ new_hash = {}
41
+ hash.each { |k, v| new_hash[k.downcase] ||= v }
42
+ new_hash
43
+ end
44
+
45
+ def method_missing(name)
46
+ param = read_params[name.to_s.downcase]
47
+ return nil if param.nil?
48
+ return param[0] if param.length == 1
49
+
50
+ param
51
+ end
52
+
53
+ def to_s
54
+ "SSH Configuration"
55
+ end
56
+
57
+ def resource_id
58
+ @conf_path || "SSH Configuration"
59
+ end
60
+
61
+ private
62
+
63
+ def read_content
64
+ return @content if defined?(@content)
65
+
66
+ @content = read_file_content(@conf_path)
67
+ end
68
+
69
+ def read_params
70
+ return @params if defined?(@params)
71
+ return @params = {} if read_content.nil?
72
+
73
+ conf =
74
+ SimpleConfig.new(
75
+ read_content,
76
+ assignment_regex: /^\s*(\S+?)\s+(.*?)\s*$/,
77
+ multiple_values: true
78
+ )
79
+ @params = convert_hash(conf.params)
80
+ end
81
+
82
+ def ssh_config_file(type)
83
+ if inspec.os.windows?
84
+ programdata = inspec.os_env("programdata").content
85
+ return "#{programdata}\\ssh\\#{type}"
86
+ end
87
+
88
+ "/etc/ssh/#{type}"
89
+ end
90
+ end
91
+
92
+ class SshdConfig < SshConfig
93
+ name "sshd_config"
94
+ supports platform: "unix"
95
+ supports platform: "windows"
96
+ desc "Use the sshd_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges."
97
+ example <<~EXAMPLE
98
+ describe sshd_config do
99
+ its('Protocol') { should eq '2' }
100
+ end
101
+ EXAMPLE
102
+
103
+ def initialize(path = nil)
104
+ super(path || ssh_config_file("sshd_config"))
105
+ end
106
+
107
+ def to_s
108
+ "SSHD Configuration"
109
+ end
110
+
111
+ private
112
+
113
+ def ssh_config_file(type)
114
+ if inspec.os.windows?
115
+ programdata = inspec.os_env("programdata").content
116
+ return "#{programdata}\\ssh\\#{type}"
117
+ end
118
+
119
+ "/etc/ssh/#{type}"
120
+ end
121
+ end
122
+
123
+ class SshdActiveConfig < SshdConfig
124
+ name "sshd_active_config"
125
+ supports platform: "unix"
126
+ supports platform: "windows"
127
+ desc "Use the sshd_active_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges."
128
+ example <<~EXAMPLE
129
+ describe sshd_active_config do
130
+ its('Protocol') { should eq '2' }
131
+ end
132
+ EXAMPLE
133
+
134
+ attr_reader :active_path
135
+
136
+ def initialize
137
+ @active_path = dynamic_sshd_config_path
138
+ super(@active_path)
139
+ end
140
+
141
+ def to_s
142
+ "SSHD Active Configuration (active path: #{@conf_path})"
143
+ end
144
+
145
+ private
146
+
147
+ def ssh_config_file(type)
148
+ if inspec.os.windows?
149
+ programdata = inspec.os_env("programdata").content
150
+ return "#{programdata}\\ssh\\#{type}"
151
+ end
152
+
153
+ "/etc/ssh/#{type}"
154
+ end
155
+
156
+ def dynamic_sshd_config_path
157
+ if inspec.os.windows?
158
+ script = <<-EOH
159
+ $sshdPath = (Get-Command sshd.exe).Source
160
+ if ($sshdPath -ne $null) {
161
+ Write-Output $sshdPath
162
+ } else {
163
+ Write-Error "sshd.exe not found"
164
+ }
165
+ EOH
166
+ sshd_path_result = inspec.powershell(script).stdout.strip
167
+ sshd_path = "\"#{sshd_path_result}\""
168
+ if !sshd_path_result.empty? && sshd_path_result != "sshd.exe not found"
169
+ command_output = inspec.command("sudo #{sshd_path} -dd 2>&1").stdout
170
+ dynamic_path =
171
+ command_output
172
+ .lines
173
+ .find { |line| line.include?("filename") }
174
+ &.split("filename")
175
+ &.last
176
+ &.strip
177
+ env_var_name = dynamic_path.match(/__(.*?)__/)[1]
178
+ if env_var_name?
179
+ dynamic_path =
180
+ dynamic_path.gsub(
181
+ /__#{env_var_name}__/,
182
+ inspec.os_env(env_var_name).content
183
+ )
184
+ end
185
+ else
186
+ Inspec::Log.error("sshd.exe not found using PowerShell script block.")
187
+ return nil
188
+ end
189
+ elsif inspec.os.unix?
190
+ sshd_path = "/usr/sbin/sshd"
191
+ command_output = inspec.command("sudo #{sshd_path} -dd 2>&1").stdout
192
+ dynamic_path =
193
+ command_output
194
+ .lines
195
+ .find { |line| line.include?("filename") }
196
+ &.split("filename")
197
+ &.last
198
+ &.strip
199
+ else
200
+ Inspec::Log.error(
201
+ "Unable to determine sshd configuration path on Windows using -T flag."
202
+ )
203
+ return nil
204
+ end
205
+
206
+ if dynamic_path.nil? || dynamic_path.empty?
207
+ Inspec::Log.warn(
208
+ "No active SSHD configuration found. Using default configuration."
209
+ )
210
+ return ssh_config_file("sshd_config")
211
+ end
212
+ dynamic_path
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,124 @@
1
+ require "inspec/utils/file_reader"
2
+ require "net/ssh" unless defined?(Net::SSH)
3
+
4
+ # Change module if required
5
+ module Inspec::Resources
6
+ class SshKey < FileResource
7
+ # Every resource requires an internal name.
8
+ name "ssh_key"
9
+
10
+ # Restrict to only run on the below platforms (if none were given,
11
+ # all OS's and cloud API's supported)
12
+ supports platform: "unix"
13
+ supports platform: "windows"
14
+
15
+ desc "public/private SSH key pair test"
16
+
17
+ example <<~EXAMPLE
18
+ describe ssh_key('path: ~/.ssh/id_rsa') do
19
+ its('key_length') { should eq 4096 }
20
+ its('type') { should cmp /rsa/ }
21
+ it { should be_private }
22
+ end
23
+ EXAMPLE
24
+
25
+ include FileReader
26
+
27
+ def initialize(keypath, passphrase = nil)
28
+ skip_resource "The `ssh_key` resource is not yet available on your OS." unless inspec.os.unix? || inspec.os.windows?
29
+ @key_path = set_ssh_key_path(keypath)
30
+ @passphrase = passphrase
31
+ @key = read_ssh_key
32
+ super(@key_path)
33
+ end
34
+
35
+ def public?
36
+ return if @key.nil?
37
+
38
+ @key[:public]
39
+ end
40
+
41
+ def private?
42
+ return if @key.nil?
43
+
44
+ @key[:private]
45
+ end
46
+
47
+ def key_length
48
+ return if @key.nil?
49
+
50
+ @key[:key_length]
51
+ end
52
+
53
+ def type
54
+ return if @key.nil?
55
+
56
+ @key[:type]
57
+ end
58
+
59
+ # Define a resource ID. This is used in reporting engines to uniquely identify the individual resource.
60
+ # This might be a file path, or a process ID, or a cloud instance ID. Only meaningful to the implementation.
61
+ # Must be a string. Defaults to the empty string if not implemented.
62
+ def resource_id
63
+ @key_path || "SSH key"
64
+ end
65
+
66
+ def to_s
67
+ "ssh_key #{@key_path}"
68
+ end
69
+
70
+ private
71
+
72
+ def set_ssh_key_path(keypath)
73
+ if File.exist?(keypath)
74
+ @key_path = keypath
75
+ elsif File.exist?(File.join("#{Dir.home}/.ssh/", keypath))
76
+ @key_path = File.join("#{Dir.home}/.ssh/", keypath)
77
+ else
78
+ raise Inspec::Exceptions::ResourceSkipped, "Can't find file: #{keypath}"
79
+ end
80
+ end
81
+
82
+ def read_ssh_key
83
+ key_data = {}
84
+ key = nil
85
+ filecontent = read_file_content((@key_path), @passphrase)
86
+ raise Inspec::Exceptions::ResourceSkipped, "File is empty: #{@key_path}" if filecontent.split("\n").empty?
87
+
88
+ if filecontent.split("\n")[0].include?("PRIVATE")
89
+ # Net::SSH::KeyFactory does not have support to load private key for DSA
90
+ key = Net::SSH::KeyFactory.load_private_key(@key_path, @passphrase, false)
91
+ unless key.nil?
92
+ key_data[:private] = true
93
+ key_data[:public] = false
94
+ # The data send for ssh type is not in same format so it's good to match on the string
95
+ key_data[:type] = key.ssh_type
96
+ key_data[:key_length] = key_lengh(key)
97
+ end
98
+ else
99
+ key = Net::SSH::KeyFactory.load_public_key(@key_path)
100
+ unless key.nil?
101
+ key_data[:private] = false
102
+ key_data[:public] = true
103
+ # The data send for ssh type is not in same format so it's good to match on the string
104
+ key_data[:type] = key.ssh_type
105
+ key_data[:key_length] = key_lengh(key)
106
+ end
107
+ end
108
+
109
+ key_data
110
+ rescue OpenSSL::PKey::PKeyError => e
111
+ raise Inspec::Exceptions::ResourceFailed, "#{e.message}"
112
+ end
113
+
114
+ def key_lengh(key)
115
+ if key.class.to_s == "OpenSSL::PKey::RSA"
116
+ key.public_key.n.num_bits
117
+ else
118
+ # Unable to get the key lenght data for other types of keys
119
+ # TODO: Need to check if there is any method that will get this info.
120
+ nil
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,2 @@
1
+ # This is just here to make the dynamic loader happy.
2
+ require "inspec/resources/ssh_config"
@@ -0,0 +1,2 @@
1
+ # This is just here to make the dynamic loader happy.
2
+ require "inspec/resources/ssh_config"
@@ -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{^\s*([^/]*?)/(.*?)\s*$}.match(id)
124
+ val = %r{^([^/]+)/.*$}.match(id)
125
125
  val.nil? ? nil : val[1]
126
126
  end
127
127
 
@@ -71,8 +71,6 @@ require "inspec/resources/oneget"
71
71
  require "inspec/resources/oracle"
72
72
  require "inspec/resources/oracledb_conf"
73
73
  require "inspec/resources/oracledb_listener_conf"
74
- require "inspec/resources/opa_cli"
75
- require "inspec/resources/opa_api"
76
74
  require "inspec/resources/oracledb_session"
77
75
  require "inspec/resources/os"
78
76
  require "inspec/resources/os_env"
@@ -97,6 +95,8 @@ require "inspec/resources/security_policy"
97
95
  require "inspec/resources/selinux"
98
96
  require "inspec/resources/service"
99
97
  require "inspec/resources/shadow"
98
+ require "inspec/resources/ssh_config"
99
+ require "inspec/resources/ssh_key"
100
100
  require "inspec/resources/ssl"
101
101
  require "inspec/resources/sys_info"
102
102
  require "inspec/resources/toml"
data/lib/inspec/rule.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # copyright: 2015, Dominik Richter
2
+ # Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates.
3
+ # All Rights Reserved.
2
4
 
3
5
  require "method_source"
4
6
  require "date"
data/lib/inspec/runner.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # copyright: 2015, Dominik Richter
2
+ # Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates.
3
+ # All Rights Reserved.
2
4
 
3
5
  require "forwardable" unless defined?(Forwardable)
4
6
  require "uri" unless defined?(URI)
@@ -172,7 +174,16 @@ module Inspec
172
174
  end
173
175
 
174
176
  def run(with = nil)
175
- ChefLicensing.check_software_entitlement! if Inspec::Dist::EXEC_NAME == "inspec"
177
+ product_dist_name = Inspec::Dist::PRODUCT_NAME
178
+ if Inspec::Dist::EXEC_NAME == "inspec"
179
+ if Inspec::Telemetry::RunContextProbe.guess_run_context == "test-kitchen"
180
+ product_dist_name = "Chef Workstation"
181
+ configure_licensing_config_for_kitchen(@conf)
182
+ # Persist the license key in file when passed via test-kitchen
183
+ ChefLicensing.fetch_and_persist if @conf[:chef_license_key]
184
+ end
185
+ ChefLicensing.check_software_entitlement!
186
+ end
176
187
 
177
188
  # Validate if profiles are signed and verified
178
189
  # Additional check is required to provide error message in case of inspec exec command (exec command can use multiple profiles as well)
@@ -187,8 +198,11 @@ module Inspec
187
198
  Inspec::Telemetry.run_starting(runner: self, conf: @conf)
188
199
  load
189
200
  run_tests(with)
201
+ rescue ChefLicensing::LicenseKeyFetcher::LicenseKeyNotFetchedError
202
+ Inspec::Log.error "#{product_dist_name} cannot execute without valid licenses."
203
+ Inspec::UI.new.exit(:license_not_set)
190
204
  rescue ChefLicensing::SoftwareNotEntitled
191
- Inspec::Log.error "License is not entitled to use InSpec."
205
+ Inspec::Log.error "License is not entitled to use #{product_dist_name}."
192
206
  Inspec::UI.new.exit(:license_not_entitled)
193
207
  rescue ChefLicensing::Error => e
194
208
  Inspec::Log.error e.message
@@ -0,0 +1,25 @@
1
+ module DeprecatedCoreResourcesList
2
+ CORE_RESOURCES_DEPRECATED = %i{
3
+ docker_container
4
+ docker_image
5
+ docker_plugin
6
+ docker_service
7
+ elasticsearch
8
+ ibmdb2_conf
9
+ ibmdb2_session
10
+ mongodb
11
+ mongodb_conf
12
+ mongodb_session
13
+ opa_api
14
+ opa_cli
15
+ podman
16
+ podman_container
17
+ podman_image
18
+ podman_network
19
+ podman_pod
20
+ podman_volume
21
+ rabbitmq_config
22
+ sybase_conf
23
+ sybase_session
24
+ }.freeze
25
+ end
@@ -4,6 +4,20 @@ 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 = "https://services.chef.io/licensing"
7
+ config.license_server_url = ENV["CHEF_LICENSE_SERVER"] || "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,15 +72,23 @@ 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
- 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
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
79
82
  mount = [fs, "on", path, "type"]
80
- mount.concat(other_opts.scan(/\S+/))
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)
81
89
  else
82
- # ... otherwise we just split the fields by whitespaces
83
- mount = mount_line.scan(/\S+/)
90
+ # If no whitespace, simply split by spaces
91
+ mount = mount_line.split(/\s+/)
84
92
  end
85
93
 
86
94
  # parse device and type
@@ -109,8 +117,10 @@ module Inspec
109
117
 
110
118
  # Device-/Sharename or Mountpoint includes whitespaces?
111
119
  def includes_whitespaces?(mount_line)
112
- ws = mount_line.match(/^(.+)\son\s(.+)\stype\s.*$/)
113
- ws.captures[0].include?(" ") || ws.captures[1].include?(" ")
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?(" ") }
114
124
  end
115
125
  end
116
126
 
@@ -1,4 +1,6 @@
1
1
  # copyright: 2015, Dominik Richter
2
+ # Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates.
3
+ # All Rights Reserved.
2
4
 
3
5
  require "inspec/utils/parser"
4
6
  require "hashie"
@@ -26,8 +26,11 @@ module Inspec
26
26
  end
27
27
 
28
28
  def self.run_by_thor?(stack)
29
- stack_match(stack: stack, path: "thor/command", label: "run") &&
30
- stack_match(stack: stack, path: "thor/invocation", label: "invoke_command")
29
+ # Handled in both ways to fix label differences for Ruby 3.4 and other versions of Ruby
30
+ (stack_match(stack: stack, path: "thor/command", label: "Thor::Command#run") &&
31
+ stack_match(stack: stack, path: "thor/invocation", label: "Thor::Invocation#invoke_command")) ||
32
+ (stack_match(stack: stack, path: "thor/command", label: "run") &&
33
+ stack_match(stack: stack, path: "thor/invocation", label: "invoke_command"))
31
34
  end
32
35
 
33
36
  def self.kitchen?(stack)
@@ -18,10 +18,12 @@ 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
21
22
 
22
23
  if Inspec::Dist::EXEC_NAME != "inspec" ||
23
24
  Inspec::Telemetry::RunContextProbe.under_automate? ||
24
- license&.license_type&.downcase == "commercial"
25
+ license&.license_type&.downcase == "commercial" ||
26
+ Inspec::Telemetry::RunContextProbe.guess_run_context == "test-kitchen"
25
27
 
26
28
  Inspec::Log.debug "Determined telemetry operation is not applicable and hence aborting it."
27
29
  return Inspec::Telemetry::Null
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "7.0.38.beta".freeze
2
+ VERSION = "7.0.95".freeze
3
3
  end