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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f295e7d99ec735932c005e949cf99cbb1184780d52eae109cec87faf27501c8
4
- data.tar.gz: b9fe70883d7593b0d6c7ce51067c7fb2b26154a88981d4ff6458f1f3306518b1
3
+ metadata.gz: 2e160d7044fa022329cb438d770054bb63107b59f219030464c709f6b1dcda93
4
+ data.tar.gz: 1dc6673dc552f75cb9b8671b0a466feb2c818f069112fac69aa63b1de568ef54
5
5
  SHA512:
6
- metadata.gz: 0f35167f971fcdd9d71a43bf7d6e4baf97ae9f0ac9b16b8ebe33103b15e4fee3892d34f8f2a9c0ef1a499e1860d3a8c2e4080acc20cf5415929c013bc97b0972
7
- data.tar.gz: cf3bfdfa97c737abcd3f054a6eb4899de5831e2ebebc8a4e9907865835560ff979acb2a86ccce37059dfb0075fc2d628fbdeb3045357a02ad01a9ea22842e462
6
+ metadata.gz: a389860f421bec680c4db4462fc4cf5765073661cc1154f5fe57e823f7b4f33b10d1ecd22fb286d3a50cd467170645d460ba80b96515331bd2aec9eaa80d8579
7
+ data.tar.gz: 6133800736ed63493d37bca5b3727740b1a1ab7eadb9919ffc8b728f021604a9dd7bf1d1b388169566bc4e484b3fb2fc26845e05769f1dc2afa26f530fddf7a0
data/Gemfile CHANGED
@@ -42,7 +42,7 @@ group :test do
42
42
  gem "json_schemer"
43
43
  gem "m"
44
44
  gem "minitest-sprint", "~> 1.0"
45
- gem "minitest", "5.15.0"
45
+ gem "minitest"
46
46
  gem "mocha"
47
47
  gem "nokogiri"
48
48
  gem "pry-byebug"
@@ -55,4 +55,4 @@ end
55
55
 
56
56
  group :deploy do
57
57
  gem "inquirer"
58
- end
58
+ end
@@ -73,6 +73,11 @@
73
73
  "action": "exit",
74
74
  "suffix": "This resource was removed in InSpec 4.0."
75
75
  },
76
+ "core_resource_moved_to_rp": {
77
+ "action": "exit",
78
+ "suffix": "This resource has been moved to a separate gem. Please include the appropriate gem in your dependencies to continue using this resource.",
79
+ "comment": "Deprecation notice for core resources which are now distributed as gems. Update your profile dependencies accordingly."
80
+ },
76
81
  "resource_iis_website": {
77
82
  "action": "exit",
78
83
  "suffix": "This resource was removed in InSpec 4.0.",
@@ -139,6 +144,30 @@
139
144
  "docker.+":{
140
145
  "gem": "inspec-docker-resources",
141
146
  "message": "The Inspec docker resources are moved out of InSpec core and will be installed as gem"
147
+ },
148
+ "ibmdb2.+":{
149
+ "gem": "inspec-ibmdb2-resources",
150
+ "message": "The Inspec ibmdb2 resources are moved out of InSpec core and will be installed as gem"
151
+ },
152
+ "mongodb.+":{
153
+ "gem": "inspec-mongodb-resources",
154
+ "message": "The Inspec mongodb resources are moved out of InSpec core and will be installed as gem"
155
+ },
156
+ "opa.+":{
157
+ "gem": "inspec-opa-resources",
158
+ "message": "The Inspec opa resources are moved out of InSpec core and will be installed as gem"
159
+ },
160
+ "podman.+":{
161
+ "gem": "inspec-podman-resources",
162
+ "message": "The Inspec podman resources are moved out of InSpec core and will be installed as gem"
163
+ },
164
+ "rabbitmq.+":{
165
+ "gem": "inspec-rabbitmq-resources",
166
+ "message": "The Inspec rabbitmq resources are moved out of InSpec core and will be installed as gem"
167
+ },
168
+ "sybase.+":{
169
+ "gem": "inspec-sybase-resources",
170
+ "message": "The Inspec sybase resources are moved out of InSpec core and will be installed as gem"
142
171
  }
143
172
  }
144
173
  }
data/inspec-core.gemspec CHANGED
@@ -35,11 +35,11 @@ Source code obtained from the Chef GitHub repository is made available under Apa
35
35
  spec.add_dependency "license-acceptance", ">= 0.2.13", "< 3.0"
36
36
  # TODO: We should remove the thor pinning in next upcoming releases currently it's breaking our unit test in cli_args_test for aliases due to
37
37
  # recent changes made in thor library REF: https://github.com/rails/thor/releases/tag/v1.3.0 & https://github.com/rails/thor/pull/800
38
- spec.add_dependency "thor", ">= 0.20", "< 1.3.0"
38
+ spec.add_dependency "thor", ">= 0.20", "< 1.5.0"
39
39
  spec.add_dependency "method_source", ">= 0.8", "< 2.0"
40
- spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
40
+ spec.add_dependency "rubyzip", ">= 1.2.2", "< 4.0"
41
41
  spec.add_dependency "rspec", ">= 3.9", "<= 3.14"
42
- spec.add_dependency "rspec-its", "~> 1.2"
42
+ spec.add_dependency "rspec-its", ">= 1.2", "< 3.0"
43
43
  spec.add_dependency "pry", "~> 0.13"
44
44
  spec.add_dependency "hashie", ">= 3.4", "< 6.0"
45
45
  spec.add_dependency "mixlib-log", "~> 3.0"
@@ -49,19 +49,26 @@ Source code obtained from the Chef GitHub repository is made available under Apa
49
49
  spec.add_dependency "faraday-follow_redirects", "~> 0.3"
50
50
  spec.add_dependency "tty-table", "~> 0.10"
51
51
  spec.add_dependency "tty-prompt", "~> 0.17"
52
- spec.add_dependency "tomlrb", ">= 1.2", "< 2.1"
52
+ spec.add_dependency "tomlrb", ">= 1.3", "< 2.1"
53
53
  spec.add_dependency "addressable", "~> 2.4"
54
- spec.add_dependency "parslet", ">= 1.5", "< 2.0" # Pinned < 2.0, see #5389
54
+ spec.add_dependency "parslet", ">= 1.5", "< 3.0" # Pinned < 2.0, see #5389
55
55
  spec.add_dependency "semverse", "~> 3.0"
56
56
  spec.add_dependency "multipart-post", "~> 2.0"
57
57
 
58
+ # Gem dependency needed with Ruby 3.4 upgrade
59
+ # TODO : Remove the dependency on mutex_m once the 'chef-licensing' gem is released with the fix
60
+ # spec.add_dependency "mutex_m", "~> 0.2.0"
61
+ spec.add_dependency "syslog", "~> 0.1"
62
+ spec.add_dependency "csv", "~> 3.0"
63
+ spec.add_dependency "ostruct", ">= 0.1", "< 0.7"
64
+
58
65
  # cookstyle support for inspec check
59
66
  # This was initially included in 'inspec.gemspec' to keep 'chef-client' lightweight.
60
67
  # However, it has been moved to 'inspec-core.gemspec' due to a dependency on the 'ast' gem,
61
68
  # which was causing a LoadError ('cannot load such file -- ast') for users/applications using 'inspec-core'.
62
69
  spec.add_dependency "cookstyle"
63
70
 
64
- spec.add_dependency "train-core", ">= 3.11.0"
71
+ spec.add_dependency "train-core", "~> 3.13", ">= 3.13.4"
65
72
  # Minimum major version 1 is required for Chef licensing telemetry
66
- spec.add_dependency "chef-licensing", ">= 1.0.2"
73
+ spec.add_dependency "chef-licensing", ">= 1.2.0"
67
74
  end
@@ -1,4 +1,5 @@
1
1
  require "rubygems/package" unless defined?(Gem::Package)
2
+ require "rubygems/package/tar_writer" unless defined?(Gem::Package::TarWriter)
2
3
 
3
4
  module Inspec::Archive
4
5
  class TarArchiveGenerator
@@ -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 "train"
4
6
  require "inspec/config"
@@ -165,6 +165,16 @@ module Inspec
165
165
  desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config."
166
166
  option :podman_url, type: :string,
167
167
  desc: "Provides the path to the Podman API endpoint. Defaults to unix:///run/user/$UID/podman/podman.sock for rootless container, unix:///run/podman/podman.sock for rootful container (for this you need to execute inspec as root user)."
168
+ option :socks_proxy, type: :string,
169
+ desc: "SOCKS5H proxy URL to tunnel the WinRM connection (e.g., socks5h://proxy-host:1080)."
170
+ option :socks_user, type: :string,
171
+ desc: "Username for authenticating with the SOCKS5 proxy."
172
+ option :socks_password, type: :string, lazy_default: -1,
173
+ desc: "Password for authenticating with the SOCKS5 proxy."
174
+ option :kerberos_realm, type: :string,
175
+ desc: "Kerberos realm used for authentication."
176
+ option :kerberos_service, type: :string,
177
+ desc: "Kerberos service principal name (e.g., HTTP, HOST)."
168
178
  end
169
179
 
170
180
  def self.profile_options
@@ -370,7 +380,7 @@ module Inspec
370
380
  # get the log level
371
381
  # DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
372
382
  def get_log_level(level)
373
- valid = %w{debug info warn error fatal}
383
+ valid = %w{trace debug info warn error fatal}
374
384
 
375
385
  if valid.include?(level)
376
386
  l = level
@@ -378,7 +388,7 @@ module Inspec
378
388
  l = "info"
379
389
  end
380
390
 
381
- Logger.const_get(l.upcase)
391
+ Mixlib::Log.const_get(l.upcase)
382
392
  end
383
393
 
384
394
  def pretty_handle_exception(exception)
@@ -85,8 +85,9 @@ module Inspec
85
85
  end
86
86
 
87
87
  def assert_cache_sanity!
88
- # TODO: update this to handle gem resource pack dependencies
88
+ # do not check cache sanity if the target is a gem or a resource pack
89
89
  # which are known by a special prefix on their cache key or by having the :gem key
90
+ return if target.respond_to?(:key?) && target.key?(:gem)
90
91
  return unless target.respond_to?(:key?) && target.key?(:sha256)
91
92
 
92
93
  exception_message = <<~EOF
data/lib/inspec/cli.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 "inspec/utils/deprecation/deprecator"
4
6
  require "inspec/dist"
@@ -16,6 +16,7 @@ module Inspec
16
16
  #
17
17
  class Cache
18
18
  attr_reader :path
19
+
19
20
  def initialize(path = nil)
20
21
  @path = path || File.join(Inspec.config_dir, "cache")
21
22
  FileUtils.mkdir_p(@path) unless File.directory?(@path)
@@ -59,12 +60,9 @@ module Inspec
59
60
  return false if key.nil? || key.empty?
60
61
 
61
62
  if key.start_with?("gem:")
62
- # A gem installation
63
- (_, gem_name, version) = key.split(":")
64
- loader = Inspec::Plugin::V2::Loader.new
65
- !loader.find_gem_directory(gem_name, version).nil?
66
-
67
- elsif key.start_with?("gem_path:")
63
+ # check if the gem is installed in InSpec Config DIR or if it is present as cache in cache DIR
64
+ !gemspec_path_for(key).nil? || File.directory?(base_path_for(key))
65
+ elsif key.start_with?("gem_path:") # TODO: remove this as it will be redundant with the introduction of SHA256 key
68
66
  # Gem installed as explicit path reference, as in testing / development
69
67
  entry_point_path = key.sub(/^gem_path:/, "")
70
68
  File.exist?(entry_point_path)
@@ -88,10 +86,10 @@ module Inspec
88
86
  #
89
87
  def base_path_for(key)
90
88
  if key.start_with?("gem:")
91
- # A gem installation
92
- (_, gem_name, version) = key.split(":")
93
- loader = Inspec::Plugin::V2::Loader.new
94
- loader.find_gem_directory(gem_name, version)
89
+ # fetch the Gem installed path and if the gem is not available in the installed DIR
90
+ # construct the cache path where it can be found
91
+ # At this point this path will be used both for writing and reading the gem cache
92
+ gemspec_path_for(key) || File.join(@path, key)
95
93
 
96
94
  elsif key.start_with?("gem_path:")
97
95
  # Gem installed as explicit path reference, as in testing / development
@@ -122,9 +120,7 @@ module Inspec
122
120
  locked = false
123
121
  path = base_path_for(key)
124
122
  # For archive there is no need to lock the directory so we skip those and return false for archive formatted cache
125
- if File.directory?(path)
126
- locked = File.exist?("#{path}/.lock")
127
- end
123
+ locked = File.exist?("#{path}/.lock") if File.directory?(path)
128
124
  locked
129
125
  end
130
126
 
data/lib/inspec/dsl.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  # copyright: 2015, Dominik Richter
2
+ # Copyright © 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates.
3
+ # All Rights Reserved.
4
+
2
5
  require "inspec/log"
3
6
  require "inspec/plugin/v2"
4
7
  require "inspec/utils/deprecated_cloud_resources_list"
8
+ require "inspec/utils/deprecated_core_resources_list"
5
9
 
6
10
  module Inspec::DSL
7
11
  attr_accessor :backend
@@ -49,7 +53,8 @@ module Inspec::DSL
49
53
  # Install if needed
50
54
  cfg = Inspec::Config.cached
51
55
  unless cfg.final_options[:auto_install_gems]
52
- raise Inspec::Plugin::V2::InstallRequiredError, "resource pack gem '#{gem_name}' is required for resource '#{id}' support (consider --auto-install-gems)"
56
+ Inspec.deprecate(:core_resource_moved_to_rp, "The resource pack gem '#{gem_name}' is required for resource '#{id}' support (consider --auto-install-gems).")
57
+
53
58
  end
54
59
 
55
60
  Inspec::Plugin::V2::Installer.instance.ensure_installed gem_name
@@ -8,9 +8,7 @@ module Inspec::Fetcher
8
8
  # Gem fetcher's priority should be lowest because gem profiles are only executables via inspec metadata
9
9
 
10
10
  def self.resolve(target)
11
- if target.is_a?(Hash) && target.key?(:gem)
12
- resolve_from_hash(target)
13
- end
11
+ resolve_from_hash(target) if target.is_a?(Hash) && target.key?(:gem)
14
12
  end
15
13
 
16
14
  def self.resolve_from_hash(target)
@@ -32,15 +30,13 @@ module Inspec::Fetcher
32
30
  def fetch(path)
33
31
  plugin_installer = Inspec::Plugin::V2::Installer.instance
34
32
 
35
- # Determine if gem is installed
36
- have_plugin = false
37
33
  Inspec::Log.debug("GemFetcher fetching #{@gem_name} v" + (@version || "ANY"))
38
34
 
39
- if @version
40
- have_plugin = plugin_installer.plugin_version_installed?(@gem_name, @version)
41
- else
42
- have_plugin = plugin_installer.plugin_installed?(@gem_name)
43
- end
35
+ have_plugin = if @version
36
+ plugin_installer.plugin_version_installed?(@gem_name, @version)
37
+ else
38
+ plugin_installer.plugin_installed?(@gem_name)
39
+ end
44
40
 
45
41
  unless have_plugin
46
42
  # Install
@@ -48,10 +44,26 @@ module Inspec::Fetcher
48
44
  Inspec::Log.debug("GemFetcher - install request for #{@gem_name}")
49
45
  if @gem_path
50
46
  # No version permitted
51
- plugin_installer.install(@gem_name, path: @gem_path)
47
+ plugin_installer.install(@gem_name, gem: @gem_name, path: @gem_path)
52
48
  else
53
49
  # Passing an extra gem argument to enable detecting gem based plugins
54
- plugin_installer.install(@gem_name, version: @version, source: @source, gem: @gem_name )
50
+ plugin_installer.install(@gem_name, version: @version, source: @source, gem: @gem_name)
51
+ end
52
+ end
53
+
54
+ # Usually this `path` is cache path
55
+ # We want to copy installed gem to cache path so it can be vendored
56
+ # and read again as a cache
57
+ if path
58
+ loader = Inspec::Plugin::V2::Loader.new
59
+ gem_dir_path = loader.find_gem_directory(@gem_name, @version)
60
+ if gem_dir_path
61
+ # Cache the gem file
62
+ FileUtils.mkdir_p(path)
63
+ FileUtils.cp_r(gem_dir_path, path)
64
+ @archive_path = path
65
+ else
66
+ @archive_path = @target
55
67
  end
56
68
  end
57
69
 
@@ -61,9 +73,7 @@ module Inspec::Fetcher
61
73
  @target
62
74
  end
63
75
 
64
- def archive_path
65
- @target
66
- end
76
+ attr_reader :archive_path
67
77
 
68
78
  def writable?
69
79
  # Gem based profile is not writable because it is not cached in lockfile
@@ -72,13 +82,15 @@ module Inspec::Fetcher
72
82
 
73
83
  def cache_key
74
84
  # This special value is interpreted by Inspec::Cache.exists?
75
- # gem:gemname:version
76
- # gem_path:/filesystem/path/entrypoint.rb
77
-
78
- if @gem_path
79
- "gem_path:#{@gem_path}"
80
- else
81
- "gem:#{@gem_name}:#{@version}"
85
+ # SHA256 on gem:gemname:version
86
+ # SHA256 on gem_path:/filesystem/path/entrypoint.rb
87
+ @cache_key ||= begin
88
+ key = if @gem_path
89
+ "gem_path:#{@gem_path}"
90
+ else
91
+ "gem:#{@gem_name}:#{gem_version}"
92
+ end
93
+ OpenSSL::Digest.hexdigest("SHA256", key)
82
94
  end
83
95
  end
84
96
 
@@ -91,9 +103,15 @@ module Inspec::Fetcher
91
103
  end
92
104
 
93
105
  def resolved_source
94
- h = { gem: @gem_name, version: @version, gem_path: @gem_path }
106
+ h = { gem: @gem_name, version: gem_version, gem_path: @gem_path }
95
107
  h[:sha256] = sha256
96
108
  h
97
109
  end
110
+
111
+ private
112
+
113
+ def gem_version
114
+ @version || Inspec::Plugin::V2::Loader.find_gemspec_of(@gem_name)&.version&.to_s
115
+ end
98
116
  end
99
117
  end
@@ -68,11 +68,21 @@ module Inspec::Fetcher
68
68
  else
69
69
  Dir.mktmpdir do |working_dir|
70
70
  checkout(working_dir)
71
+ if git_only_or_empty?(working_dir)
72
+ # If the temporary working directory is empty after checkout,
73
+ # this means the git repository did not contain any files (or the checkout failed).
74
+ # In this case, remove the destination directory to avoid
75
+ # leaving an empty or invalid profile directory.
76
+ if Dir.exist?(destination_path)
77
+ FileUtils.rm_rf(destination_path)
78
+ end
79
+ raise Inspec::FetcherFailure, "Profile git dependency failed for #{@remote_url} - no files found in the repository."
80
+ end
71
81
  if @relative_path
72
82
  perform_relative_path_fetch(destination_path, working_dir)
73
83
  else
74
84
  Inspec::Log.debug("Checkout of #{resolved_ref.nil? ? @remote_url : resolved_ref} successful. " \
75
- "Moving checkout to #{destination_path}")
85
+ "Moving checkout to #{destination_path}")
76
86
  FileUtils.cp_r(working_dir + "/.", destination_path)
77
87
  end
78
88
  end
@@ -80,6 +90,16 @@ module Inspec::Fetcher
80
90
  @repo_directory
81
91
  end
82
92
 
93
+ def git_only_or_empty?(dir)
94
+ return false unless Dir.exist?(dir)
95
+
96
+ children = Dir.children(dir)
97
+ # Return true if:
98
+ # - directory is completely empty
99
+ # - or it contains only one entry: '.git'
100
+ children.empty? || (children - [".git"]).empty?
101
+ end
102
+
83
103
  def perform_relative_path_fetch(destination_path, working_dir)
84
104
  Inspec::Log.debug("Checkout of #{resolved_ref.nil? ? @remote_url : resolved_ref} successful. " \
85
105
  "Moving #{@relative_path} to #{destination_path}")
@@ -1,4 +1,5 @@
1
1
  require "rubygems/package" unless defined?(Gem::Package)
2
+ require "rubygems/package/tar_header" unless defined?(Gem::Package::TarHeader)
2
3
  require "pathname" unless defined?(Pathname)
3
4
  require "zlib" unless defined?(Zlib)
4
5
  require "zip" unless defined?(Zip)
@@ -173,7 +173,7 @@ module Inspec
173
173
  raise ArgumentError, "ERROR: An '=' is required when using --input. Usage: --input input_name1=input_value1 input2=value2"
174
174
  end
175
175
  end
176
- pair = pair.match(/(.*?)=(.*)/)
176
+ pair = pair.match(/^([^=]+)=(.*)$/)
177
177
  input_name, input_value = pair[1], pair[2]
178
178
  input_value = parse_cli_input_value(input_name, input_value)
179
179
  evt = Inspec::Input::Event.new(
@@ -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 "logger"
4
6
  require "rubygems/version"
@@ -28,16 +28,23 @@ module Inspec::Plugin::V2
28
28
  private
29
29
 
30
30
  def chef_rubygems_server
31
- "https://#{DEFAULT_USERNAME}:#{licenses_string}@#{DEFAULT_CHEF_RUBY_GEMS_SERVER}"
31
+ # If there are no license keys, return nil to avoid adding an invalid source
32
+ "https://#{DEFAULT_USERNAME}:#{licenses_string}@#{DEFAULT_CHEF_RUBY_GEMS_SERVER}" unless licenses_string.empty?
32
33
  end
33
34
 
34
35
  def register_source(source)
36
+ return if source.nil? # If the source is nil, we don't want to add it
37
+
35
38
  gem_source = Gem::Source.new(source)
36
39
  sources << gem_source unless sources.include?(gem_source)
40
+ rescue StandardError => e
41
+ raise StandardError, "Unable to add gem source #{source}: #{e.message}"
37
42
  end
38
43
 
39
44
  def licenses_string
40
45
  ChefLicensing.license_keys.join(",")
46
+ rescue StandardError
47
+ ""
41
48
  end
42
49
  end
43
50
  end
@@ -285,7 +285,16 @@ module Inspec::Plugin::V2
285
285
  #===================================================================#
286
286
 
287
287
  def install_from_path(requested_plugin_name, opts)
288
- # Nothing to do here; we will later update the plugins file with the path.
288
+ return unless gem_based_plugin?(opts)
289
+
290
+ local_gem_path = opts[:path]
291
+ Inspec::Log.debug("Installing #{requested_plugin_name} from path #{local_gem_path}")
292
+ raise InstallError, "Gem File not found: #{local_gem_path}" unless File.exist?(local_gem_path)
293
+
294
+ gem_installer = Gem::Installer.at(local_gem_path, install_dir: gem_path, ignore_dependencies: true, document: [])
295
+ gem_installer.install
296
+
297
+ Inspec::Log.debug("Installed gem from path: #{local_gem_path} to #{gem_path}")
289
298
  end
290
299
 
291
300
  def install_from_gem_file(requested_plugin_name, opts)
@@ -339,6 +348,9 @@ module Inspec::Plugin::V2
339
348
  set_available_for_resolution = build_gem_request_universe(extra_request_sets, gem_to_force_update)
340
349
 
341
350
  # Solve the dependency (that is, find a way to install the new plugin and anything it needs)
351
+ # [WARN]: Gem::RequestSet cannot resolve from multiple directories
352
+ # So all dependent gems will be resolved to the GEM_HOME/Gem.default_dir directory
353
+ # assuming everything will be installed in the same dir
342
354
  request_set = Gem::RequestSet.new(new_plugin_dependency)
343
355
 
344
356
  begin
@@ -372,6 +384,15 @@ module Inspec::Plugin::V2
372
384
  requested_gemspec = activation_request.full_spec
373
385
  next if requested_gemspec.activated?
374
386
 
387
+ # The specs at this point are pointed to GEM_HOME/Gem.default_dir directory
388
+ # because of the resolved set's assumption that we will install Gems in the same directory
389
+ # In many cases, RubyGems has already loaded gems from default dir
390
+ # Hence at this point it is really only a sanity check
391
+ # And if the requested_gemspec_file has not been downloaded in this default dir do not activate it
392
+ # Activation will be taken care after the downloads
393
+ requested_gemspec_file = File.join(requested_gemspec.gem_dir, "#{requested_gemspec.name}.gemspec")
394
+ next unless File.exist?(requested_gemspec_file) || File.exist?(requested_gemspec.spec_file)
395
+
375
396
  # activate the requested gemspec from the Gem::RequestSet
376
397
  requested_gemspec.activate unless loaded_recent_most_version_of?(requested_gemspec)
377
398
  end
@@ -396,7 +417,7 @@ module Inspec::Plugin::V2
396
417
  File.write(path_inside_source, spec.to_ruby)
397
418
  end
398
419
  end
399
-
420
+ loader.activate_managed_gems_for_plugin(new_plugin_dependency.name)
400
421
  # Locate the GemVersion for the new dependency and return it
401
422
  solution.detect { |g| g.name == new_plugin_dependency.name }.version
402
423
  end
@@ -70,7 +70,9 @@ module Inspec::Plugin::V2
70
70
  require plugin_details.entry_point
71
71
  else
72
72
  load_path = plugin_details.entry_point
73
- load_path += ".rb" unless plugin_details.entry_point.end_with?(".rb")
73
+ next if load_path.end_with?(".gem") # local resource pack's path will have gem path
74
+
75
+ load_path += ".rb" unless load_path.end_with?(".rb")
74
76
  load load_path
75
77
  end
76
78
  plugin_details.loaded = true
@@ -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 "openssl" unless defined?(OpenSSL)
@@ -299,7 +301,14 @@ module Inspec
299
301
  # # Pull together waiver
300
302
  waived_control_ids = []
301
303
  waiver_paths.each do |waiver_path|
302
- waiver_content = YAML.load_file(waiver_path)
304
+ # Ruby 3.1 treats YAML load as a dangerous operation by default, requiring us to declare date and time classes as permitted
305
+ # It's not a valid option in 3.0.x
306
+ if Gem.ruby_version >= Gem::Version.new("3.1.0")
307
+ waiver_content = ::YAML.load_file(waiver_path, permitted_classes: [Date, Time])
308
+ else
309
+ waiver_content = YAML.load_file(waiver_path)
310
+ end
311
+
303
312
  unless waiver_content
304
313
  # Note that we will have already issued a detailed warning
305
314
  Inspec::Log.error "YAML parsing error in #{waiver_path}"
@@ -628,7 +637,7 @@ module Inspec
628
637
  include_tests: include_tests)
629
638
 
630
639
  # Collect all metadata defined in the control block and inputs defined inside the control block
631
- src.ast.each_node { |n|
640
+ src.ast&.each_node { |n|
632
641
  ctl_id_collector.process(n)
633
642
  input_collector.process(n)
634
643
  }
@@ -690,7 +699,7 @@ module Inspec
690
699
  }
691
700
  source_location_ref = @source_reader.target.abs_path(control_filename)
692
701
  Inspec::Profile::AstHelper::TitleCollector.new(group_data)
693
- .process(src.ast.child_nodes.first) # Picking the title defined for the whole controls file
702
+ .process(src.ast&.child_nodes&.first) # Picking the title defined for the whole controls file
694
703
  group_controls = @info_from_parse[:controls].select { |control| control[:source_location][:ref] == source_location_ref }
695
704
  group_data[:controls] = group_controls.map { |control| control[:id] }
696
705
 
@@ -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::SHA1.new
69
+ hash = Digest::SHA256.new
70
70
  hash.update(string)
71
- ary = hash.digest.unpack("NnnnnN")
71
+ ary = hash.digest[0, 16].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
@@ -39,11 +39,17 @@ module Inspec::Resources
39
39
  # expected result:
40
40
  # Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting
41
41
  # WIN-MB8NINQ388J,System,Kerberos Authentication Service,{0CCE9242-69AE-11D9-BED3-505054503030},No Auditing,
42
- result ||= inspec.command("Auditpol /get /subcategory:'#{key}' /r").stdout
42
+ auditpol_cmd = "Auditpol /get /subcategory:'#{key}' /r"
43
+ result ||= inspec.command(auditpol_cmd)
44
+
45
+ unless result.exit_status == 0
46
+ error = result.stdout + "\n" + result.stderr
47
+ raise Inspec::Exceptions::ResourceFailed, "Error while executing #{auditpol_cmd} command: #{error}"
48
+ end
43
49
 
44
50
  # find line
45
51
  target = nil
46
- result.each_line do |s|
52
+ result.stdout.each_line do |s|
47
53
  target = s.strip if s =~ /\b.*#{key}.*\b/
48
54
  end
49
55
 
@@ -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?/).flatten
196
+ action_list = line.scan(/-a ([^,\s]+),([^,\s]+)(?:\s|$)/).flatten
197
197
 
198
198
  # Actions and lists can be in either order
199
199
  valid_actions = %w{never always}
@@ -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+((\S+)\s+(\S+)\s+)?(?<pid_prog>\S+)/
491
+ reg = /^(?<proto>\S+)\s+(\S+)\s+(\S+)\s+(?<local_addr>\S+)\s+(?<foreign_addr>\S+)\s+(?:\S+\s+){0,2}(?<pid_prog>\S+)$/
492
492
  parsed = reg.match(line)
493
493
 
494
494
  return {} if parsed.nil? || line.match(/^proto/i)