inspec-core 6.8.24 → 7.0.38.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +6 -6
- data/etc/deprecations.json +15 -6
- data/lib/inspec/base_cli.rb +3 -0
- data/lib/inspec/cached_fetcher.rb +16 -1
- data/lib/inspec/dependencies/cache.rb +48 -4
- data/lib/inspec/dsl.rb +40 -11
- data/lib/inspec/exceptions.rb +1 -0
- data/lib/inspec/fetcher/gem.rb +99 -0
- data/lib/inspec/fetcher/local.rb +1 -1
- data/lib/inspec/fetcher.rb +1 -0
- data/lib/inspec/file_provider.rb +46 -1
- data/lib/inspec/input_registry.rb +1 -1
- data/lib/inspec/plugin/v2/concerns/gem_spec_helper.rb +30 -0
- data/lib/inspec/plugin/v2/gem_source_manager.rb +43 -0
- data/lib/inspec/plugin/v2/installer.rb +42 -16
- data/lib/inspec/plugin/v2/loader.rb +34 -5
- data/lib/inspec/plugin/v2/plugin_types/resource_pack.rb +8 -0
- data/lib/inspec/plugin/v2.rb +1 -0
- data/lib/inspec/profile.rb +10 -0
- data/lib/inspec/profile_context.rb +10 -0
- data/lib/inspec/reporters/automate.rb +2 -2
- data/lib/inspec/resources/auditd.rb +1 -1
- data/lib/inspec/resources/groups.rb +52 -0
- data/lib/inspec/resources/port.rb +2 -2
- data/lib/inspec/resources/postgres_session.rb +5 -9
- data/lib/inspec/resources/yum.rb +1 -1
- data/lib/inspec/resources.rb +0 -14
- data/lib/inspec/runner.rb +7 -15
- data/lib/inspec/source_reader.rb +2 -0
- data/lib/inspec/ui.rb +1 -0
- data/lib/inspec/utils/deprecation/config_file.rb +39 -3
- data/lib/inspec/utils/deprecation/deprecator.rb +10 -3
- data/lib/inspec/utils/licensing_config.rb +1 -15
- data/lib/inspec/utils/parser.rb +9 -19
- data/lib/inspec/utils/telemetry.rb +1 -3
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +2 -4
- data/lib/source_readers/gem.rb +67 -0
- data/lib/source_readers/inspec.rb +1 -1
- metadata +9 -32
- data/lib/inspec/resources/docker.rb +0 -274
- data/lib/inspec/resources/docker_container.rb +0 -116
- data/lib/inspec/resources/docker_image.rb +0 -141
- data/lib/inspec/resources/docker_object.rb +0 -52
- data/lib/inspec/resources/docker_plugin.rb +0 -68
- data/lib/inspec/resources/docker_service.rb +0 -95
- data/lib/inspec/resources/elasticsearch.rb +0 -165
- data/lib/inspec/resources/ibmdb2_conf.rb +0 -65
- data/lib/inspec/resources/ibmdb2_session.rb +0 -78
- data/lib/inspec/resources/mongodb.rb +0 -69
- data/lib/inspec/resources/mongodb_conf.rb +0 -44
- data/lib/inspec/resources/mongodb_session.rb +0 -98
- data/lib/inspec/resources/podman.rb +0 -353
- data/lib/inspec/resources/podman_container.rb +0 -84
- data/lib/inspec/resources/podman_image.rb +0 -108
- data/lib/inspec/resources/podman_network.rb +0 -81
- data/lib/inspec/resources/podman_pod.rb +0 -101
- data/lib/inspec/resources/podman_volume.rb +0 -87
- data/lib/inspec/resources/rabbitmq_conf.rb +0 -2
- data/lib/inspec/resources/rabbitmq_config.rb +0 -56
- data/lib/inspec/resources/ssh_config.rb +0 -215
- data/lib/inspec/resources/ssh_key.rb +0 -124
- data/lib/inspec/resources/sshd_active_config.rb +0 -2
- data/lib/inspec/resources/sshd_config.rb +0 -2
- data/lib/inspec/resources/sybase_conf.rb +0 -41
- data/lib/inspec/resources/sybase_session.rb +0 -124
- data/lib/inspec/utils/deprecated_core_resources_list.rb +0 -25
- data/lib/inspec/utils/podman.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f295e7d99ec735932c005e949cf99cbb1184780d52eae109cec87faf27501c8
|
4
|
+
data.tar.gz: b9fe70883d7593b0d6c7ce51067c7fb2b26154a88981d4ff6458f1f3306518b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f35167f971fcdd9d71a43bf7d6e4baf97ae9f0ac9b16b8ebe33103b15e4fee3892d34f8f2a9c0ef1a499e1860d3a8c2e4080acc20cf5415929c013bc97b0972
|
7
|
+
data.tar.gz: cf3bfdfa97c737abcd3f054a6eb4899de5831e2ebebc8a4e9907865835560ff979acb2a86ccce37059dfb0075fc2d628fbdeb3045357a02ad01a9ea22842e462
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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"
|
data/etc/deprecations.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"file_version": "
|
2
|
+
"file_version": "2.0.0",
|
3
3
|
"unknown_group_action": "ignore",
|
4
4
|
"groups": {
|
5
5
|
"attrs_value_replaces_default": {
|
@@ -73,11 +73,6 @@
|
|
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": "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."
|
80
|
-
},
|
81
76
|
"resource_iis_website": {
|
82
77
|
"action": "exit",
|
83
78
|
"suffix": "This resource was removed in InSpec 4.0.",
|
@@ -131,5 +126,19 @@
|
|
131
126
|
"action": "ignore",
|
132
127
|
"prefix": "The `inspec json` command is deprecated in InSpec 5 and replaced with `inspec export` command."
|
133
128
|
}
|
129
|
+
},
|
130
|
+
"fallback_resource_packs":{
|
131
|
+
"internal_fallback_test.+":{
|
132
|
+
"gem":"inspec-test-resources",
|
133
|
+
"message":"The internal_fallback_test resource is a test resource used to exercise InSpec's ability to fallback on gem resource packs."
|
134
|
+
},
|
135
|
+
"elasticsearch.*": {
|
136
|
+
"gem":"inspec-elasticsearch-resources",
|
137
|
+
"message":"The `inspec-elasticsearch-resources` allows testing of elasticsearch using Inspec."
|
138
|
+
},
|
139
|
+
"docker.+":{
|
140
|
+
"gem": "inspec-docker-resources",
|
141
|
+
"message": "The Inspec docker resources are moved out of InSpec core and will be installed as gem"
|
142
|
+
}
|
134
143
|
}
|
135
144
|
}
|
data/lib/inspec/base_cli.rb
CHANGED
@@ -389,6 +389,9 @@ module Inspec
|
|
389
389
|
when Inspec::InvalidProfileSignature
|
390
390
|
$stderr.puts exception.message
|
391
391
|
Inspec::UI.new.exit(:bad_signature)
|
392
|
+
when Inspec::Exceptions::GemDependencyNotFound
|
393
|
+
$stderr.puts exception.message
|
394
|
+
Inspec::UI.new.exit(:gem_dependency_not_found)
|
392
395
|
when Inspec::Error
|
393
396
|
$stderr.puts exception.message
|
394
397
|
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
|
-
|
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,8 @@ module Inspec
|
|
72
85
|
end
|
73
86
|
|
74
87
|
def assert_cache_sanity!
|
88
|
+
# TODO: update this to handle gem resource pack dependencies
|
89
|
+
# which are known by a special prefix on their cache key or by having the :gem key
|
75
90
|
return unless target.respond_to?(:key?) && target.key?(:sha256)
|
76
91
|
|
77
92
|
exception_message = <<~EOF
|
@@ -45,6 +45,12 @@ module Inspec
|
|
45
45
|
# For a given name and source_url, return true if the
|
46
46
|
# profile exists in the Cache.
|
47
47
|
#
|
48
|
+
# InSpec 7+ Special Magic for Gem-Based Resource Pack Profiles:
|
49
|
+
# These "profiles" are installed as gems, and so are "cached"
|
50
|
+
# by being installed as gems.
|
51
|
+
# The magic is triggered by a special prefix of
|
52
|
+
# the cache_key: gem: or gem_path:
|
53
|
+
#
|
48
54
|
# @param [String] name
|
49
55
|
# @param [String] source_url
|
50
56
|
# @return [Boolean]
|
@@ -52,8 +58,21 @@ module Inspec
|
|
52
58
|
def exists?(key)
|
53
59
|
return false if key.nil? || key.empty?
|
54
60
|
|
55
|
-
|
56
|
-
|
61
|
+
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:")
|
68
|
+
# Gem installed as explicit path reference, as in testing / development
|
69
|
+
entry_point_path = key.sub(/^gem_path:/, "")
|
70
|
+
File.exist?(entry_point_path)
|
71
|
+
else
|
72
|
+
# Standard cache entry
|
73
|
+
path = base_path_for(key)
|
74
|
+
File.directory?(path) || File.exist?("#{path}.tar.gz") || File.exist?("#{path}.zip")
|
75
|
+
end
|
57
76
|
end
|
58
77
|
|
59
78
|
#
|
@@ -67,8 +86,33 @@ module Inspec
|
|
67
86
|
# @param [String] source_url
|
68
87
|
# @return [String]
|
69
88
|
#
|
70
|
-
def base_path_for(
|
71
|
-
|
89
|
+
def base_path_for(key)
|
90
|
+
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)
|
95
|
+
|
96
|
+
elsif key.start_with?("gem_path:")
|
97
|
+
# Gem installed as explicit path reference, as in testing / development
|
98
|
+
entry_point_path = key.sub(/^gem_path:/, "")
|
99
|
+
# We were given an explicit path like
|
100
|
+
# inspec-test-resources/lib/inspec-test-resources.rb
|
101
|
+
# go two directories up
|
102
|
+
parts = Pathname(entry_point_path).each_filename.to_a
|
103
|
+
File.join(parts.slice(0, parts.length - 2))
|
104
|
+
else
|
105
|
+
# Standard cache entry
|
106
|
+
File.join(@path, key)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def gemspec_path_for(key)
|
111
|
+
if key.start_with?("gem:")
|
112
|
+
(_, gem_name, version) = key.split(":")
|
113
|
+
loader = Inspec::Plugin::V2::Loader.new
|
114
|
+
loader.find_gemspec_directory(gem_name, version)
|
115
|
+
end
|
72
116
|
end
|
73
117
|
|
74
118
|
#
|
data/lib/inspec/dsl.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
require "inspec/log"
|
3
3
|
require "inspec/plugin/v2"
|
4
4
|
require "inspec/utils/deprecated_cloud_resources_list"
|
5
|
-
require "inspec/utils/deprecated_core_resources_list"
|
6
5
|
|
7
6
|
module Inspec::DSL
|
8
7
|
attr_accessor :backend
|
@@ -39,20 +38,50 @@ module Inspec::DSL
|
|
39
38
|
return unless backend
|
40
39
|
|
41
40
|
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
41
|
require "inspec/resources/#{id}"
|
47
42
|
rescue LoadError => e
|
48
|
-
include DeprecatedCloudResourcesList
|
49
|
-
cloud_resource = id.start_with?("aws_") ? "aws" : "azure"
|
50
43
|
|
51
|
-
#
|
52
|
-
|
53
|
-
|
44
|
+
# InSpec 7+ Fallback Support for Resource Packs
|
45
|
+
# Use Deprecator to lookup the matching gem
|
46
|
+
# if a gem matches, try to load the resource from the gem
|
47
|
+
gem_name = Inspec::Deprecation::Deprecator.new.match_gem_for_fallback_resource_name(id.to_s)
|
48
|
+
if gem_name
|
49
|
+
# Install if needed
|
50
|
+
cfg = Inspec::Config.cached
|
51
|
+
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)"
|
53
|
+
end
|
54
|
+
|
55
|
+
Inspec::Plugin::V2::Installer.instance.ensure_installed gem_name
|
56
|
+
|
57
|
+
# Load the gem, add gemspecs to the path, load any deps, load resource libraries into registry
|
58
|
+
# This is plugin API orthodoxy but is impossible to program
|
59
|
+
# Inspec::Plugin::V2::Registry.instance.find_activator(gem_name).activate
|
60
|
+
loader = Inspec::Plugin::V2::Loader.new
|
61
|
+
|
62
|
+
# 1. Activate gem and deps.
|
63
|
+
loader.activate_managed_gems_for_plugin(gem_name)
|
64
|
+
|
65
|
+
# 2. Load all libraries from the gem path
|
66
|
+
gem_path = loader.find_gem_directory(gem_name)
|
67
|
+
resources_path = File.join(gem_path, "lib", gem_name, "resources", "*.rb")
|
68
|
+
legacy_library_path = File.join(gem_path, "libraries", "*.rb")
|
69
|
+
Dir.glob([resources_path, legacy_library_path]).each do |resource_lib|
|
70
|
+
require resource_lib
|
71
|
+
end
|
72
|
+
# Resources now available in Inspec::Resource.registry
|
54
73
|
else
|
55
|
-
|
74
|
+
# TODO: InSpec 7: Replace with Fallbacks for inspec-aws-resources and inspec-azure-resources
|
75
|
+
include DeprecatedCloudResourcesList
|
76
|
+
cloud_resource = id.start_with?("aws_") ? "aws" : "azure"
|
77
|
+
|
78
|
+
# Deprecated AWS and Azure resources in InSpec 5.
|
79
|
+
if CLOUD_RESOURCES_DEPRECATED.include? id
|
80
|
+
Inspec.deprecate(:"#{cloud_resource}_resources_in_resource_pack", "Resource '#{id}'")
|
81
|
+
else
|
82
|
+
# OK, give up entirely
|
83
|
+
raise LoadError, "#{e.message}"
|
84
|
+
end
|
56
85
|
end
|
57
86
|
end
|
58
87
|
|
data/lib/inspec/exceptions.rb
CHANGED
@@ -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,99 @@
|
|
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
|
+
if target.is_a?(Hash) && target.key?(:gem)
|
12
|
+
resolve_from_hash(target)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.resolve_from_hash(target)
|
17
|
+
return unless target.key?(:gem)
|
18
|
+
|
19
|
+
new(target)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(target, opts = {})
|
23
|
+
@target = target
|
24
|
+
@gem_name = target[:gem]
|
25
|
+
@version = target[:version] # optional
|
26
|
+
@source = target[:source] # optional
|
27
|
+
@gem_path = target[:path] # optional, sets local path installation mode
|
28
|
+
@backend = opts[:backend]
|
29
|
+
@archive_shasum = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetch(path)
|
33
|
+
plugin_installer = Inspec::Plugin::V2::Installer.instance
|
34
|
+
|
35
|
+
# Determine if gem is installed
|
36
|
+
have_plugin = false
|
37
|
+
Inspec::Log.debug("GemFetcher fetching #{@gem_name} v" + (@version || "ANY"))
|
38
|
+
|
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
|
44
|
+
|
45
|
+
unless have_plugin
|
46
|
+
# Install
|
47
|
+
# TODO - error handling?
|
48
|
+
Inspec::Log.debug("GemFetcher - install request for #{@gem_name}")
|
49
|
+
if @gem_path
|
50
|
+
# No version permitted
|
51
|
+
plugin_installer.install(@gem_name, path: @gem_path)
|
52
|
+
else
|
53
|
+
# Passing an extra gem argument to enable detecting gem based plugins
|
54
|
+
plugin_installer.install(@gem_name, version: @version, source: @source, gem: @gem_name )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Should the plugin activate? No, it should only be "fetched" (installed)
|
59
|
+
# Activation would load resource libararies and would effectively execute the profile
|
60
|
+
|
61
|
+
@target
|
62
|
+
end
|
63
|
+
|
64
|
+
def archive_path
|
65
|
+
@target
|
66
|
+
end
|
67
|
+
|
68
|
+
def writable?
|
69
|
+
# Gem based profile is not writable because it is not cached in lockfile
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def cache_key
|
74
|
+
# 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}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# The intent here is to provide a signature that would change with the content of the profile.
|
86
|
+
# In the case of gems, for released gems, "name-version" should suffice.
|
87
|
+
# For development gems specified by path, the're ever-changing anyway, so just give the path.
|
88
|
+
# In eith case, that string is in fact just the cache key.
|
89
|
+
def sha256
|
90
|
+
cache_key
|
91
|
+
end
|
92
|
+
|
93
|
+
def resolved_source
|
94
|
+
h = { gem: @gem_name, version: @version, gem_path: @gem_path }
|
95
|
+
h[:sha256] = sha256
|
96
|
+
h
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/inspec/fetcher/local.rb
CHANGED
@@ -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
|
data/lib/inspec/fetcher.rb
CHANGED
data/lib/inspec/file_provider.rb
CHANGED
@@ -7,8 +7,12 @@ require "inspec/iaf_file"
|
|
7
7
|
module Inspec
|
8
8
|
class FileProvider
|
9
9
|
def self.for_path(path)
|
10
|
-
if path.
|
10
|
+
raise "Profile or dependency path not resolved." if path.nil?
|
11
|
+
|
12
|
+
if path.is_a?(Hash) && !path.key?(:gem)
|
11
13
|
MockProvider.new(path)
|
14
|
+
elsif path.is_a?(Hash) && path.key?(:gem)
|
15
|
+
GemProvider.new(path)
|
12
16
|
elsif File.directory?(path)
|
13
17
|
DirProvider.new(path)
|
14
18
|
elsif File.exist?(path) && path.end_with?(".tar.gz", "tgz")
|
@@ -99,6 +103,47 @@ module Inspec
|
|
99
103
|
end
|
100
104
|
end # class DirProvider
|
101
105
|
|
106
|
+
class GemProvider < FileProvider
|
107
|
+
attr_reader :files
|
108
|
+
def initialize(gem_info)
|
109
|
+
# Determine a path to the gem installation directory
|
110
|
+
gem_name = gem_info[:gem]
|
111
|
+
bootstrap_file = gem_info[:path]
|
112
|
+
gem_version = gem_info[:version]
|
113
|
+
if bootstrap_file
|
114
|
+
# We were given an explicit path - go two directories up
|
115
|
+
parts = Pathname(gem_info[:path]).each_filename.to_a
|
116
|
+
@gem_lib_root = File.join(parts.slice(0, parts.length - 2))
|
117
|
+
@files = Dir[File.join(Shellwords.shellescape(@gem_lib_root), "**", "*")]
|
118
|
+
else
|
119
|
+
# Look up where the gem is installed, respecting version
|
120
|
+
loader = Inspec::Plugin::V2::Loader.new
|
121
|
+
gem_path = loader.find_gem_directory(gem_name, gem_version)
|
122
|
+
if gem_path && File.exist?(gem_path)
|
123
|
+
gem = DirProvider.new(gem_path)
|
124
|
+
@files = gem.files
|
125
|
+
gem
|
126
|
+
else
|
127
|
+
raise Inspec::Exceptions::GemDependencyNotFound, "Dependency does not exist #{gem_name}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def read(file)
|
133
|
+
return nil unless files.include?(file)
|
134
|
+
return nil unless File.file?(file)
|
135
|
+
|
136
|
+
File.read(file)
|
137
|
+
end
|
138
|
+
|
139
|
+
def binread(file)
|
140
|
+
return nil unless files.include?(file)
|
141
|
+
return nil unless File.file?(file)
|
142
|
+
|
143
|
+
File.binread(file)
|
144
|
+
end
|
145
|
+
end # class GemProvider
|
146
|
+
|
102
147
|
class ZipProvider < FileProvider
|
103
148
|
attr_reader :files
|
104
149
|
|
@@ -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(
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Inspec
|
4
|
+
module Plugin
|
5
|
+
module V2
|
6
|
+
# holds all GemSpec related helper functions
|
7
|
+
module GemSpecHelper
|
8
|
+
|
9
|
+
def loaded_recent_most_version_of?(gemspec)
|
10
|
+
# Check if the gem is already loaded via bundler
|
11
|
+
# In most cases this is true since all Plugins/Resource Packs inherit from inspec-core
|
12
|
+
gem_name = gemspec.name
|
13
|
+
loaded_gem = Gem.loaded_specs[gem_name]
|
14
|
+
return false unless loaded_gem
|
15
|
+
|
16
|
+
# follow bundler's original philosophy i.e load gems that are recent most
|
17
|
+
# This logic works unless there is a pinned version which we don't expect to have since these are managed by us
|
18
|
+
if gemspec.version > loaded_gem.version
|
19
|
+
# deactivate the lower version specs that are loaded via bundler
|
20
|
+
Gem.loaded_specs.delete(gem_name)
|
21
|
+
false # so it can re-activate the requested spec
|
22
|
+
else
|
23
|
+
# don't activate requested gemspec when the already loaded gem is the most recent version
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "singleton" unless defined?(Singleton)
|
3
|
+
require "forwardable" unless defined?(Forwardable)
|
4
|
+
require "chef-licensing"
|
5
|
+
|
6
|
+
module Inspec::Plugin::V2
|
7
|
+
class GemSourceManager
|
8
|
+
include Singleton
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
DEFAULT_CHEF_RUBY_GEMS_SERVER = "rubygems.chef.io"
|
12
|
+
DEFAULT_USERNAME = "v1"
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@sources = Gem.sources
|
16
|
+
end
|
17
|
+
|
18
|
+
def_delegator :@sources, :sources
|
19
|
+
|
20
|
+
def add_chef_rubygems_server
|
21
|
+
register_source(chef_rubygems_server)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(sources)
|
25
|
+
Array(sources).each { |source| register_source(source) }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def chef_rubygems_server
|
31
|
+
"https://#{DEFAULT_USERNAME}:#{licenses_string}@#{DEFAULT_CHEF_RUBY_GEMS_SERVER}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_source(source)
|
35
|
+
gem_source = Gem::Source.new(source)
|
36
|
+
sources << gem_source unless sources.include?(gem_source)
|
37
|
+
end
|
38
|
+
|
39
|
+
def licenses_string
|
40
|
+
ChefLicensing.license_keys.join(",")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -12,6 +12,9 @@ require "rubygems/uninstaller"
|
|
12
12
|
require "rubygems/remote_fetcher"
|
13
13
|
|
14
14
|
require "inspec/plugin/v2/filter"
|
15
|
+
require "inspec/plugin/v2/concerns/gem_spec_helper"
|
16
|
+
|
17
|
+
require "inspec/plugin/v2/gem_source_manager"
|
15
18
|
|
16
19
|
module Inspec::Plugin::V2
|
17
20
|
# Handles all actions modifying the user's plugin set:
|
@@ -23,6 +26,7 @@ module Inspec::Plugin::V2
|
|
23
26
|
class Installer
|
24
27
|
include Singleton
|
25
28
|
extend Forwardable
|
29
|
+
include Inspec::Plugin::V2::GemSpecHelper
|
26
30
|
|
27
31
|
Gem.configuration["verbose"] = false
|
28
32
|
|
@@ -45,6 +49,10 @@ module Inspec::Plugin::V2
|
|
45
49
|
list_installed_plugin_gems.detect { |spec| spec.name == name && spec.version == Gem::Version.new(version) }
|
46
50
|
end
|
47
51
|
|
52
|
+
def ensure_installed(name)
|
53
|
+
plugin_installed?(name) || install(name)
|
54
|
+
end
|
55
|
+
|
48
56
|
# Installs a plugin. Defaults to assuming the plugin provided is a gem, and will try to install
|
49
57
|
# from whatever gemsources `rubygems` thinks it should use.
|
50
58
|
# If it's a gem, installs it and its dependencies to the `gem_path`. The gem is not activated.
|
@@ -213,7 +221,10 @@ module Inspec::Plugin::V2
|
|
213
221
|
if opts.key?(:version) && plugin_version_installed?(plugin_name, opts[:version])
|
214
222
|
raise InstallError, "#{plugin_name} version #{opts[:version]} is already installed."
|
215
223
|
else
|
216
|
-
|
224
|
+
# Do not redirect to plugin update when using gem based plugin
|
225
|
+
unless gem_based_plugin?(opts)
|
226
|
+
raise InstallError, "#{plugin_name} is already installed. Use 'inspec plugin update' to change version."
|
227
|
+
end
|
217
228
|
end
|
218
229
|
end
|
219
230
|
|
@@ -296,18 +307,21 @@ module Inspec::Plugin::V2
|
|
296
307
|
install_gem_to_plugins_dir(plugin_dependency, [requested_local_gem_set])
|
297
308
|
end
|
298
309
|
|
299
|
-
def install_from_remote_gems(requested_plugin_name, opts)
|
310
|
+
def install_from_remote_gems(requested_plugin_name, opts, source_manager: GemSourceManager.instance)
|
300
311
|
plugin_dependency = Gem::Dependency.new(requested_plugin_name, opts[:version] || "> 0")
|
312
|
+
source_manager.add_chef_rubygems_server # ensure CHEF RUBYGEMS server is added to the source
|
313
|
+
|
314
|
+
# This adds custom gem sources to the memoized `Gem.Sources` for this specific run
|
315
|
+
# Note: This will not make any change to the environment Gem source list and
|
316
|
+
# in fact will consider all of the environment Gem sources and custom gem sources to resolve deps
|
317
|
+
source_manager.add(opts[:source])
|
301
318
|
|
302
|
-
# BestSet is rubygems.org API + indexing
|
303
|
-
sources
|
304
|
-
|
305
|
-
else
|
306
|
-
Gem::Resolver::BestSet.new
|
307
|
-
end
|
319
|
+
# BestSet is rubygems.org API + indexing by default
|
320
|
+
# `Gem.sources` is injected as a dependency implicitly while BestSet is initialized
|
321
|
+
sources = Gem::Resolver::BestSet.new
|
308
322
|
|
309
323
|
begin
|
310
|
-
install_gem_to_plugins_dir(plugin_dependency, [sources], opts[:update_mode])
|
324
|
+
install_gem_to_plugins_dir(plugin_dependency, [sources], opts[:update_mode], opts: opts)
|
311
325
|
rescue Gem::RemoteFetcher::FetchError => gem_ex
|
312
326
|
# TODO: Give a hint if the host was not resolvable or a 404 occured
|
313
327
|
ex = Inspec::Plugin::V2::InstallError.new(gem_ex.message)
|
@@ -318,7 +332,7 @@ module Inspec::Plugin::V2
|
|
318
332
|
|
319
333
|
def install_gem_to_plugins_dir(new_plugin_dependency, # rubocop: disable Metrics/AbcSize
|
320
334
|
extra_request_sets = [],
|
321
|
-
update_mode = false)
|
335
|
+
update_mode = false, opts: {})
|
322
336
|
|
323
337
|
# Get a list of all the gems available to us.
|
324
338
|
gem_to_force_update = update_mode ? new_plugin_dependency.name : nil
|
@@ -338,21 +352,28 @@ module Inspec::Plugin::V2
|
|
338
352
|
|
339
353
|
# Activate all current plugins before trying to activate the new one
|
340
354
|
loader.list_managed_gems.each do |spec|
|
341
|
-
|
355
|
+
# Skip in case of update mode
|
356
|
+
# Skip in case using a gem based plugin
|
357
|
+
next if spec.name == new_plugin_dependency.name && (update_mode || gem_based_plugin?(opts))
|
342
358
|
|
343
|
-
|
359
|
+
# activate the requested gemspec from the Gem::RequestSet
|
360
|
+
spec.activate unless loaded_recent_most_version_of?(spec)
|
344
361
|
end
|
345
362
|
|
346
363
|
# Make sure we remove any previously loaded gem on update
|
347
|
-
|
364
|
+
# Make sure we remove any previously loaded gem when trying to use resource pack gem
|
365
|
+
# Gem based plugin when updated need to deactivate older version of gem
|
366
|
+
Gem.loaded_specs.delete(new_plugin_dependency.name) if update_mode || gem_based_plugin?(opts)
|
348
367
|
|
349
368
|
# Test activating the solution. This makes sure we do not try to load two different versions
|
350
369
|
# of the same gem on the stack or a malformed dependency.
|
351
370
|
begin
|
352
371
|
solution.each do |activation_request|
|
353
|
-
|
354
|
-
|
355
|
-
|
372
|
+
requested_gemspec = activation_request.full_spec
|
373
|
+
next if requested_gemspec.activated?
|
374
|
+
|
375
|
+
# activate the requested gemspec from the Gem::RequestSet
|
376
|
+
requested_gemspec.activate unless loaded_recent_most_version_of?(requested_gemspec)
|
356
377
|
end
|
357
378
|
rescue Gem::LoadError => gem_ex
|
358
379
|
ex = Inspec::Plugin::V2::InstallError.new(gem_ex.message)
|
@@ -536,5 +557,10 @@ module Inspec::Plugin::V2
|
|
536
557
|
|
537
558
|
conf_file
|
538
559
|
end
|
560
|
+
|
561
|
+
def gem_based_plugin?(opts)
|
562
|
+
# Param passed by gem fetcher while installing a new gem plugin dependency.
|
563
|
+
!!opts[:gem]
|
564
|
+
end
|
539
565
|
end
|
540
566
|
end
|