inspec 1.45.9 → 1.45.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +54 -32
- data/CHANGELOG.md +29 -21
- data/Gemfile +1 -1
- data/docs/resources/ini.md.erb +14 -1
- data/docs/shell.md +1 -1
- data/inspec.gemspec +2 -2
- data/lib/bundles/inspec-artifact/cli.rb +3 -8
- data/lib/bundles/inspec-compliance/configuration.rb +5 -5
- data/lib/bundles/inspec-compliance/http.rb +2 -5
- data/lib/bundles/inspec-compliance/target.rb +6 -6
- data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +1 -1
- data/lib/bundles/inspec-habitat/profile.rb +68 -74
- data/lib/bundles/inspec-supermarket/api.rb +7 -7
- data/lib/bundles/inspec-supermarket/cli.rb +1 -1
- data/lib/fetchers/git.rb +3 -8
- data/lib/fetchers/local.rb +7 -13
- data/lib/fetchers/url.rb +1 -1
- data/lib/inspec/backend.rb +0 -1
- data/lib/inspec/base_cli.rb +1 -1
- data/lib/inspec/cached_fetcher.rb +11 -12
- data/lib/inspec/cli.rb +0 -1
- data/lib/inspec/control_eval_context.rb +2 -2
- data/lib/inspec/dependencies/lockfile.rb +13 -15
- data/lib/inspec/dependencies/requirement.rb +1 -1
- data/lib/inspec/dependencies/resolver.rb +3 -5
- data/lib/inspec/dsl.rb +5 -5
- data/lib/inspec/dsl_shared.rb +1 -1
- data/lib/inspec/env_printer.rb +26 -26
- data/lib/inspec/metadata.rb +11 -10
- data/lib/inspec/objects/or_test.rb +4 -2
- data/lib/inspec/objects/test.rb +1 -1
- data/lib/inspec/profile.rb +2 -2
- data/lib/inspec/resource.rb +1 -3
- data/lib/inspec/rspec_json_formatter.rb +6 -8
- data/lib/inspec/shell.rb +51 -52
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +1 -2
- data/lib/resources/audit_policy.rb +2 -2
- data/lib/resources/auditd.rb +6 -3
- data/lib/resources/dh_params.rb +1 -2
- data/lib/resources/docker.rb +2 -2
- data/lib/resources/docker_container.rb +4 -4
- data/lib/resources/elasticsearch.rb +2 -6
- data/lib/resources/etc_group.rb +2 -4
- data/lib/resources/groups.rb +14 -14
- data/lib/resources/host.rb +2 -3
- data/lib/resources/packages.rb +1 -1
- data/lib/resources/port.rb +1 -1
- data/lib/resources/postgres.rb +6 -6
- data/lib/resources/powershell.rb +1 -1
- data/lib/resources/service.rb +4 -5
- data/lib/resources/users.rb +58 -58
- data/lib/resources/vbscript.rb +10 -10
- data/lib/resources/virtualization.rb +3 -4
- data/lib/resources/x509_certificate.rb +1 -1
- data/lib/resources/yum.rb +1 -1
- data/lib/source_readers/inspec.rb +2 -1
- data/lib/utils/command_wrapper.rb +3 -8
- data/lib/utils/filter.rb +1 -1
- data/lib/utils/json_log.rb +2 -1
- data/lib/utils/latest_version.rb +5 -4
- data/lib/utils/object_traversal.rb +1 -1
- data/lib/utils/parser.rb +2 -2
- metadata +4 -4
data/lib/inspec/objects/test.rb
CHANGED
@@ -42,7 +42,7 @@ module Inspec
|
|
42
42
|
def describe_chain
|
43
43
|
return nil if @qualifier.empty?
|
44
44
|
|
45
|
-
resource =
|
45
|
+
resource = @qualifier.length > 1 ? @qualifier[0..-2] : [@qualifier[0]]
|
46
46
|
res = resource.map { |q| ruby_qualifier(q) }.join('.')
|
47
47
|
xres = nil
|
48
48
|
|
data/lib/inspec/profile.rb
CHANGED
@@ -106,7 +106,7 @@ module Inspec
|
|
106
106
|
# we share the backend between profiles.
|
107
107
|
#
|
108
108
|
# This will cause issues if a profile attempts to load a file via `inspec.profile.file`
|
109
|
-
train_options = options.
|
109
|
+
train_options = options.reject { |k, _| k == 'target' } # See https://github.com/chef/inspec/pull/1646
|
110
110
|
@backend = options[:backend].nil? ? Inspec::Backend.create(train_options) : options[:backend].dup
|
111
111
|
@runtime_profile = RuntimeProfile.new(self)
|
112
112
|
@backend.profile = @runtime_profile
|
@@ -421,7 +421,7 @@ module Inspec
|
|
421
421
|
[['inspec.yml', source_reader.metadata.content]] +
|
422
422
|
[['inspec.lock.deps', YAML.dump(deps)]]
|
423
423
|
|
424
|
-
files.
|
424
|
+
files.sort_by { |a| a[0] }
|
425
425
|
.map { |f| res << f[0] << "\0" << f[1] << "\0" }
|
426
426
|
|
427
427
|
res.digest.unpack('H*')[0]
|
data/lib/inspec/resource.rb
CHANGED
@@ -455,10 +455,10 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
455
455
|
end
|
456
456
|
|
457
457
|
def print_last_control_with_examples
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
458
|
+
return unless @last_control
|
459
|
+
|
460
|
+
print_control(@last_control)
|
461
|
+
@last_control.examples.each { |example| print_result(example) }
|
462
462
|
end
|
463
463
|
|
464
464
|
def last_control_is_anonymous?
|
@@ -634,8 +634,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
634
634
|
s = format('Profile Summary: %s, %s, %s',
|
635
635
|
format_with_color(success_color, success_str),
|
636
636
|
format_with_color(failed_color, failed_str),
|
637
|
-
format_with_color(skipped_color, skipped_str)
|
638
|
-
)
|
637
|
+
format_with_color(skipped_color, skipped_str))
|
639
638
|
output.puts(s) if summary['total'] > 0
|
640
639
|
end
|
641
640
|
|
@@ -651,8 +650,7 @@ class InspecRspecCli < InspecRspecJson # rubocop:disable Metrics/ClassLength
|
|
651
650
|
s = format('Test Summary: %s, %s, %s',
|
652
651
|
format_with_color(success_color, "#{summary['passed']} successful"),
|
653
652
|
format_with_color(failed_color, failed_str),
|
654
|
-
format_with_color(skipped_color, "#{summary['skipped']} skipped")
|
655
|
-
)
|
653
|
+
format_with_color(skipped_color, "#{summary['skipped']} skipped"))
|
656
654
|
|
657
655
|
output.puts(s)
|
658
656
|
end
|
data/lib/inspec/shell.rb
CHANGED
@@ -103,35 +103,34 @@ module Inspec
|
|
103
103
|
|
104
104
|
def print_target_info
|
105
105
|
ctx = @runner.backend
|
106
|
-
puts
|
107
|
-
You are currently running on:
|
106
|
+
puts <<~EOF
|
107
|
+
You are currently running on:
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
EOF
|
109
|
+
OS platform: #{mark ctx.os[:name] || 'unknown'}
|
110
|
+
OS family: #{mark ctx.os[:family] || 'unknown'}
|
111
|
+
OS release: #{mark ctx.os[:release] || 'unknown'}
|
112
|
+
EOF
|
113
113
|
end
|
114
114
|
|
115
115
|
def help(topic = nil)
|
116
116
|
if topic.nil?
|
117
117
|
|
118
|
-
puts
|
118
|
+
puts <<~EOF
|
119
|
+
Available commands:
|
119
120
|
|
120
|
-
|
121
|
+
`[resource]` - run resource on target machine
|
122
|
+
`help resources` - show all available resources that can be used as commands
|
123
|
+
`help [resource]` - information about a specific resource
|
124
|
+
`help matchers` - show information about common matchers
|
125
|
+
`exit` - exit the InSpec shell
|
121
126
|
|
122
|
-
|
123
|
-
`help resources` - show all available resources that can be used as commands
|
124
|
-
`help [resource]` - information about a specific resource
|
125
|
-
`help matchers` - show information about common matchers
|
126
|
-
`exit` - exit the InSpec shell
|
127
|
+
You can use resources in this environment to test the target machine. For example:
|
127
128
|
|
128
|
-
|
129
|
+
command('uname -a').stdout
|
130
|
+
file('/proc/cpuinfo').content => "value"
|
129
131
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
#{print_target_info}
|
134
|
-
EOF
|
132
|
+
#{print_target_info}
|
133
|
+
EOF
|
135
134
|
elsif topic == 'resources'
|
136
135
|
resources.sort.each do |resource|
|
137
136
|
puts " - #{resource}"
|
@@ -164,60 +163,60 @@ EOF
|
|
164
163
|
end
|
165
164
|
|
166
165
|
def print_matchers_help
|
167
|
-
puts
|
168
|
-
Matchers are used to compare resource values to expectations. While some
|
169
|
-
resources implement their own custom matchers, the following matchers are
|
170
|
-
common amongst all resources:
|
166
|
+
puts <<~EOL
|
167
|
+
Matchers are used to compare resource values to expectations. While some
|
168
|
+
resources implement their own custom matchers, the following matchers are
|
169
|
+
common amongst all resources:
|
171
170
|
|
172
|
-
#{mark 'be'}
|
171
|
+
#{mark 'be'}
|
173
172
|
|
174
|
-
The #{mark 'be'} matcher can be used to compare numeric values.
|
173
|
+
The #{mark 'be'} matcher can be used to compare numeric values.
|
175
174
|
|
176
|
-
|
175
|
+
its('size') { should be >= 10 }
|
177
176
|
|
178
|
-
#{mark 'cmp'}
|
177
|
+
#{mark 'cmp'}
|
179
178
|
|
180
|
-
The #{mark 'cmp'} matcher is like #{mark 'eq'} but less restrictive. It will try
|
181
|
-
to fit the resource value to the expectation.
|
179
|
+
The #{mark 'cmp'} matcher is like #{mark 'eq'} but less restrictive. It will try
|
180
|
+
to fit the resource value to the expectation.
|
182
181
|
|
183
|
-
"Protocol" likely returns a string, but cmp will ensure it's a number before
|
184
|
-
comparing:
|
182
|
+
"Protocol" likely returns a string, but cmp will ensure it's a number before
|
183
|
+
comparing:
|
185
184
|
|
186
|
-
|
187
|
-
|
185
|
+
its('Protocol') { should cmp 2 }
|
186
|
+
its('Protocol') { should cmp '2' }
|
188
187
|
|
189
|
-
"users" may return an array, but if it contains only one item, cmp will compare
|
190
|
-
it as a string or number as needed:
|
188
|
+
"users" may return an array, but if it contains only one item, cmp will compare
|
189
|
+
it as a string or number as needed:
|
191
190
|
|
192
|
-
|
191
|
+
its('users') { should cmp 'root' }
|
193
192
|
|
194
|
-
cmp is not case-sensitive:
|
193
|
+
cmp is not case-sensitive:
|
195
194
|
|
196
|
-
|
197
|
-
|
195
|
+
its('log_format') { should cmp 'raw' }
|
196
|
+
its('log_format') { should cmp 'RAW' }
|
198
197
|
|
199
|
-
#{mark 'eq'}
|
198
|
+
#{mark 'eq'}
|
200
199
|
|
201
|
-
The #{mark 'eq'} matcher tests for exact equality of two values. Value type
|
202
|
-
(string, number, etc.) is important and must be the same. For a less-restrictive
|
203
|
-
comparison matcher, use the #{mark 'cmp'} matcher.
|
200
|
+
The #{mark 'eq'} matcher tests for exact equality of two values. Value type
|
201
|
+
(string, number, etc.) is important and must be the same. For a less-restrictive
|
202
|
+
comparison matcher, use the #{mark 'cmp'} matcher.
|
204
203
|
|
205
|
-
|
204
|
+
its('RSAAuthentication') { should_not eq 'no' }
|
206
205
|
|
207
|
-
#{mark 'include'}
|
206
|
+
#{mark 'include'}
|
208
207
|
|
209
|
-
The #{mark 'include'} matcher tests to see if a value is included in a list.
|
208
|
+
The #{mark 'include'} matcher tests to see if a value is included in a list.
|
210
209
|
|
211
|
-
|
210
|
+
its('users') { should include 'my_user' }
|
212
211
|
|
213
|
-
#{mark 'match'}
|
212
|
+
#{mark 'match'}
|
214
213
|
|
215
|
-
The #{mark 'match'} matcher can be used to test a string for a match using a
|
216
|
-
regular expression.
|
214
|
+
The #{mark 'match'} matcher can be used to test a string for a match using a
|
215
|
+
regular expression.
|
217
216
|
|
218
|
-
|
217
|
+
its('content') { should_not match /^MyKey:\\s+some value/ }
|
219
218
|
|
220
|
-
For more examples, see: https://www.inspec.io/docs/reference/matchers/
|
219
|
+
For more examples, see: https://www.inspec.io/docs/reference/matchers/
|
221
220
|
|
222
221
|
EOL
|
223
222
|
end
|
data/lib/inspec/version.rb
CHANGED
data/lib/matchers/matchers.rb
CHANGED
@@ -266,7 +266,7 @@ end
|
|
266
266
|
# - compare strings case-insensitive
|
267
267
|
# - you expect a number (strings will be converted if possible)
|
268
268
|
#
|
269
|
-
RSpec::Matchers.define :cmp do |first_expected|
|
269
|
+
RSpec::Matchers.define :cmp do |first_expected| # rubocop:disable Metrics/BlockLength
|
270
270
|
|
271
271
|
def integer?(value)
|
272
272
|
!(value =~ /\A0+\Z|\A[1-9]\d*\Z/).nil?
|
@@ -324,7 +324,6 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
324
324
|
|
325
325
|
# fallback to simple operation
|
326
326
|
actual.method(op).call(expected)
|
327
|
-
|
328
327
|
rescue NameError => _
|
329
328
|
false
|
330
329
|
rescue ArgumentError
|
data/lib/resources/auditd.rb
CHANGED
@@ -101,7 +101,8 @@ module Inspec::Resources
|
|
101
101
|
'permissions' => perms,
|
102
102
|
'key' => key,
|
103
103
|
'fields_nokey' => fields_nokey,
|
104
|
-
},
|
104
|
+
},
|
105
|
+
)
|
105
106
|
end
|
106
107
|
|
107
108
|
def syscall_rules_for(line)
|
@@ -128,7 +129,8 @@ module Inspec::Resources
|
|
128
129
|
'permissions' => perms,
|
129
130
|
'exit' => exit_field,
|
130
131
|
'fields_nokey' => fields_nokey,
|
131
|
-
},
|
132
|
+
},
|
133
|
+
)
|
132
134
|
end
|
133
135
|
end
|
134
136
|
|
@@ -142,7 +144,8 @@ module Inspec::Resources
|
|
142
144
|
'file' => file,
|
143
145
|
'key' => key,
|
144
146
|
'permissions' => perms,
|
145
|
-
},
|
147
|
+
},
|
148
|
+
)
|
146
149
|
end
|
147
150
|
|
148
151
|
def to_s
|
data/lib/resources/dh_params.rb
CHANGED
@@ -26,8 +26,7 @@ class DhParams < Inspec.resource(1)
|
|
26
26
|
def initialize(filename)
|
27
27
|
@dh_params_path = filename
|
28
28
|
file = inspec.file(@dh_params_path)
|
29
|
-
return skip_resource
|
30
|
-
"#{@dh_params_path}" unless file.exist?
|
29
|
+
return skip_resource "Unable to find DH parameters file #{@dh_params_path}" unless file.exist?
|
31
30
|
|
32
31
|
begin
|
33
32
|
@dh_params = OpenSSL::PKey::DH.new file.content
|
data/lib/resources/docker.rb
CHANGED
@@ -146,7 +146,7 @@ module Inspec::Resources
|
|
146
146
|
# @see https://github.com/moby/moby/issues/20625, works for docker 1.13+
|
147
147
|
# raw_containers = inspec.command('docker ps -a --no-trunc --format \'{{ json . }}\'').stdout
|
148
148
|
# therefore we stick with older approach
|
149
|
-
labels = %w{Command CreatedAt ID Image Labels
|
149
|
+
labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
|
150
150
|
|
151
151
|
# Networks LocalVolumes work with 1.13+ only
|
152
152
|
if !version.empty? && Gem::Version.new(version['Client']['Version']) >= Gem::Version.new('1.13')
|
@@ -183,7 +183,7 @@ module Inspec::Resources
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def ensure_container_keys(entry)
|
186
|
-
%w{Command CreatedAt ID Image Labels
|
186
|
+
%w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status Networks LocalVolumes}.each { |key|
|
187
187
|
entry[key.downcase] = nil if !entry.key?(key.downcase)
|
188
188
|
}
|
189
189
|
entry
|
@@ -63,10 +63,10 @@ module Inspec::Resources
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def command
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
return unless container_info.entries.length == 1
|
67
|
+
|
68
|
+
cmd = container_info.commands[0]
|
69
|
+
cmd.slice(1, cmd.length - 2)
|
70
70
|
end
|
71
71
|
|
72
72
|
def image
|
@@ -154,9 +154,7 @@ module Inspec::Resources
|
|
154
154
|
raise 'Connection refused - peer certificate issuer is not recognized'
|
155
155
|
end
|
156
156
|
|
157
|
-
|
158
|
-
raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}"
|
159
|
-
end
|
157
|
+
raise "Error fetching Elastcsearch data from curl #{url}: #{cmd.stderr}" unless cmd.exit_status.zero?
|
160
158
|
end
|
161
159
|
|
162
160
|
def verify_json_payload!(content)
|
@@ -164,9 +162,7 @@ module Inspec::Resources
|
|
164
162
|
raise "#{content['error']['type']}: #{content['error']['reason']}"
|
165
163
|
end
|
166
164
|
|
167
|
-
if content['_nodes']['successful'].zero?
|
168
|
-
raise 'No successful nodes available in cluster'
|
169
|
-
end
|
165
|
+
raise 'No successful nodes available in cluster' if content['_nodes']['successful'].zero?
|
170
166
|
end
|
171
167
|
end
|
172
168
|
end
|
data/lib/resources/etc_group.rb
CHANGED
@@ -49,13 +49,11 @@ module Inspec::Resources
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def groups(filter = nil)
|
52
|
-
|
53
|
-
entries.map { |x| x['name'] } if !entries.nil?
|
52
|
+
(filter || @entries)&.map { |x| x['name'] }
|
54
53
|
end
|
55
54
|
|
56
55
|
def gids(filter = nil)
|
57
|
-
|
58
|
-
entries.map { |x| x['gid'] } if !entries.nil?
|
56
|
+
(filter || @entries)&.map { |x| x['gid'] }
|
59
57
|
end
|
60
58
|
|
61
59
|
def users(filter = nil)
|
data/lib/resources/groups.rb
CHANGED
@@ -157,20 +157,20 @@ module Inspec::Resources
|
|
157
157
|
class WindowsGroup < GroupInfo
|
158
158
|
# returns all local groups
|
159
159
|
def groups
|
160
|
-
script =
|
161
|
-
Function ConvertTo-SID { Param([byte[]]$BinarySID)
|
162
|
-
|
163
|
-
}
|
164
|
-
|
165
|
-
$Computername = $Env:Computername
|
166
|
-
$adsi = [ADSI]"WinNT://$Computername"
|
167
|
-
$groups = $adsi.Children | where {$_.SchemaClassName -eq 'group'} | ForEach {
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
}
|
173
|
-
$groups | ConvertTo-Json -Depth 3
|
160
|
+
script = <<~EOH
|
161
|
+
Function ConvertTo-SID { Param([byte[]]$BinarySID)
|
162
|
+
(New-Object System.Security.Principal.SecurityIdentifier($BinarySID,0)).Value
|
163
|
+
}
|
164
|
+
|
165
|
+
$Computername = $Env:Computername
|
166
|
+
$adsi = [ADSI]"WinNT://$Computername"
|
167
|
+
$groups = $adsi.Children | where {$_.SchemaClassName -eq 'group'} | ForEach {
|
168
|
+
$name = $_.Name[0]
|
169
|
+
$sid = ConvertTo-SID -BinarySID $_.ObjectSID[0]
|
170
|
+
$group =[ADSI]$_.Path
|
171
|
+
new-object psobject -property @{name = $group.Name[0]; gid = $sid; domain=$Computername}
|
172
|
+
}
|
173
|
+
$groups | ConvertTo-Json -Depth 3
|
174
174
|
EOH
|
175
175
|
cmd = inspec.powershell(script)
|
176
176
|
# cannot rely on exit code for now, successful command returns exit code 1
|
data/lib/resources/host.rb
CHANGED
@@ -70,9 +70,8 @@ module Inspec::Resources
|
|
70
70
|
end
|
71
71
|
|
72
72
|
missing_requirements = @host_provider.missing_requirements(protocol)
|
73
|
-
|
74
|
-
|
75
|
-
end
|
73
|
+
return skip_resource 'The following requirements are not met for this resource: ' \
|
74
|
+
"#{missing_requirements.join(', ')}" unless missing_requirements.empty?
|
76
75
|
end
|
77
76
|
|
78
77
|
def proto
|
data/lib/resources/packages.rb
CHANGED
@@ -97,7 +97,7 @@ module Inspec::Resources
|
|
97
97
|
class Rpms < PkgsManagement
|
98
98
|
def build_package_list
|
99
99
|
# use two spaces as delimiter in case any of the fields has a space in it
|
100
|
-
command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'"
|
100
|
+
command = "rpm -qa --queryformat '%{NAME} %{VERSION}-%{RELEASE}\\n'" # rubocop:disable Style/FormatStringToken
|
101
101
|
cmd = inspec.command(command)
|
102
102
|
all = cmd.stdout.split("\n")
|
103
103
|
return [] if all.nil?
|
data/lib/resources/port.rb
CHANGED
@@ -242,7 +242,7 @@ module Inspec::Resources
|
|
242
242
|
procs[proc_id] = [] unless procs.key?(proc_id)
|
243
243
|
|
244
244
|
# change address '*' to zero
|
245
|
-
host =
|
245
|
+
host = port_id =~ /^ipv6:/ ? '[::]' : '0.0.0.0' if host == '*'
|
246
246
|
# entrust URI to scrub the host and port
|
247
247
|
begin
|
248
248
|
uri = URI("addr://#{host}:#{port}")
|