inspec-core 4.52.9 → 4.56.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -11
- data/inspec-core.gemspec +2 -2
- data/lib/inspec/config.rb +5 -1
- data/lib/inspec/dependencies/requirement.rb +2 -1
- data/lib/inspec/formatters/base.rb +8 -6
- data/lib/inspec/library_eval_context.rb +2 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +10 -0
- data/lib/inspec/profile_context.rb +1 -6
- data/lib/inspec/reporters/automate.rb +1 -1
- data/lib/inspec/reporters/json.rb +1 -1
- data/lib/inspec/resources/bash.rb +2 -0
- data/lib/inspec/resources/file.rb +38 -0
- data/lib/inspec/resources/firewalld.rb +83 -9
- data/lib/inspec/resources/grub_conf.rb +1 -1
- data/lib/inspec/resources/iptables.rb +18 -2
- data/lib/inspec/resources/kernel_parameters.rb +58 -0
- data/lib/inspec/resources/mssql_session.rb +11 -3
- data/lib/inspec/resources/package.rb +74 -1
- data/lib/inspec/resources/registry_key.rb +30 -0
- data/lib/inspec/resources/selinux.rb +6 -1
- data/lib/inspec/resources/timezone.rb +65 -0
- data/lib/inspec/resources.rb +2 -0
- data/lib/inspec/runner_rspec.rb +30 -0
- data/lib/inspec/utils/filter.rb +46 -2
- data/lib/inspec/utils/run_data_filters.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb +1 -1
- data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +4 -3
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9930c475b5a1e282ab613db458f60c77561db82d6c009d6c7254f5a3789132f5
|
4
|
+
data.tar.gz: 8a11ae471b5954568be5bf6fc88e52d974a5ac9cb83caf2a6560dd3dd26d55fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0106f09ddcc1077650b6781631188dcb4231829b4e2b737680f49c6736b3c08001523d34a9398eb7499147dde9d22c4bbdd9058721c484424fe69933535e7557
|
7
|
+
data.tar.gz: b04b2c02c6d1009cee30a5ca32521d4c62e62fcf72727d0f720af5fa54da01029dbcd1b25656460f73d9d4cb7f3bf3b94b7e1f049479770a0a4848aa1f25034f
|
data/Gemfile
CHANGED
@@ -11,11 +11,6 @@ gem "inspec-bin", path: "./inspec-bin"
|
|
11
11
|
|
12
12
|
gem "ffi", ">= 1.9.14", "!= 1.13.0", "!= 1.14.2"
|
13
13
|
|
14
|
-
if Gem.ruby_version.to_s.start_with?("2.5")
|
15
|
-
# 16.7.23 required ruby 2.6+
|
16
|
-
gem "chef-utils", "< 16.7.23" # TODO: remove when we drop ruby 2.5
|
17
|
-
end
|
18
|
-
|
19
14
|
# inspec tests depend text output that changed in the 3.10 release
|
20
15
|
# but our runtime dep is still 3.9+
|
21
16
|
gem "rspec", ">= 3.10"
|
@@ -30,11 +25,7 @@ end
|
|
30
25
|
group :test do
|
31
26
|
gem "chefstyle", "~> 2.0.3"
|
32
27
|
gem "concurrent-ruby", "~> 1.0"
|
33
|
-
|
34
|
-
gem "html-proofer", "= 3.19.1" , platforms: :ruby # do not attempt to run proofer on windows
|
35
|
-
else
|
36
|
-
gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
|
37
|
-
end
|
28
|
+
gem "html-proofer", platforms: :ruby # do not attempt to run proofer on windows
|
38
29
|
gem "json_schemer", ">= 0.2.1", "< 0.2.19"
|
39
30
|
gem "m"
|
40
31
|
gem "minitest-sprint", "~> 1.0"
|
@@ -45,7 +36,8 @@ group :test do
|
|
45
36
|
gem "pry", "~> 0.10"
|
46
37
|
gem "rake", ">= 10"
|
47
38
|
gem "ruby-progressbar", "~> 1.8"
|
48
|
-
gem "simplecov", "~> 0.
|
39
|
+
gem "simplecov", "~> 0.21"
|
40
|
+
gem "simplecov_json_formatter"
|
49
41
|
gem "webmock", "~> 3.0"
|
50
42
|
end
|
51
43
|
|
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.6"
|
17
17
|
|
18
18
|
# the gemfile and gemspec are necessary for appbundler so don't remove it
|
19
19
|
spec.files =
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_dependency "thor", ">= 0.20", "< 2.0"
|
29
29
|
spec.add_dependency "method_source", ">= 0.8", "< 2.0"
|
30
30
|
spec.add_dependency "rubyzip", ">= 1.2.2", "< 3.0"
|
31
|
-
spec.add_dependency "rspec", ">= 3.9", "
|
31
|
+
spec.add_dependency "rspec", ">= 3.9", "<= 3.11"
|
32
32
|
spec.add_dependency "rspec-its", "~> 1.2"
|
33
33
|
spec.add_dependency "pry", "~> 0.13"
|
34
34
|
spec.add_dependency "hashie", ">= 3.4", "< 5.0"
|
data/lib/inspec/config.rb
CHANGED
@@ -367,7 +367,11 @@ module Inspec
|
|
367
367
|
.find_activators(plugin_type: :reporter)\
|
368
368
|
.map(&:activator_name).map(&:to_s)
|
369
369
|
|
370
|
-
|
370
|
+
streaming_reporters = Inspec::Plugin::V2::Registry.instance\
|
371
|
+
.find_activators(plugin_type: :streaming_reporter)\
|
372
|
+
.map(&:activator_name).map(&:to_s)
|
373
|
+
|
374
|
+
valid_types = rspec_built_in_formatters + inspec_reporters_that_are_not_yet_plugins + plugin_reporters + streaming_reporters
|
371
375
|
|
372
376
|
reporters.each do |reporter_name, reporter_config|
|
373
377
|
raise NotImplementedError, "'#{reporter_name}' is not a valid reporter type." unless valid_types.include?(reporter_name)
|
@@ -102,7 +102,8 @@ module Inspec
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def fetcher
|
105
|
-
@
|
105
|
+
@runner_options ||= (Inspec::Config.cached || {})
|
106
|
+
@fetcher ||= Inspec::CachedFetcher.new(opts, @cache, @runner_options)
|
106
107
|
end
|
107
108
|
|
108
109
|
# load dependencies of the dependency
|
@@ -70,6 +70,7 @@ module Inspec::Formatters
|
|
70
70
|
name: platform(:name),
|
71
71
|
release: platform(:release),
|
72
72
|
target: backend_target,
|
73
|
+
target_id: platform(:uuid),
|
73
74
|
}
|
74
75
|
end
|
75
76
|
|
@@ -205,12 +206,13 @@ module Inspec::Formatters
|
|
205
206
|
def platform(field)
|
206
207
|
return nil if @backend.nil?
|
207
208
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
209
|
+
@backend.platform[field]
|
210
|
+
rescue Train::PlatformUuidDetectionFailed
|
211
|
+
Inspec::Log.warn("Could not find platform target_id.")
|
212
|
+
nil
|
213
|
+
rescue Train::Error => e
|
214
|
+
Inspec::Log.warn(e.message)
|
215
|
+
nil
|
214
216
|
end
|
215
217
|
|
216
218
|
def backend_target
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Inspec::Plugin::V2::PluginType
|
2
|
+
class StreamingReporter < Inspec::Plugin::V2::PluginBase # TBD Superclass may need to change
|
3
|
+
register_plugin_type(:streaming_reporter)
|
4
|
+
|
5
|
+
#====================================================================#
|
6
|
+
# StreamingReporter plugin type API
|
7
|
+
#====================================================================#
|
8
|
+
# Implementation classes must implement these methods.
|
9
|
+
end
|
10
|
+
end
|
@@ -68,6 +68,7 @@ module Inspec
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def reload_dsl
|
71
|
+
@resource_registry.merge!(Inspec::Resource.new_registry)
|
71
72
|
@control_eval_context = nil
|
72
73
|
end
|
73
74
|
|
@@ -263,9 +264,3 @@ module Inspec
|
|
263
264
|
end # DomainSpecificLunacy
|
264
265
|
end # ProfileContext
|
265
266
|
end
|
266
|
-
|
267
|
-
if RUBY_VERSION < "2.5"
|
268
|
-
class Module
|
269
|
-
public :define_method
|
270
|
-
end
|
271
|
-
end
|
@@ -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] = @config["node_uuid"] || @config["target_id"]
|
24
|
+
final_report[:node_uuid] = report[:platform][:target_id] || @config["node_uuid"] || @config["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])
|
@@ -61,6 +61,24 @@ module Inspec::Resources
|
|
61
61
|
res.force_encoding("utf-8")
|
62
62
|
end
|
63
63
|
|
64
|
+
# returns hash containing list of users/groups and their file permissions.
|
65
|
+
def user_permissions
|
66
|
+
return {} unless exist?
|
67
|
+
|
68
|
+
return skip_reource"`user_permissions` is not supported on your OS yet." unless inspec.os.windows?
|
69
|
+
|
70
|
+
@perms_provider.user_permissions(file)
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns true if inheritance is enabled on file or folder
|
74
|
+
def inherited?
|
75
|
+
return false unless exist?
|
76
|
+
|
77
|
+
return skip_resource "`inherited?` is not supported on your OS yet." unless inspec.os.windows?
|
78
|
+
|
79
|
+
@perms_provider.inherited?(file)
|
80
|
+
end
|
81
|
+
|
64
82
|
def contain(*_)
|
65
83
|
raise "Contain is not supported. Please use standard RSpec matchers."
|
66
84
|
end
|
@@ -244,6 +262,26 @@ module Inspec::Resources
|
|
244
262
|
end
|
245
263
|
|
246
264
|
class WindowsFilePermissions < FilePermissions
|
265
|
+
|
266
|
+
def user_permissions(file)
|
267
|
+
script = <<-EOH
|
268
|
+
$Acl = Get-Acl -Path #{file.path}
|
269
|
+
$Result = foreach ($Access in $acl.Access) {
|
270
|
+
[PSCustomObject]@{
|
271
|
+
$Access.IdentityReference.Value = $Access.FileSystemRights.ToString()
|
272
|
+
}
|
273
|
+
}
|
274
|
+
$Result | ConvertTo-Json
|
275
|
+
EOH
|
276
|
+
result = inspec.powershell(script)
|
277
|
+
JSON.load(result.stdout).inject(&:merge) unless result.stdout.empty?
|
278
|
+
end
|
279
|
+
|
280
|
+
def inherited?(file)
|
281
|
+
cmd = inspec.command("(Get-Acl -Path #{file.path}).access| Where-Object {$_.IsInherited -eq $true} | measure | % { $_.Count }")
|
282
|
+
cmd.stdout.chomp == "0" ? false : true
|
283
|
+
end
|
284
|
+
|
247
285
|
def check_file_permission_by_mask(_file, _access_type, _usergroup, _specific_user)
|
248
286
|
raise "`check_file_permission_by_mask` is not supported on Windows"
|
249
287
|
end
|
@@ -32,6 +32,17 @@ module Inspec::Resources
|
|
32
32
|
.register_column(:interfaces, field: "interfaces")
|
33
33
|
.register_column(:sources, field: "sources")
|
34
34
|
.register_column(:services, field: "services")
|
35
|
+
.register_column(:target, field: "target")
|
36
|
+
.register_column(:ports, field: "ports")
|
37
|
+
.register_column(:protocols, field: "protocols")
|
38
|
+
.register_column(:forward_ports, field: "forward_ports")
|
39
|
+
.register_column(:source_ports, field: "source_ports")
|
40
|
+
.register_column(:icmp_blocks, field: "icmp_blocks")
|
41
|
+
.register_column(:rich_rules, field: "rich_rules")
|
42
|
+
.register_custom_matcher(:icmp_block_inversion?) { |x| x.params[0]["icmp_block_inversion"] }
|
43
|
+
.register_custom_matcher(:has_icmp_block_inversion_enabled?) { |x| x.params[0]["icmp_block_inversion"] }
|
44
|
+
.register_custom_matcher(:masquerade?) { |x| x.params[0]["masquerade"] }
|
45
|
+
.register_custom_matcher(:has_masquerade_enabled?) { |x| x.params[0]["masquerade"] }
|
35
46
|
|
36
47
|
filter.install_filter_methods_on_resource(self, :params)
|
37
48
|
|
@@ -64,28 +75,28 @@ module Inspec::Resources
|
|
64
75
|
end
|
65
76
|
|
66
77
|
def has_service_enabled_in_zone?(query_service, query_zone = default_zone)
|
67
|
-
firewalld_command("--zone=#{query_zone} --query-service=#{query_service}") == "yes"
|
78
|
+
firewalld_command("--permanent --zone=#{query_zone} --query-service=#{query_service}") == "yes"
|
68
79
|
end
|
69
80
|
|
70
81
|
def service_ports_enabled_in_zone(query_service, query_zone = default_zone)
|
71
82
|
# return: String of ports open
|
72
83
|
# example: ['22/tcp', '4722/tcp']
|
73
|
-
firewalld_command("--zone=#{query_zone} --service=#{query_service} --get-ports
|
84
|
+
firewalld_command("--permanent --zone=#{query_zone} --service=#{query_service} --get-ports").split(" ")
|
74
85
|
end
|
75
86
|
|
76
87
|
def service_protocols_enabled_in_zone(query_service, query_zone = default_zone)
|
77
|
-
# return: String of
|
88
|
+
# return: String of protocols open
|
78
89
|
# example: ['icmp', 'ipv4', 'igmp']
|
79
|
-
firewalld_command("--zone=#{query_zone} --service=#{query_service} --get-protocols
|
90
|
+
firewalld_command("--permanent --zone=#{query_zone} --service=#{query_service} --get-protocols").split(" ")
|
80
91
|
end
|
81
92
|
|
82
93
|
def has_port_enabled_in_zone?(query_port, query_zone = default_zone)
|
83
|
-
firewalld_command("--zone=#{query_zone} --query-port=#{query_port}") == "yes"
|
94
|
+
firewalld_command("--permanent --zone=#{query_zone} --query-port=#{query_port}") == "yes"
|
84
95
|
end
|
85
96
|
|
86
97
|
def has_rule_enabled?(rule, query_zone = default_zone)
|
87
98
|
rule = "rule #{rule}" unless rule.start_with?("rule")
|
88
|
-
firewalld_command("--zone=#{query_zone} --query-rich-rule='#{rule}'") == "yes"
|
99
|
+
firewalld_command("--permanent --zone=#{query_zone} --query-rich-rule='#{rule}'") == "yes"
|
89
100
|
end
|
90
101
|
|
91
102
|
def to_s
|
@@ -120,19 +131,82 @@ module Inspec::Resources
|
|
120
131
|
"interfaces" => line.split(":")[1].split(" "),
|
121
132
|
"services" => services_bound(zone),
|
122
133
|
"sources" => sources_bound(zone),
|
134
|
+
"target" => target_bound(zone),
|
135
|
+
"icmp_block_inversion" => icmp_block_inversion_bound?(zone),
|
136
|
+
"ports" => ports_bound(zone),
|
137
|
+
"protocols" => protocols_bound(zone),
|
138
|
+
"masquerade" => masquerade_bound?(zone),
|
139
|
+
"forward_ports" => forward_ports_bound(zone),
|
140
|
+
"source_ports" => source_ports_bound(zone),
|
141
|
+
"icmp_blocks" => icmp_blocks_bound(zone),
|
142
|
+
"rich_rules" => rich_rules_bound(zone),
|
123
143
|
}
|
124
144
|
end
|
125
145
|
|
146
|
+
def target_bound(query_zone)
|
147
|
+
# result: a target bound for the zone
|
148
|
+
# example: 'DROP'
|
149
|
+
firewalld_command("--permanent --zone=#{query_zone} --get-target").strip
|
150
|
+
end
|
151
|
+
|
152
|
+
def icmp_block_inversion_bound?(query_zone)
|
153
|
+
# result: true/false whether inversion of icmp blocks has been enabled for a zone
|
154
|
+
# example: true
|
155
|
+
firewalld_command("--permanent --zone=#{query_zone} --query-icmp-block-inversion") == "yes"
|
156
|
+
end
|
157
|
+
|
158
|
+
def ports_bound(query_zone)
|
159
|
+
# result: a list of ports bound for a zone
|
160
|
+
# example: ['80/tcp', '443/tcp']
|
161
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-ports").split(" ")
|
162
|
+
end
|
163
|
+
|
164
|
+
def protocols_bound(query_zone)
|
165
|
+
# result: a list of protocols added for a zone
|
166
|
+
# example: ['icmp', 'ipv4', 'igmp']
|
167
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-protocols").split(" ")
|
168
|
+
end
|
169
|
+
|
170
|
+
def masquerade_bound?(query_zone)
|
171
|
+
# result: true/false whether IPv4 masquerading has been enabled for a zone
|
172
|
+
# example: true
|
173
|
+
firewalld_command("--permanent --zone=#{query_zone} --query-masquerade") == "yes"
|
174
|
+
end
|
175
|
+
|
176
|
+
def forward_ports_bound(query_zone)
|
177
|
+
# result: a list of IPv4 forward ports bound to a zone
|
178
|
+
# example: ['port=80:proto=tcp:toport=88', 'port=12345:proto=tcp:toport=54321:toaddr=192.168.1.3']
|
179
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-forward-ports").split("\n")
|
180
|
+
end
|
181
|
+
|
182
|
+
def source_ports_bound(query_zone)
|
183
|
+
# result: a list of source ports bound to a zone
|
184
|
+
# example: ['80/tcp', '8080/tcp']
|
185
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-source-ports").split(" ")
|
186
|
+
end
|
187
|
+
|
188
|
+
def icmp_blocks_bound(query_zone)
|
189
|
+
# result: a list of internet ICMP type blocks bound to a zone
|
190
|
+
# example: ['echo-request', 'echo-reply']
|
191
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-icmp-blocks").split(" ")
|
192
|
+
end
|
193
|
+
|
194
|
+
def rich_rules_bound(query_zone)
|
195
|
+
# result: a list of rich language rules bound to a zone
|
196
|
+
# example: ['rule protocol value="ah" accept', 'rule service name="ftp" log limit value="1/m" audit accept']
|
197
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-rich-rules").split("\n")
|
198
|
+
end
|
199
|
+
|
126
200
|
def sources_bound(query_zone)
|
127
201
|
# result: a list containing either an ip address or ip address with a mask, or a ipset or an ipset with the ipset prefix.
|
128
202
|
# example: ['192.168.0.4', '192.168.0.0/16', '2111:DB28:ABC:12::', '2111:db89:ab3d:0112::0/64']
|
129
|
-
firewalld_command("--zone=#{query_zone} --list-sources").split(" ")
|
203
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-sources").split(" ")
|
130
204
|
end
|
131
205
|
|
132
206
|
def services_bound(query_zone)
|
133
207
|
# result: a list of services bound to a zone.
|
134
208
|
# example: ['ssh', 'dhcpv6-client']
|
135
|
-
firewalld_command("--zone=#{query_zone} --list-services").split(" ")
|
209
|
+
firewalld_command("--permanent --zone=#{query_zone} --list-services").split(" ")
|
136
210
|
end
|
137
211
|
|
138
212
|
def firewalld_command(command)
|
@@ -145,4 +219,4 @@ module Inspec::Resources
|
|
145
219
|
result.stdout.strip
|
146
220
|
end
|
147
221
|
end
|
148
|
-
end
|
222
|
+
end
|
@@ -162,7 +162,7 @@ module Inspec::Resources
|
|
162
162
|
|
163
163
|
current_kernel = file_line.split(" ", 2)[1]
|
164
164
|
lines.drop(index + 1).each do |kernel_line|
|
165
|
-
if kernel_line =~
|
165
|
+
if kernel_line =~ /(?:^\s*\w+)/ && !(kernel_line =~ /^title.*/)
|
166
166
|
option_type = kernel_line.split(" ")[0]
|
167
167
|
line_options = kernel_line.split(" ").drop(1)
|
168
168
|
if (menu_entry == conf["default"].to_i && @kernel == "default") || current_kernel == @kernel
|
@@ -33,6 +33,7 @@ module Inspec::Resources
|
|
33
33
|
def initialize(params = {})
|
34
34
|
@table = params[:table]
|
35
35
|
@chain = params[:chain]
|
36
|
+
@ignore_comments = params[:ignore_comments] || false
|
36
37
|
|
37
38
|
# we're done if we are on linux
|
38
39
|
return if inspec.os.linux?
|
@@ -59,8 +60,13 @@ module Inspec::Resources
|
|
59
60
|
cmd = inspec.command(iptables_cmd)
|
60
61
|
return [] if cmd.exit_status.to_i != 0
|
61
62
|
|
62
|
-
|
63
|
-
|
63
|
+
if @ignore_comments
|
64
|
+
# split rules, returns array or rules without any comment
|
65
|
+
@iptables_cache = remove_comments_from_rules(cmd.stdout.split("\n"))
|
66
|
+
else
|
67
|
+
# split rules, returns array or rules
|
68
|
+
@iptables_cache = cmd.stdout.split("\n").map(&:strip)
|
69
|
+
end
|
64
70
|
end
|
65
71
|
|
66
72
|
def to_s
|
@@ -69,6 +75,16 @@ module Inspec::Resources
|
|
69
75
|
|
70
76
|
private
|
71
77
|
|
78
|
+
def remove_comments_from_rules(rules)
|
79
|
+
rules.each do |rule|
|
80
|
+
next if rule.nil?
|
81
|
+
|
82
|
+
rule.gsub!(/ -m comment --comment "([^"]*)"/, "")
|
83
|
+
rule.strip
|
84
|
+
end
|
85
|
+
rules
|
86
|
+
end
|
87
|
+
|
72
88
|
def find_iptables_or_error
|
73
89
|
%w{/usr/sbin/iptables /sbin/iptables iptables}.each do |cmd|
|
74
90
|
return cmd if inspec.command(cmd).exist?
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Inspec::Resources
|
2
|
+
class KernelParameters < Inspec.resource(1)
|
3
|
+
name "kernel_parameters"
|
4
|
+
supports platform: "unix"
|
5
|
+
desc "Use the kernel_parameters InSpec audit resource to test kernel parameters on Linux platforms."
|
6
|
+
example <<~EXAMPLE
|
7
|
+
describe kernel_parameters.where(parameter: /^net./ ) do
|
8
|
+
its('parameters') { should include 'net.ipv4.conf.all.forwarding' }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe kernel_parameters.where(parameter: "net.ipv4.conf.all.forwarding") do
|
12
|
+
its('values') { should eq [0] }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe kernel_parameters do
|
16
|
+
its('parameters') { should include 'net.ipv4.conf.all.forwarding' }
|
17
|
+
its('values') { should include 0 }
|
18
|
+
end
|
19
|
+
EXAMPLE
|
20
|
+
|
21
|
+
filter = FilterTable.create
|
22
|
+
filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
|
23
|
+
filter.register_column(:parameters, field: "parameter")
|
24
|
+
.register_column(:values, field: "value")
|
25
|
+
filter.install_filter_methods_on_resource(self, :params)
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
# this resource is only supported on Linux
|
29
|
+
return skip_resource "The `kernel_parameters` resource is not supported on your OS." unless inspec.os.linux?
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"Kernel Parameters"
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def params
|
39
|
+
cmd = inspec.command("/sbin/sysctl -a")
|
40
|
+
cmd.exit_status != 0 ? [] : parse_kernel_paramater(cmd.stdout)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_kernel_paramater(stdout)
|
44
|
+
result = []
|
45
|
+
stdout.split("\n").each do |out|
|
46
|
+
splitted_output = out.split("=").map(&:strip)
|
47
|
+
result.push(
|
48
|
+
{
|
49
|
+
"parameter" => splitted_output[0],
|
50
|
+
"value" => splitted_output[1].to_i,
|
51
|
+
}
|
52
|
+
)
|
53
|
+
end
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -76,7 +76,7 @@ module Inspec::Resources
|
|
76
76
|
if cmd.exit_status != 0 || out =~ /Sqlcmd: Error/
|
77
77
|
raise Inspec::Exceptions::ResourceFailed, "Could not execute the sql query #{out}"
|
78
78
|
else
|
79
|
-
DatabaseHelper::SQLQueryResult.new(cmd, parse_csv_result(cmd))
|
79
|
+
DatabaseHelper::SQLQueryResult.new(cmd, parse_csv_result(cmd.stdout))
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -94,9 +94,17 @@ module Inspec::Resources
|
|
94
94
|
!query("select getdate()").empty?
|
95
95
|
end
|
96
96
|
|
97
|
-
def parse_csv_result(
|
97
|
+
def parse_csv_result(stdout)
|
98
98
|
require "csv" unless defined?(CSV)
|
99
|
-
|
99
|
+
|
100
|
+
# replaces \n with \r since multiline data in older versions of database returns faulty
|
101
|
+
# formatted multiline data, example name\r\n----\r\nThis is\na multiline field\r\n
|
102
|
+
out = stdout.gsub("\n", "\r")
|
103
|
+
out = out.gsub("\r\r", "\r")
|
104
|
+
|
105
|
+
# row separator used since row delimiters \n (in linux) or \r\n (in windows)
|
106
|
+
# are converted to \r for consistency and handling faulty formatted multiline data
|
107
|
+
table = CSV.parse(out, headers: true, row_sep: "\r")
|
100
108
|
|
101
109
|
# remove first row, since it will be a seperator line
|
102
110
|
table.delete(0)
|
@@ -26,6 +26,7 @@ module Inspec::Resources
|
|
26
26
|
@cache = nil
|
27
27
|
# select package manager
|
28
28
|
@pkgman = nil
|
29
|
+
@latest_version = nil
|
29
30
|
|
30
31
|
os = inspec.os
|
31
32
|
if os.debian?
|
@@ -60,6 +61,15 @@ module Inspec::Resources
|
|
60
61
|
info[:installed] == true
|
61
62
|
end
|
62
63
|
|
64
|
+
def latest?(_provider = nil, _version = nil)
|
65
|
+
os = inspec.os
|
66
|
+
if os.solaris? || (%w{hpux aix}.include? os[:family])
|
67
|
+
raise Inspec::Exceptions::ResourceSkipped, "The `be_latest` matcher is not supported on your OS yet."
|
68
|
+
end
|
69
|
+
|
70
|
+
(!info[:only_version_no].nil? && !latest_version.nil?) && (info[:only_version_no] == latest_version)
|
71
|
+
end
|
72
|
+
|
63
73
|
# returns true it the package is held (if the OS supports it)
|
64
74
|
def held?(_provider = nil, _version = nil)
|
65
75
|
info[:held] == true
|
@@ -82,6 +92,10 @@ module Inspec::Resources
|
|
82
92
|
info[:version]
|
83
93
|
end
|
84
94
|
|
95
|
+
def latest_version
|
96
|
+
@latest_version ||= ( @pkgman.latest_version(@package_name) || info[:latest_version] )
|
97
|
+
end
|
98
|
+
|
85
99
|
def to_s
|
86
100
|
"System Package #{@package_name}"
|
87
101
|
end
|
@@ -107,6 +121,21 @@ module Inspec::Resources
|
|
107
121
|
# combined into a `ResourceSkipped` exception message.
|
108
122
|
[]
|
109
123
|
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def fetch_latest_version(cmd_string)
|
128
|
+
cmd = inspec.command(cmd_string)
|
129
|
+
if cmd.exit_status != 0
|
130
|
+
raise Inspec::Exceptions::ResourceFailed, "Failed to fetch latest version. Error: #{cmd.stderr}"
|
131
|
+
else
|
132
|
+
fetch_version_no(cmd.stdout)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def fetch_version_no(output)
|
137
|
+
output.scan(/(?:(?:\d+)[.]){2,}(?:\d+)/).max_by { |s| Gem::Version.new(s) } unless output.nil?
|
138
|
+
end
|
110
139
|
end
|
111
140
|
|
112
141
|
# Debian / Ubuntu
|
@@ -124,14 +153,21 @@ module Inspec::Resources
|
|
124
153
|
# If the package is installed and marked hold, Status is "hold ok installed"
|
125
154
|
# If the package is removed and not purged, Status is "deinstall ok config-files" with exit_status 0
|
126
155
|
# If the package is purged cmd fails with non-zero exit status
|
156
|
+
|
127
157
|
{
|
128
158
|
name: params["Package"],
|
129
159
|
installed: params["Status"].split(" ")[2] == "installed",
|
130
160
|
held: params["Status"].split(" ")[0] == "hold",
|
131
161
|
version: params["Version"],
|
132
162
|
type: "deb",
|
163
|
+
only_version_no: fetch_version_no(params["Version"]),
|
133
164
|
}
|
134
165
|
end
|
166
|
+
|
167
|
+
def latest_version(package_name)
|
168
|
+
cmd_string = "apt list #{package_name} -a"
|
169
|
+
fetch_latest_version(cmd_string)
|
170
|
+
end
|
135
171
|
end
|
136
172
|
|
137
173
|
# RHEL family
|
@@ -181,9 +217,15 @@ module Inspec::Resources
|
|
181
217
|
installed: true,
|
182
218
|
version: "#{v}-#{r}",
|
183
219
|
type: "rpm",
|
220
|
+
only_version_no: "#{v}",
|
184
221
|
}
|
185
222
|
end
|
186
223
|
|
224
|
+
def latest_version(package_name)
|
225
|
+
cmd_string = "yum list #{package_name}"
|
226
|
+
fetch_latest_version(cmd_string)
|
227
|
+
end
|
228
|
+
|
187
229
|
private
|
188
230
|
|
189
231
|
def rpm_command(package_name)
|
@@ -216,11 +258,17 @@ module Inspec::Resources
|
|
216
258
|
installed: true,
|
217
259
|
version: pkg["installed"][0]["version"],
|
218
260
|
type: "brew",
|
261
|
+
latest_version: pkg["versions"]["stable"],
|
262
|
+
only_version_no: pkg["installed"][0]["version"],
|
219
263
|
}
|
220
264
|
rescue JSON::ParserError => e
|
221
265
|
raise Inspec::Exceptions::ResourceFailed,
|
222
266
|
"Failed to parse JSON from `brew` command. Error: #{e}"
|
223
267
|
end
|
268
|
+
|
269
|
+
def latest_version(package_name)
|
270
|
+
nil
|
271
|
+
end
|
224
272
|
end
|
225
273
|
|
226
274
|
# Arch Linux
|
@@ -240,8 +288,14 @@ module Inspec::Resources
|
|
240
288
|
installed: true,
|
241
289
|
version: params["Version"],
|
242
290
|
type: "pacman",
|
291
|
+
only_version_no: fetch_version_no(params["Version"]),
|
243
292
|
}
|
244
293
|
end
|
294
|
+
|
295
|
+
def latest_version(package_name)
|
296
|
+
cmd_string = "pacman -Ss #{package_name} | grep #{package_name} | grep installed"
|
297
|
+
fetch_latest_version(cmd_string)
|
298
|
+
end
|
245
299
|
end
|
246
300
|
|
247
301
|
class HpuxPkg < PkgManagement
|
@@ -267,13 +321,20 @@ module Inspec::Resources
|
|
267
321
|
pkg_info = cmd.stdout.split("\n").delete_if { |e| e =~ /^WARNING/i }
|
268
322
|
pkg = pkg_info[0].split(" - ")[0]
|
269
323
|
|
324
|
+
version = pkg.partition("-")[2]
|
270
325
|
{
|
271
326
|
name: pkg.partition("-")[0],
|
272
327
|
installed: true,
|
273
|
-
version:
|
328
|
+
version: version,
|
274
329
|
type: "pkg",
|
330
|
+
only_version_no: fetch_version_no(version),
|
275
331
|
}
|
276
332
|
end
|
333
|
+
|
334
|
+
def latest_version(package_name)
|
335
|
+
cmd_string = "apk info #{package_name}"
|
336
|
+
fetch_latest_version(cmd_string)
|
337
|
+
end
|
277
338
|
end
|
278
339
|
|
279
340
|
class FreebsdPkg < PkgManagement
|
@@ -292,8 +353,14 @@ module Inspec::Resources
|
|
292
353
|
installed: true,
|
293
354
|
version: params["Version"],
|
294
355
|
type: "pkg",
|
356
|
+
only_version_no: params["Version"],
|
295
357
|
}
|
296
358
|
end
|
359
|
+
|
360
|
+
def latest_version(package_name)
|
361
|
+
cmd_string = "pkg version -v | grep #{package_name}"
|
362
|
+
fetch_latest_version(cmd_string)
|
363
|
+
end
|
297
364
|
end
|
298
365
|
|
299
366
|
# Determines the installed packages on Windows using the Windows package registry entries.
|
@@ -339,8 +406,14 @@ module Inspec::Resources
|
|
339
406
|
installed: true,
|
340
407
|
version: package["DisplayVersion"],
|
341
408
|
type: "windows",
|
409
|
+
only_version_no: package["DisplayVersion"],
|
342
410
|
}
|
343
411
|
end
|
412
|
+
|
413
|
+
def latest_version(package_name)
|
414
|
+
cmd_string = "Get-Package #{package_name} -AllVersions"
|
415
|
+
fetch_latest_version(cmd_string)
|
416
|
+
end
|
344
417
|
end
|
345
418
|
|
346
419
|
# AIX
|
@@ -105,6 +105,21 @@ module Inspec::Resources
|
|
105
105
|
children_keys(@options[:path], filter)
|
106
106
|
end
|
107
107
|
|
108
|
+
# returns hash containing users / groups and their permission
|
109
|
+
def user_permissions
|
110
|
+
return {} unless exists?
|
111
|
+
|
112
|
+
get_permissions(@options[:path])
|
113
|
+
end
|
114
|
+
|
115
|
+
# returns true if inheritance is enabled for registry key.
|
116
|
+
def inherited?
|
117
|
+
return false unless exists?
|
118
|
+
|
119
|
+
cmd = inspec.command("(Get-Acl -Path 'Registry::#{@options[:path]}').access| Where-Object {$_.IsInherited -eq $true} | measure | % { $_.Count }")
|
120
|
+
cmd.stdout.chomp == "0" ? false : true
|
121
|
+
end
|
122
|
+
|
108
123
|
# returns nil, if not existent or value
|
109
124
|
def method_missing(*keys)
|
110
125
|
# allow the use of array syntax in an `its` block so that users
|
@@ -283,6 +298,21 @@ module Inspec::Resources
|
|
283
298
|
|
284
299
|
key.start_with?("\\") ? key : "\\#{key}"
|
285
300
|
end
|
301
|
+
|
302
|
+
def get_permissions(path)
|
303
|
+
script = <<~EOH
|
304
|
+
$path = '#{path}'
|
305
|
+
$Acl = Get-Acl -Path ('Registry::' + $path)
|
306
|
+
$Result = foreach ($Access in $acl.Access) {
|
307
|
+
[PSCustomObject]@{
|
308
|
+
$Access.IdentityReference = $Access.RegistryRights.ToString()
|
309
|
+
}
|
310
|
+
}
|
311
|
+
$Result | ConvertTo-Json
|
312
|
+
EOH
|
313
|
+
result = inspec.powershell(script)
|
314
|
+
JSON.load(result.stdout).inject(&:merge) unless result.stdout.empty?
|
315
|
+
end
|
286
316
|
end
|
287
317
|
|
288
318
|
class WindowsRegistryKey < RegistryKey
|
@@ -84,8 +84,13 @@ module Inspec::Resources
|
|
84
84
|
|
85
85
|
def initialize(selinux_path = "/etc/selinux/config")
|
86
86
|
@path = selinux_path
|
87
|
-
|
87
|
+
if inspec.os.redhat? && inspec.os.name == "amazon"
|
88
|
+
lcmd = "/usr/sbin/sestatus"
|
89
|
+
else
|
90
|
+
lcmd = "sestatus"
|
91
|
+
end
|
88
92
|
|
93
|
+
cmd = inspec.command(lcmd)
|
89
94
|
if cmd.exit_status != 0
|
90
95
|
# `sestatus` command not found error message comes in stdout so handling both here
|
91
96
|
out = cmd.stdout + "\n" + cmd.stderr
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
|
3
|
+
module Inspec::Resources
|
4
|
+
class TimeZone < Cmd
|
5
|
+
name "timezone"
|
6
|
+
supports platform: "unix"
|
7
|
+
supports platform: "windows"
|
8
|
+
|
9
|
+
desc "Check for timezone configurations"
|
10
|
+
example <<~EXAMPLE
|
11
|
+
describe timezone do
|
12
|
+
its('identifier') { should eq 'Asia/Kolkata' }
|
13
|
+
its('name') { should eq 'IST' }
|
14
|
+
its('time_offset') { should eq '+0530' }
|
15
|
+
end
|
16
|
+
EXAMPLE
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@output = {}
|
20
|
+
os = inspec.os
|
21
|
+
cmd = if os.windows?
|
22
|
+
inspec.command("Get-TimeZone")
|
23
|
+
else
|
24
|
+
inspec.command("timedatectl status | grep -i 'Time zone'")
|
25
|
+
end
|
26
|
+
if cmd.exit_status != 0
|
27
|
+
raise Inspec::Exceptions::ResourceFailed, "Time Zone resource with error: #{cmd.stderr}"
|
28
|
+
else
|
29
|
+
if os.windows?
|
30
|
+
splitted_output = cmd.stdout.strip.gsub(/\r/, "").split("\n").select { |out| (out.include? "Id") || (out.include? "DisplayName") || (out.include? "BaseUtcOffset") }
|
31
|
+
@output["identifier"] = split_and_fetch_last(splitted_output[1])
|
32
|
+
@output["name"] = split_and_fetch_last(splitted_output[0])
|
33
|
+
@output["time_offset"] = split_and_fetch_last(splitted_output[2])
|
34
|
+
else
|
35
|
+
splitted_output = cmd.stdout.split(":")[-1]&.strip&.gsub(/[(),^]*/, "")&.split(" ") || []
|
36
|
+
@output["identifier"] = splitted_output[0]
|
37
|
+
@output["name"] = splitted_output[1]
|
38
|
+
@output["time_offset"] = splitted_output[2]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def identifier
|
44
|
+
@output["identifier"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def name
|
48
|
+
@output["name"]
|
49
|
+
end
|
50
|
+
|
51
|
+
def time_offset
|
52
|
+
@output["time_offset"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
"Time Zone resource"
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def split_and_fetch_last(string_value)
|
62
|
+
string_value.split(" :")[-1].strip
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/inspec/resources.rb
CHANGED
@@ -41,6 +41,7 @@ require "inspec/resources/cassandradb_session"
|
|
41
41
|
require "inspec/resources/cassandradb_conf"
|
42
42
|
require "inspec/resources/cassandra"
|
43
43
|
require "inspec/resources/crontab"
|
44
|
+
require "inspec/resources/timezone"
|
44
45
|
require "inspec/resources/dh_params"
|
45
46
|
require "inspec/resources/directory"
|
46
47
|
require "inspec/resources/docker"
|
@@ -72,6 +73,7 @@ require "inspec/resources/ip6tables"
|
|
72
73
|
require "inspec/resources/iptables"
|
73
74
|
require "inspec/resources/kernel_module"
|
74
75
|
require "inspec/resources/kernel_parameter"
|
76
|
+
require "inspec/resources/kernel_parameters"
|
75
77
|
require "inspec/resources/key_rsa"
|
76
78
|
require "inspec/resources/ksh"
|
77
79
|
require "inspec/resources/limits_conf"
|
data/lib/inspec/runner_rspec.rb
CHANGED
@@ -123,6 +123,8 @@ module Inspec
|
|
123
123
|
def set_optional_formatters
|
124
124
|
return if @conf["reporter"].nil?
|
125
125
|
|
126
|
+
# This is a slightly modified version of the default RSpec JSON formatter
|
127
|
+
# No one in their right mind should be using this because we have a much better JSON reporter - named "json"
|
126
128
|
if @conf["reporter"].key?("json-rspec")
|
127
129
|
# We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
|
128
130
|
if @conf["reporter"]["json-rspec"]&.[]("file").nil?
|
@@ -133,6 +135,7 @@ module Inspec
|
|
133
135
|
@conf["reporter"].delete("json-rspec")
|
134
136
|
end
|
135
137
|
|
138
|
+
# These are built-in to rspec
|
136
139
|
formats = @conf["reporter"].select { |k, _v| %w{documentation progress html}.include?(k) }
|
137
140
|
formats.each do |k, v|
|
138
141
|
# We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
|
@@ -143,6 +146,33 @@ module Inspec
|
|
143
146
|
end
|
144
147
|
@conf["reporter"].delete(k)
|
145
148
|
end
|
149
|
+
|
150
|
+
# Here we need to look for reporter names in the reporter option that
|
151
|
+
# are names of streaming reporter plugins. We load them, then tell RSpec to add them as formatters.
|
152
|
+
# They will have already been detected at this point (see v2_loader.load_all in cli.rb)
|
153
|
+
# but they will not be activated activated at this point.
|
154
|
+
# then list all plugins by type by name
|
155
|
+
reg = Inspec::Plugin::V2::Registry.instance
|
156
|
+
streaming_reporters = reg\
|
157
|
+
.find_activators(plugin_type: :streaming_reporter)\
|
158
|
+
.map(&:activator_name).map(&:to_s)
|
159
|
+
|
160
|
+
@conf["reporter"].each do |streaming_reporter_name, file_target|
|
161
|
+
# It could be a non-streaming reporter
|
162
|
+
next unless streaming_reporters.include? streaming_reporter_name
|
163
|
+
|
164
|
+
# Activate the plugin so the formatter ID gets registered with RSpec, presumably
|
165
|
+
activator = reg.find_activator(plugin_type: :streaming_reporter, activator_name: streaming_reporter_name.to_sym)
|
166
|
+
activator.activate!
|
167
|
+
|
168
|
+
# We cannot pass in a nil output path. Rspec only accepts a valid string or a IO object.
|
169
|
+
if file_target&.[]("file").nil?
|
170
|
+
RSpec.configuration.add_formatter(activator.implementation_class)
|
171
|
+
else
|
172
|
+
RSpec.configuration.add_formatter(activator.implementation_class, file_target["file"])
|
173
|
+
end
|
174
|
+
@conf["reporter"].delete(streaming_reporter_name)
|
175
|
+
end
|
146
176
|
end
|
147
177
|
|
148
178
|
# Configure the output formatter and stream to be used with RSpec.
|
data/lib/inspec/utils/filter.rb
CHANGED
@@ -114,6 +114,7 @@ module FilterTable
|
|
114
114
|
raise(ArgumentError, "'#{decorate_symbols(raw_field_name)}' is not a recognized criterion - expected one of #{decorate_symbols(list_fields).join(", ")}'") unless field?(raw_field_name)
|
115
115
|
|
116
116
|
populate_lazy_field(raw_field_name, desired_value) if is_field_lazy?(raw_field_name)
|
117
|
+
populate_lazy_instance_field(raw_field_name, desired_value) if is_field_lazy_instance?(raw_field_name)
|
117
118
|
new_criteria_string += " #{raw_field_name} == #{desired_value.inspect}"
|
118
119
|
filtered_raw_data = filter_raw_data(filtered_raw_data, raw_field_name, desired_value)
|
119
120
|
end
|
@@ -188,6 +189,8 @@ module FilterTable
|
|
188
189
|
is_field ||= list_fields.include?(proposed_field.to_sym)
|
189
190
|
is_field ||= is_field_lazy?(proposed_field.to_s)
|
190
191
|
is_field ||= is_field_lazy?(proposed_field.to_sym)
|
192
|
+
is_field ||= is_field_lazy_instance?(proposed_field.to_s)
|
193
|
+
is_field ||= is_field_lazy_instance?(proposed_field.to_sym)
|
191
194
|
|
192
195
|
is_field
|
193
196
|
end
|
@@ -210,6 +213,23 @@ module FilterTable
|
|
210
213
|
mark_lazy_field_populated(field_name)
|
211
214
|
end
|
212
215
|
|
216
|
+
def populate_lazy_instance_field(field_name, criterion)
|
217
|
+
return unless is_field_lazy_instance?(field_name)
|
218
|
+
return if field_populated?(field_name)
|
219
|
+
|
220
|
+
raw_data.each do |row|
|
221
|
+
next if row.key?(field_name) # skip row if pre-existing data is present
|
222
|
+
|
223
|
+
lazy_caller = callback_for_lazy_instance_field(field_name)
|
224
|
+
if lazy_caller.is_a?(Proc)
|
225
|
+
lazy_caller.call(row, criterion, resource_instance)
|
226
|
+
elsif lazy_caller.is_a?(Symbol)
|
227
|
+
resource_instance.send(lazy_caller, row, criterion, self)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
mark_lazy_field_populated(field_name)
|
231
|
+
end
|
232
|
+
|
213
233
|
def is_field_lazy?(sought_field_name)
|
214
234
|
custom_properties_schema.values.any? do |property_struct|
|
215
235
|
sought_field_name == property_struct.field_name && \
|
@@ -217,6 +237,13 @@ module FilterTable
|
|
217
237
|
end
|
218
238
|
end
|
219
239
|
|
240
|
+
def is_field_lazy_instance?(sought_field_name)
|
241
|
+
custom_properties_schema.values.any? do |property_struct|
|
242
|
+
sought_field_name == property_struct.field_name && \
|
243
|
+
property_struct.opts[:lazy_instance]
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
220
247
|
def callback_for_lazy_field(field_name)
|
221
248
|
return unless is_field_lazy?(field_name)
|
222
249
|
|
@@ -225,6 +252,14 @@ module FilterTable
|
|
225
252
|
end.opts[:lazy]
|
226
253
|
end
|
227
254
|
|
255
|
+
def callback_for_lazy_instance_field(field_name)
|
256
|
+
return unless is_field_lazy_instance?(field_name)
|
257
|
+
|
258
|
+
custom_properties_schema.values.find do |property_struct|
|
259
|
+
property_struct.field_name == field_name
|
260
|
+
end.opts[:lazy_instance]
|
261
|
+
end
|
262
|
+
|
228
263
|
def field_populated?(field_name)
|
229
264
|
@populated_lazy_columns[field_name]
|
230
265
|
end
|
@@ -349,12 +384,18 @@ module FilterTable
|
|
349
384
|
# args of the row struct; also the Struct class will already have provided
|
350
385
|
# a setter for each field.
|
351
386
|
@custom_properties.values.each do |property_info|
|
352
|
-
next unless property_info.opts[:lazy]
|
387
|
+
next unless property_info.opts[:lazy] || property_info.opts[:lazy_instance]
|
353
388
|
|
354
389
|
field_name = property_info.field_name.to_sym
|
355
390
|
row_eval_context_type.send(:define_method, field_name) do
|
356
391
|
unless filter_table.field_populated?(field_name)
|
357
|
-
|
392
|
+
if property_info.opts[:lazy]
|
393
|
+
filter_table.populate_lazy_field(field_name, NoCriteriaProvided)
|
394
|
+
end # No access to criteria here
|
395
|
+
if property_info.opts[:lazy_instance]
|
396
|
+
filter_table.populate_lazy_instance_field(field_name,
|
397
|
+
NoCriteriaProvided)
|
398
|
+
end
|
358
399
|
# OK, the underlying raw data has the value in the first row
|
359
400
|
# (because we would trigger population only on the first row)
|
360
401
|
# We could just return the value, but we need to set it on this Struct in case it is referenced multiple times
|
@@ -449,7 +490,10 @@ module FilterTable
|
|
449
490
|
result = where(nil)
|
450
491
|
if custom_property_struct.opts[:lazy]
|
451
492
|
result.populate_lazy_field(custom_property_struct.field_name, filter_criteria_value)
|
493
|
+
elsif custom_property_struct.opts[:lazy_instance]
|
494
|
+
result.populate_lazy_instance_field(custom_property_struct.field_name, filter_criteria_value)
|
452
495
|
end
|
496
|
+
|
453
497
|
result = where(nil).get_column_values(custom_property_struct.field_name) # TODO: the where(nil). is likely unneeded
|
454
498
|
result = result.flatten.uniq.compact if custom_property_struct.opts[:style] == :simple
|
455
499
|
result
|
@@ -65,7 +65,7 @@ module Inspec
|
|
65
65
|
c[:results]&.each do |r|
|
66
66
|
next unless r[:message] # :message only set on failure
|
67
67
|
|
68
|
-
pos = r[:message].index(
|
68
|
+
pos = r[:message].index(/\n{1,2}Diff.*:/)
|
69
69
|
next unless pos # Only textual tests get Diffs
|
70
70
|
|
71
71
|
r[:message] = r[:message].slice(0, pos)
|
data/lib/inspec/version.rb
CHANGED
@@ -84,7 +84,7 @@ module InspecPlugins
|
|
84
84
|
return {} if data.nil? || data.empty?
|
85
85
|
|
86
86
|
parsed = JSON.parse(data)
|
87
|
-
return {} unless parsed.key?("
|
87
|
+
return {} unless parsed.key?("build_timestamp") && !parsed["build_timestamp"].empty?
|
88
88
|
|
89
89
|
parsed
|
90
90
|
end
|
@@ -219,9 +219,10 @@ module InspecPlugins
|
|
219
219
|
def version
|
220
220
|
config = InspecPlugins::Compliance::Configuration.new
|
221
221
|
info = InspecPlugins::Compliance::API.version(config)
|
222
|
-
if !info.nil? && info["
|
223
|
-
|
224
|
-
puts "
|
222
|
+
if !info.nil? && info["build_timestamp"]
|
223
|
+
# key info["api"] is not longer available in latest version api response
|
224
|
+
puts "Name: automate"
|
225
|
+
puts "Version: #{info["build_timestamp"]}"
|
225
226
|
else
|
226
227
|
puts "Could not determine server version."
|
227
228
|
exit 1
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.56.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef InSpec Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef-telemetry
|
@@ -117,7 +117,7 @@ dependencies:
|
|
117
117
|
- - ">="
|
118
118
|
- !ruby/object:Gem::Version
|
119
119
|
version: '3.9'
|
120
|
-
- - "
|
120
|
+
- - "<="
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '3.11'
|
123
123
|
type: :runtime
|
@@ -127,7 +127,7 @@ dependencies:
|
|
127
127
|
- - ">="
|
128
128
|
- !ruby/object:Gem::Version
|
129
129
|
version: '3.9'
|
130
|
-
- - "
|
130
|
+
- - "<="
|
131
131
|
- !ruby/object:Gem::Version
|
132
132
|
version: '3.11'
|
133
133
|
- !ruby/object:Gem::Dependency
|
@@ -479,6 +479,7 @@ files:
|
|
479
479
|
- lib/inspec/plugin/v2/plugin_types/input.rb
|
480
480
|
- lib/inspec/plugin/v2/plugin_types/mock.rb
|
481
481
|
- lib/inspec/plugin/v2/plugin_types/reporter.rb
|
482
|
+
- lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb
|
482
483
|
- lib/inspec/plugin/v2/registry.rb
|
483
484
|
- lib/inspec/plugin/v2/status.rb
|
484
485
|
- lib/inspec/profile.rb
|
@@ -554,6 +555,7 @@ files:
|
|
554
555
|
- lib/inspec/resources/json.rb
|
555
556
|
- lib/inspec/resources/kernel_module.rb
|
556
557
|
- lib/inspec/resources/kernel_parameter.rb
|
558
|
+
- lib/inspec/resources/kernel_parameters.rb
|
557
559
|
- lib/inspec/resources/key_rsa.rb
|
558
560
|
- lib/inspec/resources/ksh.rb
|
559
561
|
- lib/inspec/resources/launchd_service.rb
|
@@ -619,6 +621,7 @@ files:
|
|
619
621
|
- lib/inspec/resources/sys_info.rb
|
620
622
|
- lib/inspec/resources/systemd_service.rb
|
621
623
|
- lib/inspec/resources/sysv_service.rb
|
624
|
+
- lib/inspec/resources/timezone.rb
|
622
625
|
- lib/inspec/resources/toml.rb
|
623
626
|
- lib/inspec/resources/upstart_service.rb
|
624
627
|
- lib/inspec/resources/user.rb
|
@@ -788,7 +791,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
788
791
|
requirements:
|
789
792
|
- - ">="
|
790
793
|
- !ruby/object:Gem::Version
|
791
|
-
version: '2.
|
794
|
+
version: '2.6'
|
792
795
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
793
796
|
requirements:
|
794
797
|
- - ">="
|