inspec-core 4.56.20 → 5.7.9
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/etc/deprecations.json +12 -11
- data/inspec-core.gemspec +1 -1
- data/lib/inspec/base_cli.rb +14 -2
- data/lib/inspec/cli.rb +15 -2
- data/lib/inspec/dependency_installer.rb +74 -0
- data/lib/inspec/dependency_loader.rb +97 -0
- data/lib/inspec/dsl.rb +11 -2
- data/lib/inspec/errors.rb +7 -0
- data/lib/inspec/formatters/base.rb +23 -0
- data/lib/inspec/metadata.rb +36 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
- data/lib/inspec/profile.rb +68 -7
- data/lib/inspec/reporters/automate.rb +1 -1
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters/json.rb +31 -11
- data/lib/inspec/resource.rb +6 -0
- data/lib/inspec/resources/cron.rb +49 -0
- data/lib/inspec/resources/ipfilter.rb +59 -0
- data/lib/inspec/resources/ipnat.rb +58 -0
- data/lib/inspec/resources/oracledb_session.rb +3 -7
- data/lib/inspec/resources/postgres_session.rb +2 -4
- data/lib/inspec/resources.rb +3 -16
- data/lib/inspec/runner.rb +18 -1
- data/lib/inspec/runner_rspec.rb +15 -0
- data/lib/inspec/schema/exec_json.rb +59 -58
- data/lib/inspec/schema/exec_json_min.rb +16 -16
- data/lib/inspec/schema/primitives.rb +68 -51
- data/lib/inspec/schema/profile_json.rb +27 -27
- data/lib/inspec/schema.rb +1 -0
- data/lib/inspec/ui.rb +1 -0
- data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec.rb +3 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
- data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
- data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
- data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
- data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
- data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
- data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
- data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
- metadata +20 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c3af1b1fd71ded2286e8aa90c46c74dd20f7fb31c525e56ae03e52952c26b0f
|
|
4
|
+
data.tar.gz: 507db51585f790cc26af852626b3bb52f8a35f36870ee563902234f1c2664a2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00447ba26c980417a501be959fb8ca85268db4e600417c11a912181da2c75c41169d419f1177fac484a12c1c405cae3aab5912ec9cab24f9a9e4adf355d40faa
|
|
7
|
+
data.tar.gz: f007b4bc1998187a7313f34f8739145f5e511500e2c9ca280b7163495a6909646be25fed9b4307a27f370e5e36b94b36b558c9e8d5c67079dc6cf24fb93029ea
|
data/etc/deprecations.json
CHANGED
|
@@ -17,9 +17,14 @@
|
|
|
17
17
|
"prefix": "Inputs should be specified by using the 'inputs' key in profile metadata, not 'attributes'."
|
|
18
18
|
},
|
|
19
19
|
"aws_resources_in_resource_pack": {
|
|
20
|
-
"comment": "
|
|
21
|
-
"action": "
|
|
22
|
-
"prefix": "AWS resources
|
|
20
|
+
"comment": "Deprecated in InSpec 5",
|
|
21
|
+
"action": "exit",
|
|
22
|
+
"prefix": "AWS resources in core InSpec are deprecated and have been removed in InSpec 5. They are now part of a resource pack. Please update your profiles to depend on git@github.com:inspec/inspec-aws.git ."
|
|
23
|
+
},
|
|
24
|
+
"azure_resources_in_resource_pack": {
|
|
25
|
+
"comment": "Deprecated in InSpec 5",
|
|
26
|
+
"action": "exit",
|
|
27
|
+
"prefix": "Azure resources in core InSpec are deprecated and have been removed in InSpec 5. They are now part of a resource pack. Please update your profiles to depend on git@github.com:inspec/inspec-azure.git ."
|
|
23
28
|
},
|
|
24
29
|
"cli_option_json_config": {
|
|
25
30
|
"action": "ignore",
|
|
@@ -55,10 +60,6 @@
|
|
|
55
60
|
"action": "fail_control",
|
|
56
61
|
"suffix": "This property was removed in InSpec 4.0."
|
|
57
62
|
},
|
|
58
|
-
"properties_aws_iam_user": {
|
|
59
|
-
"action": "fail_control",
|
|
60
|
-
"suffix": "This property was removed in InSpec 4.0."
|
|
61
|
-
},
|
|
62
63
|
"properties_shadow": {
|
|
63
64
|
"action": "fail_control",
|
|
64
65
|
"suffix": "This property was removed in InSpec 4.0."
|
|
@@ -72,10 +73,6 @@
|
|
|
72
73
|
"action": "exit",
|
|
73
74
|
"suffix": "This resource was removed in InSpec 4.0."
|
|
74
75
|
},
|
|
75
|
-
"resource_azure_generic_resource": {
|
|
76
|
-
"action": "warn",
|
|
77
|
-
"prefix": "The azure_generic_resource is deprecated. Please use a specific resource. See: 'https://github.com/inspec/inspec/issues/3131'"
|
|
78
|
-
},
|
|
79
76
|
"resource_iis_website": {
|
|
80
77
|
"action": "exit",
|
|
81
78
|
"suffix": "This resource was removed in InSpec 4.0.",
|
|
@@ -125,6 +122,10 @@
|
|
|
125
122
|
"action": "warn",
|
|
126
123
|
"prefix": "The --hook option is being replaced by the --activator option.",
|
|
127
124
|
"suffix": "This options will be removed in InSpec 4.0."
|
|
125
|
+
},
|
|
126
|
+
"cli_option_target_id":{
|
|
127
|
+
"action": "warn",
|
|
128
|
+
"prefix": "The --target-id option is deprecated in InSpec 5. Its value will be ignored."
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
}
|
data/inspec-core.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.license = "Apache-2.0"
|
|
14
14
|
spec.require_paths = ["lib"]
|
|
15
15
|
|
|
16
|
-
spec.required_ruby_version = ">= 2.
|
|
16
|
+
spec.required_ruby_version = ">= 2.7"
|
|
17
17
|
|
|
18
18
|
# the gemfile and gemspec are necessary for appbundler so don't remove it
|
|
19
19
|
spec.files =
|
data/lib/inspec/base_cli.rb
CHANGED
|
@@ -99,8 +99,18 @@ module Inspec
|
|
|
99
99
|
desc: "Specify a particular shell to use."
|
|
100
100
|
option :ssl, type: :boolean,
|
|
101
101
|
desc: "Use SSL for transport layer encryption (WinRM)."
|
|
102
|
+
option :ssl_peer_fingerprint, type: :string,
|
|
103
|
+
desc: "Specify peer fingerprint for SSL authentication, used in lieu of certificates"
|
|
102
104
|
option :self_signed, type: :boolean,
|
|
103
105
|
desc: "Allow remote scans with self-signed certificates (WinRM)."
|
|
106
|
+
option :ca_trust_file, type: :string,
|
|
107
|
+
desc: "Specify CA trust file for SSL authentication"
|
|
108
|
+
option :client_cert, type: :string,
|
|
109
|
+
desc: "Specify client certificate for SSL authentication"
|
|
110
|
+
option :client_key, type: :string,
|
|
111
|
+
desc: "Specify client key required with client cert for SSL authentication"
|
|
112
|
+
option :client_key_pass, type: :string, lazy_default: -1,
|
|
113
|
+
desc: "Specify client cert password, if required for SSL authentication"
|
|
104
114
|
option :winrm_transport, type: :string, default: "negotiate",
|
|
105
115
|
desc: "Specify which transport to use, defaults to negotiate (WinRM)."
|
|
106
116
|
option :winrm_disable_sspi, type: :boolean,
|
|
@@ -121,7 +131,7 @@ module Inspec
|
|
|
121
131
|
option :insecure, type: :boolean, default: false,
|
|
122
132
|
desc: "Disable SSL verification on select targets"
|
|
123
133
|
option :target_id, type: :string,
|
|
124
|
-
desc: "Provide a ID which will be included on reports"
|
|
134
|
+
desc: "Provide a ID which will be included on reports - deprecated"
|
|
125
135
|
option :winrm_shell_type, type: :string, default: "powershell",
|
|
126
136
|
desc: "Specify a shell type for winrm (eg. 'elevated' or 'powershell')"
|
|
127
137
|
option :docker_url, type: :string,
|
|
@@ -135,6 +145,8 @@ module Inspec
|
|
|
135
145
|
desc: "Folder which contains referenced profiles."
|
|
136
146
|
option :vendor_cache, type: :string,
|
|
137
147
|
desc: "Use the given path for caching dependencies. (default: ~/.inspec/cache)"
|
|
148
|
+
option :auto_install_gems, type: :boolean, default: false,
|
|
149
|
+
desc: "Auto installs gem dependencies of the profile or resource pack."
|
|
138
150
|
end
|
|
139
151
|
|
|
140
152
|
def self.supermarket_options
|
|
@@ -152,7 +164,7 @@ module Inspec
|
|
|
152
164
|
desc: "A list of tags names that are part of controls to filter and run controls, or a list of /regexes/ to match against tags names of controls. Ignore all other tests."
|
|
153
165
|
option :reporter, type: :array,
|
|
154
166
|
banner: "one two:/output/file/path",
|
|
155
|
-
desc: "Enable one or more output reporters: cli, documentation, html, progress, json, json-min, json-rspec, junit, yaml"
|
|
167
|
+
desc: "Enable one or more output reporters: cli, documentation, html, progress, progress-bar, json, json-min, json-rspec, junit, yaml"
|
|
156
168
|
option :reporter_message_truncation, type: :string,
|
|
157
169
|
desc: "Number of characters to truncate failure messages and code_desc in report data to (default: no truncation)"
|
|
158
170
|
option :reporter_backtrace_inclusion, type: :boolean,
|
data/lib/inspec/cli.rb
CHANGED
|
@@ -95,8 +95,6 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
95
95
|
desc "check PATH", "verify all tests at the specified PATH"
|
|
96
96
|
option :format, type: :string,
|
|
97
97
|
desc: "The output format to use doc (default), json. If valid format is not provided then it will use the default."
|
|
98
|
-
option :with_cookstyle, type: :boolean,
|
|
99
|
-
desc: "Enable or disable cookstyle checks.", default: false
|
|
100
98
|
profile_options
|
|
101
99
|
def check(path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
102
100
|
o = config
|
|
@@ -203,6 +201,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
203
201
|
vendor_deps(path, vendor_options)
|
|
204
202
|
|
|
205
203
|
profile = Inspec::Profile.for_target(path, o)
|
|
204
|
+
gem_deps = profile.metadata.gem_dependencies + \
|
|
205
|
+
profile.locked_dependencies.list.map { |_k, v| v.profile.metadata.gem_dependencies }.flatten
|
|
206
|
+
unless gem_deps.empty?
|
|
207
|
+
o[:logger].warn "Archiving a profile that contains gem dependencies, but InSpec cannot package gems with the profile! Please archive your ~/.inspec/gems directory separately."
|
|
208
|
+
end
|
|
209
|
+
|
|
206
210
|
result = profile.check
|
|
207
211
|
|
|
208
212
|
if result && !o[:ignore_errors] == false
|
|
@@ -298,6 +302,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
298
302
|
def exec(*targets)
|
|
299
303
|
o = config
|
|
300
304
|
diagnose(o)
|
|
305
|
+
deprecate_target_id(config)
|
|
301
306
|
configure_logger(o)
|
|
302
307
|
|
|
303
308
|
runner = Inspec::Runner.new(o)
|
|
@@ -316,6 +321,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
316
321
|
option :format, type: :string
|
|
317
322
|
def detect
|
|
318
323
|
o = config
|
|
324
|
+
deprecate_target_id(config)
|
|
319
325
|
o[:command] = "platform.params"
|
|
320
326
|
|
|
321
327
|
configure_logger(o)
|
|
@@ -356,6 +362,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
356
362
|
desc: "Specify one or more inputs directly on the command line to the shell, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures."
|
|
357
363
|
def shell_func
|
|
358
364
|
o = config
|
|
365
|
+
deprecate_target_id(config)
|
|
359
366
|
diagnose(o)
|
|
360
367
|
o[:debug_shell] = true
|
|
361
368
|
|
|
@@ -443,6 +450,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI
|
|
|
443
450
|
|
|
444
451
|
private
|
|
445
452
|
|
|
453
|
+
def deprecate_target_id(config)
|
|
454
|
+
unless config[:target_id].nil?
|
|
455
|
+
Inspec.deprecate "cli_option_target_id"
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
446
459
|
def run_command(opts)
|
|
447
460
|
runner = Inspec::Runner.new(Inspec::Config.new(opts))
|
|
448
461
|
res = runner.eval_with_virtual_profile(opts[:command])
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# This class will install the gem depedencies for profiles etc.
|
|
2
|
+
# The basic things which is required to install dependencies is the gem path where gem needs to be installed
|
|
3
|
+
# and the list of gems needs to be installed.
|
|
4
|
+
require "rubygems/remote_fetcher"
|
|
5
|
+
require "forwardable" unless defined?(Forwardable)
|
|
6
|
+
|
|
7
|
+
module Inspec
|
|
8
|
+
class DependencyInstaller
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
attr_reader :gem_path, :requested_gems, :dependency_loader
|
|
12
|
+
|
|
13
|
+
def_delegator :dependency_loader, :inspec_gem_path
|
|
14
|
+
|
|
15
|
+
def initialize(gem_path = nil, requested_gems = [])
|
|
16
|
+
@dependency_loader = Inspec::DependencyLoader.new
|
|
17
|
+
@gem_path = gem_path || inspec_gem_path
|
|
18
|
+
@requested_gems = requested_gems
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def install
|
|
22
|
+
requested_gems.each do |requested_gem|
|
|
23
|
+
version = requested_gem[:version].nil? ? "> 0" : requested_gem[:version]
|
|
24
|
+
install_from_remote_gems(requested_gem[:name], { version: version })
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def install_from_remote_gems(requested_gem_name, opts)
|
|
31
|
+
version = opts[:version].split(",")
|
|
32
|
+
begin
|
|
33
|
+
gem_dependency = Gem::Dependency.new(requested_gem_name, version || "> 0")
|
|
34
|
+
|
|
35
|
+
# BestSet is rubygems.org API + indexing, APISet is for custom sources
|
|
36
|
+
sources = if opts[:source]
|
|
37
|
+
Gem::Resolver::APISet.new(URI.join(opts[:source] + "/api/v1/dependencies"))
|
|
38
|
+
else
|
|
39
|
+
Gem::Resolver::BestSet.new
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
install_gem_to_gems_dir(gem_dependency, [sources], opts[:update_mode])
|
|
43
|
+
rescue Gem::RemoteFetcher::FetchError => gem_ex
|
|
44
|
+
ex = Inspec::GemDependencyInstallError.new(gem_ex.message)
|
|
45
|
+
ex.gem_name = requested_gem_name
|
|
46
|
+
raise ex
|
|
47
|
+
rescue Gem::Requirement::BadRequirementError => gem_ex
|
|
48
|
+
ex = Inspec::GemDependencyInstallError.new(gem_ex.message)
|
|
49
|
+
ex.gem_name = requested_gem_name
|
|
50
|
+
raise "Unparseable gem dependency '#{version}' for '#{ex.gem_name}'"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def install_gem_to_gems_dir(gem_dependency, extra_request_sets = [], update_mode = false)
|
|
55
|
+
# Solve the dependency (that is, find a way to install the new gem and anything it needs)
|
|
56
|
+
request_set = Gem::RequestSet.new(gem_dependency)
|
|
57
|
+
|
|
58
|
+
begin
|
|
59
|
+
solution = request_set.resolve
|
|
60
|
+
rescue Gem::UnsatisfiableDependencyError => gem_ex
|
|
61
|
+
ex = Inspec::GemDependencyInstallError.new(gem_ex.message)
|
|
62
|
+
ex.gem_name = gem_dependency.name
|
|
63
|
+
raise ex
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# OK, perform the installation.
|
|
67
|
+
# Ignore deps here, because any needed deps should already be baked into gem_dependency
|
|
68
|
+
request_set.install_into(gem_path, true, ignore_dependencies: true, document: [])
|
|
69
|
+
|
|
70
|
+
# Locate the GemVersion for the new dependency and return it
|
|
71
|
+
solution.detect { |g| g.name == gem_dependency.name }.version
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# This class will load the gem depedencies for profiles etc.
|
|
2
|
+
# The basic things which is required to load gem dependencies is the path from which gems needs to be loaded
|
|
3
|
+
# and the list of gems needs to be loaded.
|
|
4
|
+
|
|
5
|
+
module Inspec
|
|
6
|
+
class DependencyLoader
|
|
7
|
+
attr_accessor :gem_path, :gem_list
|
|
8
|
+
|
|
9
|
+
# initializes the dependency_loader
|
|
10
|
+
def initialize(gem_path = nil, gem_list = [])
|
|
11
|
+
@gem_path = gem_path || inspec_gem_path
|
|
12
|
+
@gem_list = gem_list
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def load
|
|
16
|
+
Gem.path << gem_path
|
|
17
|
+
Gem.refresh
|
|
18
|
+
|
|
19
|
+
gem_list.each do |gem_data|
|
|
20
|
+
version = gem_data[:version].nil? ? "> 0" : gem_data[:version]
|
|
21
|
+
activate_gem_dependency(gem_data[:name], version)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspec_gem_path
|
|
26
|
+
self.class.inspec_gem_path
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.inspec_gem_path
|
|
30
|
+
require "rbconfig" unless defined?(RbConfig)
|
|
31
|
+
ruby_abi_version = RbConfig::CONFIG["ruby_version"]
|
|
32
|
+
# TODO: why are we installing under the api directory for plugins?
|
|
33
|
+
base_dir = Inspec.config_dir
|
|
34
|
+
base_dir = File.realpath base_dir if File.exist? base_dir
|
|
35
|
+
File.join(base_dir, "gems", ruby_abi_version)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Lists all gems found in the inspec_gem_path.
|
|
39
|
+
# @return [Array[Gem::Specification]] Specs of all gems found.
|
|
40
|
+
def list_managed_gems
|
|
41
|
+
Dir.glob(File.join(gem_path, "specifications", "*.gemspec")).map { |p| Gem::Specification.load(p) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def list_installed_gems
|
|
45
|
+
list_managed_gems
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def gem_installed?(name)
|
|
49
|
+
list_installed_gems.any? { |spec| spec.name == name }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def gem_version_installed?(name, version)
|
|
53
|
+
list_installed_gems.any? { |s| s.name == name && Gem::Requirement.new(version.split(",")) =~ s.version }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def activate_gem_dependency(name, version_constraint = "> 0")
|
|
59
|
+
version_constraint = version_constraint.split(",")
|
|
60
|
+
gem_deps = [Gem::Dependency.new(name.to_s, version_constraint)]
|
|
61
|
+
managed_gem_set = Gem::Resolver::VendorSet.new
|
|
62
|
+
|
|
63
|
+
# Note: There is an issue in resolving gem dependency.
|
|
64
|
+
# This block resolves that issue partially.
|
|
65
|
+
# But this will still fail for the gems which don't have the .gemspec file.
|
|
66
|
+
# TODO: Find the solution to resolve gem dependencies that work for the unpackaged gems which don't have the .gemspec file.
|
|
67
|
+
list_managed_gems.each do |spec|
|
|
68
|
+
unless Dir["#{spec.gem_dir}/*.gemspec"].empty?
|
|
69
|
+
managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# TODO: Next two lines merge our managed gems with the other gems available
|
|
74
|
+
# in our "local universe" - which may be the system, or it could be in a Bundler microcosm,
|
|
75
|
+
# or rbenv, etc. Do we want to merge that, though?
|
|
76
|
+
distrib_gem_set = Gem::Resolver::CurrentSet.new
|
|
77
|
+
installed_gem_set = Gem::Resolver.compose_sets(managed_gem_set, distrib_gem_set)
|
|
78
|
+
|
|
79
|
+
# So, given what we need, and what we have available, what activations are needed?
|
|
80
|
+
resolver = Gem::Resolver.new(gem_deps, installed_gem_set)
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
solution = resolver.resolve
|
|
84
|
+
rescue Gem::UnsatisfiableDependencyError => gem_ex
|
|
85
|
+
# If you broke your install, or downgraded to a plugin with a bad gemspec, you could get here.
|
|
86
|
+
ex = Inspec::GemDependencyLoadError.new(gem_ex.message)
|
|
87
|
+
raise ex
|
|
88
|
+
end
|
|
89
|
+
solution.each do |activation_request|
|
|
90
|
+
next if activation_request.full_spec.activated?
|
|
91
|
+
|
|
92
|
+
activation_request.full_spec.activate
|
|
93
|
+
# TODO: If we are under Bundler, inform it that we loaded a gem
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/inspec/dsl.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# copyright: 2015, Dominik Richter
|
|
2
2
|
require "inspec/log"
|
|
3
3
|
require "inspec/plugin/v2"
|
|
4
|
+
require "inspec/utils/deprecated_cloud_resources_list"
|
|
4
5
|
|
|
5
6
|
module Inspec::DSL
|
|
6
7
|
attr_accessor :backend
|
|
@@ -38,8 +39,16 @@ module Inspec::DSL
|
|
|
38
39
|
|
|
39
40
|
begin
|
|
40
41
|
require "inspec/resources/#{id}"
|
|
41
|
-
rescue LoadError
|
|
42
|
-
|
|
42
|
+
rescue LoadError => e
|
|
43
|
+
include DeprecatedCloudResourcesList
|
|
44
|
+
cloud_resource = id.start_with?("aws_") ? "aws" : "azure"
|
|
45
|
+
|
|
46
|
+
# Deprecated AWS and Azure resources in InSpec 5.
|
|
47
|
+
if CLOUD_RESOURCES_DEPRECATED.include? id
|
|
48
|
+
Inspec.deprecate(:"#{cloud_resource}_resources_in_resource_pack", "Resource '#{id}'")
|
|
49
|
+
else
|
|
50
|
+
raise LoadError, "#{e.message}"
|
|
51
|
+
end
|
|
43
52
|
end
|
|
44
53
|
|
|
45
54
|
klass = Inspec::Resource.registry[id.to_s]
|
data/lib/inspec/errors.rb
CHANGED
|
@@ -15,4 +15,11 @@ module Inspec
|
|
|
15
15
|
class ConfigError::Invalid < ConfigError; end
|
|
16
16
|
|
|
17
17
|
class UserInteractionRequired < Error; end
|
|
18
|
+
|
|
19
|
+
class GemDependencyLoadError < Error; end
|
|
20
|
+
|
|
21
|
+
class GemDependencyInstallError < Error
|
|
22
|
+
attr_accessor :gem_name
|
|
23
|
+
attr_accessor :version
|
|
24
|
+
end
|
|
18
25
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "rspec/core"
|
|
2
2
|
require "rspec/core/formatters/base_formatter"
|
|
3
|
+
require "set" unless defined?(Set)
|
|
3
4
|
|
|
4
5
|
module Inspec::Formatters
|
|
5
6
|
class Base < RSpec::Core::Formatters::BaseFormatter
|
|
@@ -14,6 +15,8 @@ module Inspec::Formatters
|
|
|
14
15
|
@profiles = []
|
|
15
16
|
@profiles_info = nil
|
|
16
17
|
@backend = nil
|
|
18
|
+
@all_controls_count = nil
|
|
19
|
+
@control_checks_count_map = {}
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
# RSpec Override: #dump_summary
|
|
@@ -80,6 +83,26 @@ module Inspec::Formatters
|
|
|
80
83
|
@profiles.push(profile)
|
|
81
84
|
end
|
|
82
85
|
|
|
86
|
+
# These control count related methods are called via runner rspec library of inspec
|
|
87
|
+
# And these are used within streaming plugins to determine end of control
|
|
88
|
+
######### Start of control count related methods
|
|
89
|
+
def set_controls_count(controls_count)
|
|
90
|
+
@all_controls_count = controls_count
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def set_control_checks_count_map(mapping)
|
|
94
|
+
@control_checks_count_map = mapping
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def get_controls_count
|
|
98
|
+
@all_controls_count
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def get_control_checks_count_map
|
|
102
|
+
@control_checks_count_map
|
|
103
|
+
end
|
|
104
|
+
######### end of control count related methods
|
|
105
|
+
|
|
83
106
|
# Return all the collected output to the caller
|
|
84
107
|
def results
|
|
85
108
|
run_data
|
data/lib/inspec/metadata.rb
CHANGED
|
@@ -41,6 +41,7 @@ module Inspec
|
|
|
41
41
|
description
|
|
42
42
|
version
|
|
43
43
|
inspec_version
|
|
44
|
+
entitlement_id
|
|
44
45
|
}.each do |name|
|
|
45
46
|
define_method name.to_sym do |arg|
|
|
46
47
|
params[name.to_sym] = arg
|
|
@@ -51,6 +52,10 @@ module Inspec
|
|
|
51
52
|
params[:depends] || []
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
def gem_dependencies
|
|
56
|
+
params[:gem_dependencies] || []
|
|
57
|
+
end
|
|
58
|
+
|
|
54
59
|
def supports(sth, version = nil)
|
|
55
60
|
# Ignore supports with metadata.rb. This file is legacy and the way it
|
|
56
61
|
# it handles `supports` deprecated. A deprecation warning will be printed
|
|
@@ -94,6 +99,10 @@ module Inspec
|
|
|
94
99
|
errors.push("Version needs to be in SemVer format")
|
|
95
100
|
end
|
|
96
101
|
|
|
102
|
+
if params[:entitlement_id] && params[:entitlement_id].strip.empty?
|
|
103
|
+
errors.push("Entitlement ID should not be blank.")
|
|
104
|
+
end
|
|
105
|
+
|
|
97
106
|
unless supports_runtime?
|
|
98
107
|
warnings.push("The current inspec version #{Inspec::VERSION} cannot satisfy profile inspec_version constraint #{params[:inspec_version]}")
|
|
99
108
|
end
|
|
@@ -109,6 +118,33 @@ module Inspec
|
|
|
109
118
|
warnings.push("License '#{params[:license]}' needs to be in SPDX format or marked as 'Proprietary'. See https://spdx.org/licenses/.")
|
|
110
119
|
end
|
|
111
120
|
|
|
121
|
+
# If gem_dependencies is set, it must be an array of hashes with keys name and optional version
|
|
122
|
+
unless params[:gem_dependencies].nil?
|
|
123
|
+
list = params[:gem_dependencies]
|
|
124
|
+
if list.is_a?(Array) && list.all? { |e| e.is_a? Hash }
|
|
125
|
+
list.each do |entry|
|
|
126
|
+
errors.push("gem_dependencies entries must all have a 'name' field") unless entry.key?(:name)
|
|
127
|
+
if entry[:version]
|
|
128
|
+
orig = entry[:version]
|
|
129
|
+
begin
|
|
130
|
+
# Split on commas as we may have a complex dep
|
|
131
|
+
orig.split(",").map { |c| Gem::Requirement.parse(c) }
|
|
132
|
+
rescue Gem::Requirement::BadRequirementError
|
|
133
|
+
errors.push "Unparseable gem dependency '#{orig}' for #{entry[:name]}"
|
|
134
|
+
rescue Inspec::GemDependencyInstallError => e
|
|
135
|
+
errors.push e.message
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
extra = (entry.keys - %i{name version})
|
|
139
|
+
unless extra.empty?
|
|
140
|
+
warnings.push "Unknown gem_dependencies key(s) #{extra.join(",")} seen for entry '#{entry[:name]}'"
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
else
|
|
144
|
+
errors.push("gem_dependencies must be a List of Hashes")
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
112
148
|
[errors, warnings]
|
|
113
149
|
end
|
|
114
150
|
|
|
@@ -1,10 +1,53 @@
|
|
|
1
1
|
module Inspec::Plugin::V2::PluginType
|
|
2
|
-
class StreamingReporter < Inspec::Plugin::V2::PluginBase
|
|
2
|
+
class StreamingReporter < Inspec::Plugin::V2::PluginBase
|
|
3
3
|
register_plugin_type(:streaming_reporter)
|
|
4
4
|
|
|
5
5
|
#====================================================================#
|
|
6
6
|
# StreamingReporter plugin type API
|
|
7
7
|
#====================================================================#
|
|
8
8
|
# Implementation classes must implement these methods.
|
|
9
|
+
|
|
10
|
+
def initialize_streaming_reporter
|
|
11
|
+
@running_controls_list = []
|
|
12
|
+
@control_checks_count_map = {}
|
|
13
|
+
@controls_count = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# method to identify when the control started running
|
|
19
|
+
# this will be useful in executing operations on control's level start
|
|
20
|
+
def control_started?(control_id)
|
|
21
|
+
if @running_controls_list.include? control_id
|
|
22
|
+
false
|
|
23
|
+
else
|
|
24
|
+
@running_controls_list.push(control_id)
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# method to identify when the control ended running
|
|
30
|
+
# this will be useful in executing operations on control's level end
|
|
31
|
+
def control_ended?(control_id)
|
|
32
|
+
set_control_checks_count_map_value
|
|
33
|
+
unless @control_checks_count_map[control_id].nil?
|
|
34
|
+
@control_checks_count_map[control_id] -= 1
|
|
35
|
+
@control_checks_count_map[control_id] == 0
|
|
36
|
+
else
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# method to identify total no. of controls
|
|
42
|
+
def controls_count
|
|
43
|
+
@controls_count ||= RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_controls_count
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# this method is used in the logic of determining end of control
|
|
47
|
+
def set_control_checks_count_map_value
|
|
48
|
+
if @control_checks_count_map.empty?
|
|
49
|
+
@control_checks_count_map = RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_control_checks_count_map
|
|
50
|
+
end
|
|
51
|
+
end
|
|
9
52
|
end
|
|
10
53
|
end
|
data/lib/inspec/profile.rb
CHANGED
|
@@ -13,6 +13,8 @@ require "inspec/dependencies/cache"
|
|
|
13
13
|
require "inspec/dependencies/lockfile"
|
|
14
14
|
require "inspec/dependencies/dependency_set"
|
|
15
15
|
require "inspec/utils/json_profile_summary"
|
|
16
|
+
require "inspec/dependency_loader"
|
|
17
|
+
require "inspec/dependency_installer"
|
|
16
18
|
|
|
17
19
|
module Inspec
|
|
18
20
|
class Profile
|
|
@@ -103,7 +105,6 @@ module Inspec
|
|
|
103
105
|
@check_mode = options[:check_mode] || false
|
|
104
106
|
@parent_profile = options[:parent_profile]
|
|
105
107
|
@legacy_profile_path = options[:profiles_path] || false
|
|
106
|
-
@check_cookstyle = options[:with_cookstyle]
|
|
107
108
|
Metadata.finalize(@source_reader.metadata, @profile_id, options)
|
|
108
109
|
|
|
109
110
|
# if a backend has already been created, clone it so each profile has its own unique backend object
|
|
@@ -379,6 +380,66 @@ module Inspec
|
|
|
379
380
|
@runner_context
|
|
380
381
|
end
|
|
381
382
|
|
|
383
|
+
def collect_gem_dependencies(profile_context)
|
|
384
|
+
gem_dependencies = []
|
|
385
|
+
all_profiles = []
|
|
386
|
+
profile_context.dependencies.list.values.each do |requirement|
|
|
387
|
+
all_profiles << requirement.profile
|
|
388
|
+
end
|
|
389
|
+
all_profiles << self
|
|
390
|
+
all_profiles.each do |profile|
|
|
391
|
+
gem_dependencies << profile.metadata.gem_dependencies unless profile.metadata.gem_dependencies.empty?
|
|
392
|
+
end
|
|
393
|
+
gem_dependencies.flatten.uniq
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# Loads the required gems specified in the Profile's metadata file from default inspec gems path i.e. ~/.inspec/gems
|
|
397
|
+
# else installs and loads them.
|
|
398
|
+
def load_gem_dependencies
|
|
399
|
+
gem_dependencies = collect_gem_dependencies(load_libraries)
|
|
400
|
+
gem_dependencies.each do |gem_data|
|
|
401
|
+
dependency_loader = DependencyLoader.new
|
|
402
|
+
if dependency_loader.gem_version_installed?(gem_data[:name], gem_data[:version]) ||
|
|
403
|
+
dependency_loader.gem_installed?(gem_data[:name])
|
|
404
|
+
load_gem_dependency(gem_data)
|
|
405
|
+
else
|
|
406
|
+
if Inspec::Config.cached[:auto_install_gems]
|
|
407
|
+
install_gem_dependency(gem_data)
|
|
408
|
+
load_gem_dependency(gem_data)
|
|
409
|
+
else
|
|
410
|
+
ui = Inspec::UI.new
|
|
411
|
+
gem_dependencies.each { |gem_dependency| ui.list_item("#{gem_dependency[:name]} #{gem_dependency[:version]}") }
|
|
412
|
+
choice = ui.prompt.select("Would you like to install profile gem dependencies listed above?", %w{Yes No})
|
|
413
|
+
if choice == "Yes"
|
|
414
|
+
Inspec::Config.cached[:auto_install_gems] = true
|
|
415
|
+
load_gem_dependencies
|
|
416
|
+
else
|
|
417
|
+
ui.error "Unable to resolve above listed profile gem dependencies."
|
|
418
|
+
Inspec::UI.new.exit(:gem_dependency_load_error)
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Requires gem_data as argument.
|
|
426
|
+
# gem_dta example: { name: "gem_name", version: "0.0.1"}
|
|
427
|
+
def load_gem_dependency(gem_data)
|
|
428
|
+
dependency_loader = DependencyLoader.new(nil, [gem_data])
|
|
429
|
+
dependency_loader.load
|
|
430
|
+
rescue Inspec::GemDependencyLoadError => e
|
|
431
|
+
raise e.message
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Requires gem_data as argument.
|
|
435
|
+
# gem_dta example: { name: "gem_name", version: "0.0.1"}
|
|
436
|
+
def install_gem_dependency(gem_data)
|
|
437
|
+
gem_dependency = DependencyInstaller.new(nil, [gem_data])
|
|
438
|
+
gem_dependency.install
|
|
439
|
+
rescue Inspec::GemDependencyInstallError => e
|
|
440
|
+
raise e.message
|
|
441
|
+
end
|
|
442
|
+
|
|
382
443
|
def to_s
|
|
383
444
|
"Inspec::Profile<#{name}>"
|
|
384
445
|
end
|
|
@@ -594,13 +655,12 @@ module Inspec
|
|
|
594
655
|
end
|
|
595
656
|
|
|
596
657
|
# Running cookstyle to check for code offenses
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
offense.call(data[0], data[1], data[2], nil, msg)
|
|
602
|
-
end
|
|
658
|
+
cookstyle_linting_check.each do |lint_output|
|
|
659
|
+
data = lint_output.split(":")
|
|
660
|
+
msg = "#{data[-2]}:#{data[-1]}"
|
|
661
|
+
offense.call(data[0], data[1], data[2], nil, msg)
|
|
603
662
|
end
|
|
663
|
+
|
|
604
664
|
# profile is valid if we could not find any error & offenses
|
|
605
665
|
result[:summary][:valid] = result[:errors].empty? && result[:offenses].empty?
|
|
606
666
|
|
|
@@ -776,6 +836,7 @@ module Inspec
|
|
|
776
836
|
end
|
|
777
837
|
|
|
778
838
|
def load_checks_params(params)
|
|
839
|
+
load_gem_dependencies
|
|
779
840
|
load_libraries
|
|
780
841
|
tests = collect_tests
|
|
781
842
|
params[:controls] = controls = {}
|
|
@@ -21,7 +21,7 @@ module Inspec::Reporters
|
|
|
21
21
|
final_report[:type] = "inspec_report"
|
|
22
22
|
|
|
23
23
|
final_report[:end_time] = Time.now.utc.strftime("%FT%TZ")
|
|
24
|
-
final_report[:node_uuid] =
|
|
24
|
+
final_report[:node_uuid] = @config["node_uuid"] || report[:platform][:target_id]
|
|
25
25
|
raise Inspec::ReporterError, "Cannot find a UUID for your node. Please specify one via json-config." if final_report[:node_uuid].nil?
|
|
26
26
|
|
|
27
27
|
final_report[:report_uuid] = @config["report_uuid"] || uuid_from_string(final_report[:end_time] + final_report[:node_uuid])
|