inspec-core 4.52.9 → 4.56.17
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 +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
|
- - ">="
|