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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '06894dd5c2b09dac3432041d74b257a5b25dd00c9c0a2d623e7343e6a651e1b6'
4
- data.tar.gz: 20592025afc13ecdcae95fcde514b8bc4b5855358e93dcef24365d15aa773eb1
3
+ metadata.gz: 2e160d7044fa022329cb438d770054bb63107b59f219030464c709f6b1dcda93
4
+ data.tar.gz: 1dc6673dc552f75cb9b8671b0a466feb2c818f069112fac69aa63b1de568ef54
5
5
  SHA512:
6
- metadata.gz: 2d0a1749cfa6f3d1f517f31e5bc722f85ad5ecf8dd4d155df88afcc41c76c93ba21bba3749b534fd1515a724af17bedc706755606a4a3c109a655ef891bc0e0d
7
- data.tar.gz: 2f0b14a4f79fad859d931a8d0427d88306beb44b7b4f8698910a053d383ebc05a28b9b440c7164cfd5f712d56ba08aeb35afa51b21ef1c5f157b4fb525dd2d3c
6
+ metadata.gz: a389860f421bec680c4db4462fc4cf5765073661cc1154f5fe57e823f7b4f33b10d1ecd22fb286d3a50cd467170645d460ba80b96515331bd2aec9eaa80d8579
7
+ data.tar.gz: 6133800736ed63493d37bca5b3727740b1a1ab7eadb9919ffc8b728f021604a9dd7bf1d1b388169566bc4e484b3fb2fc26845e05769f1dc2afa26f530fddf7a0
data/Gemfile CHANGED
@@ -29,12 +29,12 @@ gem "ffi", ">= 1.15.5", "< 1.17.0"
29
29
  # but our runtime dep is still 3.9+
30
30
  gem "rspec", ">= 3.10"
31
31
 
32
- group :omnibus do
33
- gem "rb-readline"
34
- gem "appbundler"
35
- gem "ed25519" # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
36
- gem "bcrypt_pbkdf" # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
37
- end
32
+ # group :omnibus do
33
+ # gem "rb-readline"
34
+ # gem "appbundler"
35
+ # gem "ed25519" # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
36
+ # gem "bcrypt_pbkdf" # ed25519 ssh key support done here as its a native gem we can't put in the gemspec
37
+ # end
38
38
 
39
39
  group :test do
40
40
  gem "chefstyle"
@@ -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
@@ -1,5 +1,5 @@
1
1
  {
2
- "file_version": "1.0.0",
2
+ "file_version": "2.0.0",
3
3
  "unknown_group_action": "ignore",
4
4
  "groups": {
5
5
  "attrs_value_replaces_default": {
@@ -74,9 +74,9 @@
74
74
  "suffix": "This resource was removed in InSpec 4.0."
75
75
  },
76
76
  "core_resource_moved_to_rp": {
77
- "action": "warn",
78
- "suffix": "This resource will be moved to a separate resource pack. Additional details will be provided with the InSpec 7 release.",
79
- "comment": "Deprecation notice for core resource which are getting moved to resource packs."
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
80
  },
81
81
  "resource_iis_website": {
82
82
  "action": "exit",
@@ -131,5 +131,43 @@
131
131
  "action": "ignore",
132
132
  "prefix": "The `inspec json` command is deprecated in InSpec 5 and replaced with `inspec export` command."
133
133
  }
134
+ },
135
+ "fallback_resource_packs":{
136
+ "internal_fallback_test.+":{
137
+ "gem":"inspec-test-resources",
138
+ "message":"The internal_fallback_test resource is a test resource used to exercise InSpec's ability to fallback on gem resource packs."
139
+ },
140
+ "elasticsearch.*": {
141
+ "gem":"inspec-elasticsearch-resources",
142
+ "message":"The `inspec-elasticsearch-resources` allows testing of elasticsearch using Inspec."
143
+ },
144
+ "docker.+":{
145
+ "gem": "inspec-docker-resources",
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"
171
+ }
134
172
  }
135
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)
@@ -389,6 +399,9 @@ module Inspec
389
399
  when Inspec::InvalidProfileSignature
390
400
  $stderr.puts exception.message
391
401
  Inspec::UI.new.exit(:bad_signature)
402
+ when Inspec::Exceptions::GemDependencyNotFound
403
+ $stderr.puts exception.message
404
+ Inspec::UI.new.exit(:gem_dependency_not_found)
392
405
  when Inspec::Error
393
406
  $stderr.puts exception.message
394
407
  exit(1)
@@ -52,7 +52,19 @@ module Inspec
52
52
  fetch
53
53
  elsif cache.exists?(cache_key) && !cache.locked?(cache_key)
54
54
  Inspec::Log.debug "Using cached dependency for #{target}"
55
- [cache.prefered_entry_for(cache_key), false]
55
+ cache_value = cache.prefered_entry_for(cache_key)
56
+ if cache_value
57
+ [cache_value, false]
58
+ else
59
+ Inspec::Log.debug "Dependency does not exist in the cache for target #{target}"
60
+ cache_key_name = cache_key
61
+ if cache_key_name.start_with?("gem:")
62
+ # When cache for gem - meaning gemspec exists but gem does not exists then clearing up gemspec is required
63
+ # This logic enables the gem fetcher logic to work step by step again
64
+ Inspec::Log.debug "Clearing cached gemspec to fix dependency issue and enable fresh download."
65
+ FileUtils.rm_rf(cache.gemspec_path_for(cache_key))
66
+ end
67
+ end
56
68
  else
57
69
  begin
58
70
  Inspec::Log.debug "Dependency does not exist in the cache #{target}"
@@ -61,6 +73,7 @@ module Inspec
61
73
  rescue SystemExit => e
62
74
  exit_code = e.status || 1
63
75
  Inspec::Log.error "Error while creating cache for dependency ... #{e.message}"
76
+ # TODO: in the case of gem profile/resource pack dependency installs gone awry, this is the wrong thing to do!
64
77
  FileUtils.rm_rf(cache.base_path_for(fetcher.cache_key))
65
78
  exit(exit_code)
66
79
  ensure
@@ -72,6 +85,9 @@ module Inspec
72
85
  end
73
86
 
74
87
  def assert_cache_sanity!
88
+ # do not check cache sanity if the target is a gem or a resource pack
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)
75
91
  return unless target.respond_to?(:key?) && target.key?(:sha256)
76
92
 
77
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)
@@ -45,6 +46,12 @@ module Inspec
45
46
  # For a given name and source_url, return true if the
46
47
  # profile exists in the Cache.
47
48
  #
49
+ # InSpec 7+ Special Magic for Gem-Based Resource Pack Profiles:
50
+ # These "profiles" are installed as gems, and so are "cached"
51
+ # by being installed as gems.
52
+ # The magic is triggered by a special prefix of
53
+ # the cache_key: gem: or gem_path:
54
+ #
48
55
  # @param [String] name
49
56
  # @param [String] source_url
50
57
  # @return [Boolean]
@@ -52,8 +59,18 @@ module Inspec
52
59
  def exists?(key)
53
60
  return false if key.nil? || key.empty?
54
61
 
55
- path = base_path_for(key)
56
- File.directory?(path) || File.exist?("#{path}.tar.gz") || File.exist?("#{path}.zip")
62
+ if key.start_with?("gem:")
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
66
+ # Gem installed as explicit path reference, as in testing / development
67
+ entry_point_path = key.sub(/^gem_path:/, "")
68
+ File.exist?(entry_point_path)
69
+ else
70
+ # Standard cache entry
71
+ path = base_path_for(key)
72
+ File.directory?(path) || File.exist?("#{path}.tar.gz") || File.exist?("#{path}.zip")
73
+ end
57
74
  end
58
75
 
59
76
  #
@@ -67,8 +84,33 @@ module Inspec
67
84
  # @param [String] source_url
68
85
  # @return [String]
69
86
  #
70
- def base_path_for(cache_key)
71
- File.join(@path, cache_key)
87
+ def base_path_for(key)
88
+ if key.start_with?("gem:")
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)
93
+
94
+ elsif key.start_with?("gem_path:")
95
+ # Gem installed as explicit path reference, as in testing / development
96
+ entry_point_path = key.sub(/^gem_path:/, "")
97
+ # We were given an explicit path like
98
+ # inspec-test-resources/lib/inspec-test-resources.rb
99
+ # go two directories up
100
+ parts = Pathname(entry_point_path).each_filename.to_a
101
+ File.join(parts.slice(0, parts.length - 2))
102
+ else
103
+ # Standard cache entry
104
+ File.join(@path, key)
105
+ end
106
+ end
107
+
108
+ def gemspec_path_for(key)
109
+ if key.start_with?("gem:")
110
+ (_, gem_name, version) = key.split(":")
111
+ loader = Inspec::Plugin::V2::Loader.new
112
+ loader.find_gemspec_directory(gem_name, version)
113
+ end
72
114
  end
73
115
 
74
116
  #
@@ -78,9 +120,7 @@ module Inspec
78
120
  locked = false
79
121
  path = base_path_for(key)
80
122
  # For archive there is no need to lock the directory so we skip those and return false for archive formatted cache
81
- if File.directory?(path)
82
- locked = File.exist?("#{path}/.lock")
83
- end
123
+ locked = File.exist?("#{path}/.lock") if File.directory?(path)
84
124
  locked
85
125
  end
86
126
 
data/lib/inspec/dsl.rb CHANGED
@@ -1,4 +1,7 @@
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"
@@ -39,20 +42,51 @@ module Inspec::DSL
39
42
  return unless backend
40
43
 
41
44
  begin
42
- include DeprecatedCoreResourcesList
43
- if CORE_RESOURCES_DEPRECATED.include? id
44
- Inspec.deprecate(:core_resource_moved_to_rp, "The resource '#{id}' will not be part of the InSpec 7 core.")
45
- end
46
45
  require "inspec/resources/#{id}"
47
46
  rescue LoadError => e
48
- include DeprecatedCloudResourcesList
49
- cloud_resource = id.start_with?("aws_") ? "aws" : "azure"
50
47
 
51
- # Deprecated AWS and Azure resources in InSpec 5.
52
- if CLOUD_RESOURCES_DEPRECATED.include? id
53
- Inspec.deprecate(:"#{cloud_resource}_resources_in_resource_pack", "Resource '#{id}'")
48
+ # InSpec 7+ Fallback Support for Resource Packs
49
+ # Use Deprecator to lookup the matching gem
50
+ # if a gem matches, try to load the resource from the gem
51
+ gem_name = Inspec::Deprecation::Deprecator.new.match_gem_for_fallback_resource_name(id.to_s)
52
+ if gem_name
53
+ # Install if needed
54
+ cfg = Inspec::Config.cached
55
+ unless cfg.final_options[: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
+
58
+ end
59
+
60
+ Inspec::Plugin::V2::Installer.instance.ensure_installed gem_name
61
+
62
+ # Load the gem, add gemspecs to the path, load any deps, load resource libraries into registry
63
+ # This is plugin API orthodoxy but is impossible to program
64
+ # Inspec::Plugin::V2::Registry.instance.find_activator(gem_name).activate
65
+ loader = Inspec::Plugin::V2::Loader.new
66
+
67
+ # 1. Activate gem and deps.
68
+ loader.activate_managed_gems_for_plugin(gem_name)
69
+
70
+ # 2. Load all libraries from the gem path
71
+ gem_path = loader.find_gem_directory(gem_name)
72
+ resources_path = File.join(gem_path, "lib", gem_name, "resources", "*.rb")
73
+ legacy_library_path = File.join(gem_path, "libraries", "*.rb")
74
+ Dir.glob([resources_path, legacy_library_path]).each do |resource_lib|
75
+ require resource_lib
76
+ end
77
+ # Resources now available in Inspec::Resource.registry
54
78
  else
55
- raise LoadError, "#{e.message}"
79
+ # TODO: InSpec 7: Replace with Fallbacks for inspec-aws-resources and inspec-azure-resources
80
+ include DeprecatedCloudResourcesList
81
+ cloud_resource = id.start_with?("aws_") ? "aws" : "azure"
82
+
83
+ # Deprecated AWS and Azure resources in InSpec 5.
84
+ if CLOUD_RESOURCES_DEPRECATED.include? id
85
+ Inspec.deprecate(:"#{cloud_resource}_resources_in_resource_pack", "Resource '#{id}'")
86
+ else
87
+ # OK, give up entirely
88
+ raise LoadError, "#{e.message}"
89
+ end
56
90
  end
57
91
  end
58
92
 
@@ -7,6 +7,7 @@ module Inspec
7
7
  class ProfileLoadFailed < StandardError; end
8
8
  class ResourceFailed < StandardError; end
9
9
  class ResourceSkipped < StandardError; end
10
+ class GemDependencyNotFound < StandardError; end
10
11
  class SecretsBackendNotFound < ArgumentError; end
11
12
  class ProfileValidationKeyNotFound < ArgumentError; end
12
13
  class ProfileSigningKeyNotFound < ArgumentError; end
@@ -0,0 +1,117 @@
1
+ require "inspec/plugin/v2/installer"
2
+
3
+ module Inspec::Fetcher
4
+ class Gem < Inspec.fetcher(1)
5
+ name "gem"
6
+ priority 0.5 # TODO: verify value
7
+ # Priority is used for setting precedence of fetchers. And registry plugin(v1) decides which fetcher to use for loading profiles by using this priority
8
+ # Gem fetcher's priority should be lowest because gem profiles are only executables via inspec metadata
9
+
10
+ def self.resolve(target)
11
+ resolve_from_hash(target) if target.is_a?(Hash) && target.key?(:gem)
12
+ end
13
+
14
+ def self.resolve_from_hash(target)
15
+ return unless target.key?(:gem)
16
+
17
+ new(target)
18
+ end
19
+
20
+ def initialize(target, opts = {})
21
+ @target = target
22
+ @gem_name = target[:gem]
23
+ @version = target[:version] # optional
24
+ @source = target[:source] # optional
25
+ @gem_path = target[:path] # optional, sets local path installation mode
26
+ @backend = opts[:backend]
27
+ @archive_shasum = nil
28
+ end
29
+
30
+ def fetch(path)
31
+ plugin_installer = Inspec::Plugin::V2::Installer.instance
32
+
33
+ Inspec::Log.debug("GemFetcher fetching #{@gem_name} v" + (@version || "ANY"))
34
+
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
40
+
41
+ unless have_plugin
42
+ # Install
43
+ # TODO - error handling?
44
+ Inspec::Log.debug("GemFetcher - install request for #{@gem_name}")
45
+ if @gem_path
46
+ # No version permitted
47
+ plugin_installer.install(@gem_name, gem: @gem_name, path: @gem_path)
48
+ else
49
+ # Passing an extra gem argument to enable detecting gem based plugins
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
67
+ end
68
+ end
69
+
70
+ # Should the plugin activate? No, it should only be "fetched" (installed)
71
+ # Activation would load resource libararies and would effectively execute the profile
72
+
73
+ @target
74
+ end
75
+
76
+ attr_reader :archive_path
77
+
78
+ def writable?
79
+ # Gem based profile is not writable because it is not cached in lockfile
80
+ false
81
+ end
82
+
83
+ def cache_key
84
+ # This special value is interpreted by Inspec::Cache.exists?
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)
94
+ end
95
+ end
96
+
97
+ # The intent here is to provide a signature that would change with the content of the profile.
98
+ # In the case of gems, for released gems, "name-version" should suffice.
99
+ # For development gems specified by path, the're ever-changing anyway, so just give the path.
100
+ # In eith case, that string is in fact just the cache key.
101
+ def sha256
102
+ cache_key
103
+ end
104
+
105
+ def resolved_source
106
+ h = { gem: @gem_name, version: gem_version, gem_path: @gem_path }
107
+ h[:sha256] = sha256
108
+ h
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
116
+ end
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}")
@@ -10,7 +10,7 @@ module Inspec::Fetcher
10
10
  if target.is_a?(String)
11
11
  local_path = resolve_from_string(target)
12
12
  new(local_path) if local_path
13
- elsif target.is_a?(Hash)
13
+ elsif target.is_a?(Hash) && !target.key?(:gem)
14
14
  local_path = resolve_from_hash(target)
15
15
  new(local_path, target) if local_path
16
16
  end
@@ -43,4 +43,5 @@ end
43
43
  require "inspec/fetcher/local"
44
44
  require "inspec/fetcher/url"
45
45
  require "inspec/fetcher/git"
46
+ require "inspec/fetcher/gem"
46
47
  require "plugins/inspec-compliance/lib/inspec-compliance/api"