inspec-core 6.8.24 → 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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +8 -8
  3. data/etc/deprecations.json +42 -4
  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 +15 -2
  8. data/lib/inspec/cached_fetcher.rb +17 -1
  9. data/lib/inspec/cli.rb +2 -0
  10. data/lib/inspec/dependencies/cache.rb +47 -7
  11. data/lib/inspec/dsl.rb +44 -10
  12. data/lib/inspec/exceptions.rb +1 -0
  13. data/lib/inspec/fetcher/gem.rb +117 -0
  14. data/lib/inspec/fetcher/git.rb +21 -1
  15. data/lib/inspec/fetcher/local.rb +1 -1
  16. data/lib/inspec/fetcher.rb +1 -0
  17. data/lib/inspec/file_provider.rb +47 -1
  18. data/lib/inspec/metadata.rb +2 -0
  19. data/lib/inspec/plugin/v2/concerns/gem_spec_helper.rb +30 -0
  20. data/lib/inspec/plugin/v2/gem_source_manager.rb +50 -0
  21. data/lib/inspec/plugin/v2/installer.rb +65 -18
  22. data/lib/inspec/plugin/v2/loader.rb +37 -6
  23. data/lib/inspec/plugin/v2/plugin_types/resource_pack.rb +8 -0
  24. data/lib/inspec/plugin/v2.rb +1 -0
  25. data/lib/inspec/profile.rb +22 -3
  26. data/lib/inspec/profile_context.rb +10 -0
  27. data/lib/inspec/resources/audit_policy.rb +8 -2
  28. data/lib/inspec/resources/groups.rb +52 -0
  29. data/lib/inspec/resources.rb +0 -14
  30. data/lib/inspec/rule.rb +2 -0
  31. data/lib/inspec/runner.rb +7 -1
  32. data/lib/inspec/source_reader.rb +2 -0
  33. data/lib/inspec/ui.rb +1 -0
  34. data/lib/inspec/utils/deprecated_core_resources_list.rb +2 -2
  35. data/lib/inspec/utils/deprecation/config_file.rb +39 -3
  36. data/lib/inspec/utils/deprecation/deprecator.rb +10 -3
  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/version.rb +1 -1
  40. data/lib/inspec/waiver_file_reader.rb +35 -18
  41. data/lib/inspec.rb +2 -0
  42. data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +1 -1
  43. data/lib/plugins/shared/core_plugin_test_helper.rb +1 -1
  44. data/lib/source_readers/gem.rb +67 -0
  45. metadata +82 -43
  46. data/lib/inspec/resources/docker.rb +0 -274
  47. data/lib/inspec/resources/docker_container.rb +0 -116
  48. data/lib/inspec/resources/docker_image.rb +0 -141
  49. data/lib/inspec/resources/docker_object.rb +0 -52
  50. data/lib/inspec/resources/docker_plugin.rb +0 -68
  51. data/lib/inspec/resources/docker_service.rb +0 -95
  52. data/lib/inspec/resources/elasticsearch.rb +0 -165
  53. data/lib/inspec/resources/ibmdb2_conf.rb +0 -65
  54. data/lib/inspec/resources/ibmdb2_session.rb +0 -78
  55. data/lib/inspec/resources/mongodb.rb +0 -69
  56. data/lib/inspec/resources/mongodb_conf.rb +0 -44
  57. data/lib/inspec/resources/mongodb_session.rb +0 -98
  58. data/lib/inspec/resources/opa.rb +0 -26
  59. data/lib/inspec/resources/opa_api.rb +0 -49
  60. data/lib/inspec/resources/opa_cli.rb +0 -57
  61. data/lib/inspec/resources/podman.rb +0 -353
  62. data/lib/inspec/resources/podman_container.rb +0 -84
  63. data/lib/inspec/resources/podman_image.rb +0 -108
  64. data/lib/inspec/resources/podman_network.rb +0 -81
  65. data/lib/inspec/resources/podman_pod.rb +0 -101
  66. data/lib/inspec/resources/podman_volume.rb +0 -87
  67. data/lib/inspec/resources/rabbitmq_conf.rb +0 -2
  68. data/lib/inspec/resources/rabbitmq_config.rb +0 -56
  69. data/lib/inspec/resources/sybase_conf.rb +0 -41
  70. data/lib/inspec/resources/sybase_session.rb +0 -124
  71. data/lib/inspec/utils/podman.rb +0 -24
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)
@@ -115,7 +117,8 @@ module Inspec
115
117
  next unless profile.supports_platform?
116
118
 
117
119
  write_lockfile(profile) if @create_lockfile
118
- profile.locked_dependencies
120
+ # TODO: InSpec 8: Replace with Profile OnLoad event handling
121
+ profile.locked_dependencies # Only need to do this once, this recurses down
119
122
  profile.load_gem_dependencies
120
123
  profile_context = profile.load_libraries
121
124
 
@@ -125,6 +128,9 @@ module Inspec
125
128
  " on unsupported platform: '#{@backend.platform.name}/#{@backend.platform.release}'."
126
129
  next
127
130
  end
131
+ # TODO: InSpec 8: Replace with Profile OnLoad event handling
132
+ requirement.profile.load_gem_dependencies
133
+ requirement.profile.load_libraries
128
134
  @test_collector.add_profile(requirement.profile)
129
135
  end
130
136
 
@@ -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
 
@@ -10,6 +10,8 @@ module DeprecatedCoreResourcesList
10
10
  mongodb
11
11
  mongodb_conf
12
12
  mongodb_session
13
+ opa_api
14
+ opa_cli
13
15
  podman
14
16
  podman_container
15
17
  podman_image
@@ -17,8 +19,6 @@ module DeprecatedCoreResourcesList
17
19
  podman_pod
18
20
  podman_volume
19
21
  rabbitmq_config
20
- ssh_config
21
- ssh_key
22
22
  sybase_conf
23
23
  sybase_session
24
24
  }.freeze
@@ -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?
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "6.8.24".freeze
2
+ VERSION = "7.0.95".freeze
3
3
  end
@@ -5,6 +5,8 @@ require "inspec/utils/waivers/json_file_reader"
5
5
  module Inspec
6
6
  class WaiverFileReader
7
7
 
8
+ SUPPORTED_FILE_EXTENSION = %w{.yaml .yml .csv .json}.freeze
9
+
8
10
  def self.fetch_waivers_by_profile(profile_id, files)
9
11
  read_waivers_from_file(profile_id, files) if @waivers_data.nil? || @waivers_data[profile_id].nil?
10
12
  @waivers_data[profile_id]
@@ -15,14 +17,10 @@ module Inspec
15
17
  output = {}
16
18
 
17
19
  files.each do |file_path|
18
- data = read_from_file(file_path)
19
- output.merge!(data) if !data.nil? && data.is_a?(Hash)
20
+ next unless valid_waiver_file?(file_path)
20
21
 
21
- if data.nil?
22
- raise Inspec::Exceptions::WaiversFileNotReadable,
23
- "Cannot find parser for waivers file." \
24
- "Check to make sure file has the appropriate extension."
25
- end
22
+ data = parse_waiver_file(file_path)
23
+ output.merge!(data) if data.is_a?(Hash)
26
24
  rescue Inspec::Exceptions::WaiversFileNotReadable, Inspec::Exceptions::WaiversFileInvalidFormatting => e
27
25
  Inspec::Log.error "Error reading waivers file #{file_path}. #{e.message}"
28
26
  Inspec::UI.new.exit(:usage_error)
@@ -31,21 +29,38 @@ module Inspec
31
29
  @waivers_data[profile_id] = output
32
30
  end
33
31
 
34
- def self.read_from_file(file_path)
35
- data = nil
36
- file_extension = File.extname(file_path)
37
- if [".yaml", ".yml"].include? file_extension
38
- data = Secrets::YAML.resolve(file_path)
39
- data = data.inputs unless data.nil?
32
+ def self.valid_waiver_file?(file_path)
33
+ # Check if the file is readable
34
+ file_extension = File.extname(file_path).downcase
35
+ unless SUPPORTED_FILE_EXTENSION.include?(file_extension)
36
+ raise Inspec::Exceptions::WaiversFileNotReadable,
37
+ "Unsupported file extension for '#{file_path}'. Allowed waiver file extensions: #{SUPPORTED_FILE_EXTENSION.join(", ")}"
38
+ end
39
+
40
+ # Check if the file is empty
41
+ if File.zero?(file_path)
42
+ Inspec::Log.warn "Waivers file '#{file_path}' is empty. Skipping waivers."
43
+ return false
44
+ end
45
+
46
+ true
47
+ end
48
+
49
+ def self.parse_waiver_file(file_path)
50
+ file_extension = File.extname(file_path).downcase
51
+
52
+ case file_extension
53
+ when ".yaml", ".yml"
54
+ data = Secrets::YAML.resolve(file_path)&.inputs
40
55
  validate_json_yaml(data)
41
- elsif file_extension == ".csv"
56
+ when ".csv"
42
57
  data = Waivers::CSVFileReader.resolve(file_path)
43
- headers = Waivers::CSVFileReader.headers
44
- validate_csv_headers(headers)
45
- elsif file_extension == ".json"
58
+ validate_csv_headers(Waivers::CSVFileReader.headers)
59
+ when ".json"
46
60
  data = Waivers::JSONFileReader.resolve(file_path)
47
- validate_json_yaml(data) unless data.nil?
61
+ validate_json_yaml(data)
48
62
  end
63
+
49
64
  data
50
65
  end
51
66
 
@@ -81,6 +96,8 @@ module Inspec
81
96
  end
82
97
 
83
98
  def self.validate_json_yaml(data)
99
+ return if data.nil?
100
+
84
101
  missing_required_field = false
85
102
  data.each do |key, value|
86
103
  # In case of yaml or json we need to validate headers/parametes for each value
data/lib/inspec.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
  libdir = File.dirname(__FILE__)
4
6
  $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
@@ -426,7 +426,7 @@ module InspecPlugins
426
426
  "at https://github.com/inspec/inspec/issues/new")
427
427
  ui.exit Inspec::UI::EXIT_PLUGIN_ERROR
428
428
  rescue Inspec::Plugin::V2::InstallError => e
429
- # This change is compatible with various versions of Ruby, including Ruby 3.3
429
+ # This change is required for Ruby 3.3 upgrade
430
430
  # Using Inspec::Log::level breaks with error `undefined method nil` in Ruby log library
431
431
  Inspec::Log.debug e.backtrace
432
432
 
@@ -12,7 +12,7 @@ require "tmpdir" unless defined?(Dir.mktmpdir)
12
12
  require "pathname" unless defined?(Pathname)
13
13
  require "forwardable" unless defined?(Forwardable)
14
14
 
15
- require "functional/helper"
15
+ require_relative "../../../test/functional/helper"
16
16
  require "inspec/plugin/v2"
17
17
 
18
18
  # Configure Minitest to expose things like `let`
@@ -0,0 +1,67 @@
1
+ require "inspec/fetcher"
2
+ require "inspec/metadata"
3
+
4
+ module SourceReaders
5
+ class GemReader < Inspec.source_reader(1)
6
+ name "gem"
7
+ priority 20
8
+
9
+ def self.resolve(target)
10
+ return new(target) unless target.files.grep(/gemspec/).empty?
11
+
12
+ nil
13
+ end
14
+
15
+ attr_reader :metadata, :metadata_src, :tests, :libraries, :data_files, :target, :readme
16
+
17
+ # This creates a new instance of an InSpec Gem-packaged profile source reader
18
+ # As of July 2024 only resource packs, not controls, may be packaged as gems
19
+ #
20
+ # @param [FileProvider] target An instance of a FileProvider object that can list files and read them
21
+ def initialize(target)
22
+ @target = target
23
+ @metadata = load_metadata(target.files.grep("inspec.yml").first)
24
+ @tests = {} # TODO - one day support controls?
25
+ @libraries = load_libs
26
+ @data_files = {}
27
+ @readme = load_readme
28
+ end
29
+
30
+ private
31
+
32
+ def load_metadata(metadata_source)
33
+ @metadata_src = @target.read(metadata_source)
34
+ Inspec::Metadata.from_ref(
35
+ metadata_source,
36
+ @metadata_src,
37
+ nil
38
+ )
39
+ rescue Psych::SyntaxError => e
40
+ raise "Unable to parse inspec.yml: line #{e.line}, #{e.problem} #{e.context}"
41
+ rescue => e
42
+ raise "Unable to parse #{metadata_source}: #{e.class} -- #{e.message}"
43
+ end
44
+
45
+ def find_all(regexp)
46
+ @target.files.grep(regexp)
47
+ end
48
+
49
+ def load_all(regexp)
50
+ find_all(regexp)
51
+ .map { |path| file = @target.read(path); [path, file] if file }
52
+ .compact
53
+ .to_h
54
+ end
55
+
56
+ def load_libs
57
+ # Legacy resource packs (inspec-gcp, inspec-aws, etc) have resources in old locations
58
+ load_all(%r{^libraries/.*\.rb$})
59
+ # New resource packs have them here
60
+ load_all(%r{^lib/.*/resources/.*\.rb$})
61
+ end
62
+
63
+ def load_readme
64
+ load_all(/README.md/)
65
+ end
66
+ end
67
+ end