inspec 0.18.0 → 0.19.0
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/CHANGELOG.md +35 -2
- data/README.md +27 -2
- data/docs/resources.rst +49 -3
- data/inspec.gemspec +1 -1
- data/lib/bundles/inspec-compliance/README.md +2 -1
- data/lib/bundles/inspec-compliance/api.rb +60 -102
- data/lib/bundles/inspec-compliance/cli.rb +133 -14
- data/lib/bundles/inspec-compliance/configuration.rb +43 -1
- data/lib/bundles/inspec-compliance/http.rb +80 -0
- data/lib/bundles/inspec-compliance.rb +1 -0
- data/lib/inspec/metadata.rb +40 -27
- data/lib/inspec/objects/test.rb +2 -1
- data/lib/inspec/resource.rb +1 -0
- data/lib/inspec/rspec_json_formatter.rb +1 -1
- data/lib/inspec/runner.rb +19 -13
- data/lib/inspec/runner_rspec.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/matchers/matchers.rb +32 -13
- data/lib/resources/grub_conf.rb +186 -0
- data/lib/resources/json.rb +1 -1
- data/lib/resources/service.rb +9 -3
- data/lib/utils/base_cli.rb +2 -1
- data/lib/utils/hash_map.rb +37 -0
- data/test/functional/inspec_compliance_test.rb +60 -0
- data/test/functional/inspec_exec_test.rb +49 -10
- data/test/helper.rb +3 -0
- data/test/integration/default/compare_matcher_spec.rb +21 -0
- data/test/unit/metadata_test.rb +49 -23
- data/test/unit/mock/cmd/systemctl-show-all-dbus +6 -0
- data/test/unit/mock/files/grub.conf +21 -0
- data/test/unit/mock/profiles/resource-tiny/inspec.yml +10 -0
- data/test/unit/mock/profiles/resource-tiny/libraries/resource.rb +3 -0
- data/test/unit/mock/profiles/supported_inspec/inspec.yml +2 -0
- data/test/unit/mock/profiles/unsupported_inspec/inspec.yml +2 -0
- data/test/unit/profile_test.rb +1 -1
- data/test/unit/resources/grub_conf_test.rb +29 -0
- data/test/unit/resources/service_test.rb +9 -0
- data/test/unit/utils/hash_map_test.rb +63 -0
- metadata +26 -5
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Christoph Hartmann
|
3
|
+
# author: Dominik Richter
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module Compliance
|
9
|
+
# implements a simple http abstraction on top of Net::HTTP
|
10
|
+
class HTTP
|
11
|
+
# generic get requires
|
12
|
+
def self.get(url, token, insecure, basic_auth = false)
|
13
|
+
uri = URI.parse(url)
|
14
|
+
req = Net::HTTP::Get.new(uri.path)
|
15
|
+
|
16
|
+
return send_request(uri, req, insecure) if token.nil?
|
17
|
+
|
18
|
+
if basic_auth
|
19
|
+
req.basic_auth(token, '')
|
20
|
+
else
|
21
|
+
req['Authorization'] = "Bearer #{token}"
|
22
|
+
end
|
23
|
+
send_request(uri, req, insecure)
|
24
|
+
end
|
25
|
+
|
26
|
+
# generic post request
|
27
|
+
def self.post(url, token, insecure, basic_auth = false)
|
28
|
+
# form request
|
29
|
+
uri = URI.parse(url)
|
30
|
+
req = Net::HTTP::Post.new(uri.path)
|
31
|
+
if basic_auth
|
32
|
+
req.basic_auth token, ''
|
33
|
+
else
|
34
|
+
req['Authorization'] = "Bearer #{token}"
|
35
|
+
end
|
36
|
+
req.form_data={}
|
37
|
+
|
38
|
+
send_request(uri, req, insecure)
|
39
|
+
end
|
40
|
+
|
41
|
+
# post a file
|
42
|
+
def self.post_file(url, token, file_path, insecure, basic_auth = false)
|
43
|
+
uri = URI.parse(url)
|
44
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
45
|
+
|
46
|
+
# set connection flags
|
47
|
+
http.use_ssl = (uri.scheme == 'https')
|
48
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if insecure
|
49
|
+
|
50
|
+
req = Net::HTTP::Post.new(uri.path)
|
51
|
+
if basic_auth
|
52
|
+
req.basic_auth token, ''
|
53
|
+
else
|
54
|
+
req['Authorization'] = "Bearer #{token}"
|
55
|
+
end
|
56
|
+
|
57
|
+
req.body_stream=File.open(file_path, 'rb')
|
58
|
+
req.add_field('Content-Length', File.size(file_path))
|
59
|
+
req.add_field('Content-Type', 'application/x-gtar')
|
60
|
+
|
61
|
+
boundary = 'INSPEC-PROFILE-UPLOAD'
|
62
|
+
req.add_field('session', boundary)
|
63
|
+
res=http.request(req)
|
64
|
+
res
|
65
|
+
end
|
66
|
+
|
67
|
+
# sends a http requests
|
68
|
+
def self.send_request(uri, req, insecure)
|
69
|
+
opts = {
|
70
|
+
use_ssl: uri.scheme == 'https',
|
71
|
+
}
|
72
|
+
opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if insecure
|
73
|
+
|
74
|
+
res = Net::HTTP.start(uri.host, uri.port, opts) {|http|
|
75
|
+
http.request(req)
|
76
|
+
}
|
77
|
+
res
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/inspec/metadata.rb
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
# author: Christoph Hartmann
|
5
5
|
|
6
6
|
require 'logger'
|
7
|
+
require 'rubygems/version'
|
8
|
+
require 'rubygems/requirement'
|
7
9
|
|
8
10
|
module Inspec
|
9
11
|
# Extract metadata.rb information
|
@@ -40,8 +42,10 @@ module Inspec
|
|
40
42
|
# already.
|
41
43
|
end
|
42
44
|
|
43
|
-
def is_supported(os, entry)
|
44
|
-
name
|
45
|
+
def is_supported?(os, entry)
|
46
|
+
name = entry[:'os-name'] || entry[:os]
|
47
|
+
family = entry[:'os-family']
|
48
|
+
release = entry[:release]
|
45
49
|
|
46
50
|
# return true if the backend matches the supported OS's
|
47
51
|
# fields act as masks, i.e. any value configured for os-name, os-family,
|
@@ -66,34 +70,24 @@ module Inspec
|
|
66
70
|
name_ok && family_ok && release_ok
|
67
71
|
end
|
68
72
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
family = try_support[:'os-family']
|
74
|
-
release = try_support[:release]
|
75
|
-
elsif entry.is_a?(String)
|
76
|
-
@logger.warn(
|
77
|
-
"Do not use deprecated `supports: #{entry}` syntax. Instead use "\
|
78
|
-
"`supports: {os-family: #{entry}}`.")
|
79
|
-
family = entry
|
80
|
-
end
|
73
|
+
def inspec_requirement
|
74
|
+
inspec = params[:supports].find { |x| !x[:inspec].nil? } || {}
|
75
|
+
Gem::Requirement.create(inspec[:inspec])
|
76
|
+
end
|
81
77
|
|
82
|
-
|
78
|
+
def supports_runtime?
|
79
|
+
running = Gem::Version.new(Inspec::VERSION)
|
80
|
+
inspec_requirement.satisfied_by?(running)
|
83
81
|
end
|
84
82
|
|
85
83
|
def supports_transport?(backend)
|
86
|
-
# make sure the supports field is always an array
|
87
|
-
supp = params[:supports]
|
88
|
-
supp = supp.is_a?(Hash) ? [supp] : Array(supp)
|
89
|
-
|
90
84
|
# with no supports specified, always return true, as there are no
|
91
85
|
# constraints on the supported backend; it is equivalent to putting
|
92
86
|
# all fields into accept-all mode
|
93
|
-
return true if
|
87
|
+
return true if params[:supports].empty?
|
94
88
|
|
95
|
-
found =
|
96
|
-
is_supported(backend.os, entry)
|
89
|
+
found = params[:supports].find do |entry|
|
90
|
+
is_supported?(backend.os, entry)
|
97
91
|
end
|
98
92
|
|
99
93
|
# finally, if we found a supported entry, we are good to go
|
@@ -132,32 +126,51 @@ module Inspec
|
|
132
126
|
@missing_methods
|
133
127
|
end
|
134
128
|
|
135
|
-
def self.symbolize_keys(
|
136
|
-
|
129
|
+
def self.symbolize_keys(obj)
|
130
|
+
return obj.map { |i| symbolize_keys(i) } if obj.is_a?(Array)
|
131
|
+
return obj unless obj.is_a?(Hash)
|
132
|
+
|
133
|
+
obj.each_with_object({}) {|(k, v), h|
|
137
134
|
v = symbolize_keys(v) if v.is_a?(Hash)
|
135
|
+
v = symbolize_keys(v) if v.is_a?(Array)
|
138
136
|
h[k.to_sym] = v
|
139
137
|
}
|
140
138
|
end
|
141
139
|
|
142
|
-
def self.finalize(metadata, profile_id)
|
140
|
+
def self.finalize(metadata, profile_id, logger = nil)
|
143
141
|
return nil if metadata.nil?
|
144
142
|
param = metadata.params || {}
|
145
143
|
param['name'] = profile_id.to_s unless profile_id.to_s.empty?
|
146
144
|
param['version'] = param['version'].to_s unless param['version'].nil?
|
147
145
|
metadata.params = symbolize_keys(param)
|
146
|
+
|
147
|
+
# consolidate supports field with legacy mode
|
148
|
+
metadata.params[:supports] =
|
149
|
+
case x = metadata.params[:supports]
|
150
|
+
when Hash then [x]
|
151
|
+
when Array then x
|
152
|
+
when nil then []
|
153
|
+
else
|
154
|
+
logger ||= Logger.new(nil)
|
155
|
+
logger.warn(
|
156
|
+
"Do not use deprecated `supports: #{x}` syntax. Instead use "\
|
157
|
+
"`supports: {os-family: #{x}}`.")
|
158
|
+
[{ :'os-family' => x }]
|
159
|
+
end
|
160
|
+
|
148
161
|
metadata
|
149
162
|
end
|
150
163
|
|
151
164
|
def self.from_yaml(ref, contents, profile_id, logger = nil)
|
152
165
|
res = Metadata.new(ref, logger)
|
153
166
|
res.params = YAML.load(contents)
|
154
|
-
finalize(res, profile_id)
|
167
|
+
finalize(res, profile_id, logger)
|
155
168
|
end
|
156
169
|
|
157
170
|
def self.from_ruby(ref, contents, profile_id, logger = nil)
|
158
171
|
res = Metadata.new(ref, logger)
|
159
172
|
res.instance_eval(contents, ref, 1)
|
160
|
-
finalize(res, profile_id)
|
173
|
+
finalize(res, profile_id, logger)
|
161
174
|
end
|
162
175
|
|
163
176
|
def self.from_ref(ref, contents, profile_id, logger = nil)
|
data/lib/inspec/objects/test.rb
CHANGED
@@ -48,7 +48,8 @@ module Inspec
|
|
48
48
|
|
49
49
|
if @qualifier.length > 1
|
50
50
|
last = @qualifier[-1]
|
51
|
-
|
51
|
+
# preventing its(:to_i) as the value returned is always 0
|
52
|
+
if last.length == 1 && last[0] != 'to_i'
|
52
53
|
xres = last[0]
|
53
54
|
else
|
54
55
|
res += '.' + ruby_qualifier(last)
|
data/lib/inspec/resource.rb
CHANGED
@@ -38,7 +38,7 @@ class InspecRspecFormatter < RSpec::Core::Formatters::JsonFormatter
|
|
38
38
|
|
39
39
|
def dump_summary(summary)
|
40
40
|
super(summary)
|
41
|
-
@output_hash[:profiles] = @profiles.map do |profile|
|
41
|
+
@output_hash[:profiles] = Array(@profiles).map do |profile|
|
42
42
|
r = profile.params.dup
|
43
43
|
r.delete(:rules)
|
44
44
|
r
|
data/lib/inspec/runner.rb
CHANGED
@@ -52,7 +52,26 @@ module Inspec
|
|
52
52
|
add_profile(profile, options)
|
53
53
|
end
|
54
54
|
|
55
|
+
def supports_profile?(profile)
|
56
|
+
return true if profile.metadata.nil?
|
57
|
+
|
58
|
+
if !profile.metadata.supports_runtime?
|
59
|
+
fail 'This profile requires InSpec version '\
|
60
|
+
"#{profile.metadata.inspec_requirement}. You are running "\
|
61
|
+
"InSpec v#{Inspec::VERSION}.\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
if !profile.metadata.supports_transport?(@backend)
|
65
|
+
os_info = @backend.os[:family].to_s
|
66
|
+
fail "This OS/platform (#{os_info}) is not supported by this profile."
|
67
|
+
end
|
68
|
+
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
55
72
|
def add_profile(profile, options = {})
|
73
|
+
return if !options[:ignore_supports] && !supports_profile?(profile)
|
74
|
+
|
56
75
|
@test_collector.add_profile(profile)
|
57
76
|
options[:metadata] = profile.metadata
|
58
77
|
|
@@ -86,19 +105,6 @@ module Inspec
|
|
86
105
|
tests = [tests] unless tests.is_a? Array
|
87
106
|
tests.each { |t| add_test_to_context(t, ctx) }
|
88
107
|
|
89
|
-
# skip based on support checks in metadata
|
90
|
-
meta = options[:metadata]
|
91
|
-
if !options[:ignore_supports] && !meta.nil? &&
|
92
|
-
!meta.supports_transport?(@backend)
|
93
|
-
os_info = @backend.os[:family].to_s
|
94
|
-
ctx.rules.values.each do |ctrl|
|
95
|
-
::Inspec::Rule.set_skip_rule(
|
96
|
-
ctrl,
|
97
|
-
"This OS/platform (#{os_info}) is not supported by this profile.",
|
98
|
-
)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
108
|
# process the resulting rules
|
103
109
|
filter_controls(ctx.rules, options[:controls]).each do |rule_id, rule|
|
104
110
|
register_rule(rule_id, rule)
|
data/lib/inspec/runner_rspec.rb
CHANGED
data/lib/inspec/version.rb
CHANGED
data/lib/matchers/matchers.rb
CHANGED
@@ -226,7 +226,7 @@ end
|
|
226
226
|
# - compare strings case-insensitive
|
227
227
|
# - you expect a number (strings will be converted if possible)
|
228
228
|
#
|
229
|
-
RSpec::Matchers.define :cmp do |
|
229
|
+
RSpec::Matchers.define :cmp do |first_expected|
|
230
230
|
|
231
231
|
def integer?(value)
|
232
232
|
!(value =~ /\A\d+\Z/).nil?
|
@@ -243,33 +243,52 @@ RSpec::Matchers.define :cmp do |expected|
|
|
243
243
|
!(value =~ /\A0+\d+\Z/).nil?
|
244
244
|
end
|
245
245
|
|
246
|
-
|
247
|
-
actual = actual[0] if actual.is_a?(Array) && !expected.is_a?(Array) && actual.length == 1
|
246
|
+
def try_match(actual, op, expected) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
248
247
|
# if actual and expected are strings
|
249
248
|
if expected.is_a?(String) && actual.is_a?(String)
|
250
|
-
actual.casecmp(expected) == 0
|
249
|
+
return actual.casecmp(expected) == 0 if op == :==
|
251
250
|
elsif expected.is_a?(String) && integer?(expected) && actual.is_a?(Integer)
|
252
|
-
expected.to_i
|
251
|
+
return actual.method(op).call(expected.to_i)
|
253
252
|
elsif expected.is_a?(Integer) && integer?(actual)
|
254
|
-
|
253
|
+
return actual.to_i.method(op).call(expected)
|
255
254
|
elsif expected.is_a?(Float) && float?(actual)
|
256
|
-
|
255
|
+
return actual.to_f.method(op).call(expected)
|
257
256
|
elsif octal?(expected) && actual.is_a?(Integer)
|
258
|
-
expected.to_i(8)
|
259
|
-
|
260
|
-
|
261
|
-
|
257
|
+
return actual.method(op).call(expected.to_i(8))
|
258
|
+
end
|
259
|
+
|
260
|
+
# fallback to simple operation
|
261
|
+
actual.method(op).call(expected)
|
262
|
+
|
263
|
+
rescue NameError => _
|
264
|
+
false
|
265
|
+
rescue ArgumentError
|
266
|
+
false
|
267
|
+
end
|
268
|
+
|
269
|
+
match do |actual|
|
270
|
+
@operation ||= :==
|
271
|
+
@expected ||= first_expected
|
272
|
+
return actual === @expected if @operation == :=== # rubocop:disable Style/CaseEquality
|
273
|
+
actual = actual[0] if actual.is_a?(Array) && !@expected.is_a?(Array) && actual.length == 1
|
274
|
+
try_match(actual, @operation, @expected)
|
275
|
+
end
|
276
|
+
|
277
|
+
[:==, :<, :<=, :>=, :>, :===, :=~].each do |op|
|
278
|
+
chain(op) do |x|
|
279
|
+
@operation = op
|
280
|
+
@expected = x
|
262
281
|
end
|
263
282
|
end
|
264
283
|
|
265
284
|
failure_message do |actual|
|
266
285
|
actual = '0' + actual.to_s(8) if octal?(expected)
|
267
|
-
"\nexpected: #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
|
286
|
+
"\nexpected: value #{@operation} #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
|
268
287
|
end
|
269
288
|
|
270
289
|
failure_message_when_negated do |actual|
|
271
290
|
actual = '0' + actual.to_s(8) if octal?(expected)
|
272
|
-
"\nexpected: value
|
291
|
+
"\nexpected: value ! #{@operation} #{expected}\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
|
273
292
|
end
|
274
293
|
end
|
275
294
|
|
@@ -0,0 +1,186 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Thomas Cate
|
3
|
+
# license: All rights reserved
|
4
|
+
|
5
|
+
require 'utils/simpleconfig'
|
6
|
+
|
7
|
+
class GrubConfig < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
8
|
+
name 'grub_conf'
|
9
|
+
desc 'Use the grub_conf InSpec audit resource to test the boot config of Linux systems that use Grub.'
|
10
|
+
example "
|
11
|
+
describe grub_conf('/etc/grub.conf', 'default') do
|
12
|
+
its('kernel') { should include '/vmlinuz-2.6.32-573.7.1.el6.x86_64' }
|
13
|
+
its('initrd') { should include '/initramfs-2.6.32-573.el6.x86_64.img=1' }
|
14
|
+
its('default') { should_not eq '1' }
|
15
|
+
its('timeout') { should eq '5' }
|
16
|
+
end
|
17
|
+
|
18
|
+
also check specific kernels
|
19
|
+
describe grub_conf('/etc/grub.conf', 'CentOS (2.6.32-573.12.1.el6.x86_64)') do
|
20
|
+
its('kernel') { should include 'audit=1' }
|
21
|
+
end
|
22
|
+
"
|
23
|
+
|
24
|
+
def initialize(path = nil, kernel = nil)
|
25
|
+
family = inspec.os[:family]
|
26
|
+
case family
|
27
|
+
when 'redhat', 'fedora', 'centos'
|
28
|
+
release = inspec.os[:release].to_f
|
29
|
+
supported = true
|
30
|
+
if release < 7
|
31
|
+
@conf_path = path || '/etc/grub.conf'
|
32
|
+
@version = 'legacy'
|
33
|
+
else
|
34
|
+
@conf_path = path || '/boot/grub/grub.cfg'
|
35
|
+
@defaults_path = '/etc/default/grub'
|
36
|
+
@version = 'grub2'
|
37
|
+
end
|
38
|
+
when 'ubuntu'
|
39
|
+
@conf_path = path || '/boot/grub/grub.cfg'
|
40
|
+
@defaults_path = '/etc/default/grub'
|
41
|
+
@version = 'grub2'
|
42
|
+
supported = true
|
43
|
+
end
|
44
|
+
@kernel = kernel || 'default'
|
45
|
+
return skip_resource 'The `grub_config` resource is not supported on your OS yet.' if supported.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_missing(name)
|
49
|
+
read_params[name.to_s]
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
'Grub Config'
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
######################################################################
|
59
|
+
# Grub2 This is used by all supported versions of Ubuntu and Rhel 7+ #
|
60
|
+
######################################################################
|
61
|
+
|
62
|
+
def grub2_parse_kernel_lines(content, conf)
|
63
|
+
# Find all "menuentry" lines and then parse them into arrays
|
64
|
+
menu_entry = 0
|
65
|
+
lines = content.split("\n")
|
66
|
+
kernel_opts = {}
|
67
|
+
kernel_opts['insmod'] = []
|
68
|
+
lines.each_with_index do |file_line, index|
|
69
|
+
next unless file_line =~ /(^|\s)menuentry\s.*/
|
70
|
+
lines.drop(index+1).each do |kernel_line|
|
71
|
+
next if kernel_line =~ /(^|\s)(menu|}).*/
|
72
|
+
if menu_entry == conf['GRUB_DEFAULT'].to_i && @kernel == 'default'
|
73
|
+
if kernel_line =~ /(^|\s)initrd.*/
|
74
|
+
kernel_opts['initrd'] = kernel_line.split(' ')[1]
|
75
|
+
end
|
76
|
+
if kernel_line =~ /(^|\s)linux.*/
|
77
|
+
kernel_opts['kernel'] = kernel_line.split
|
78
|
+
end
|
79
|
+
if kernel_line =~ /(^|\s)set root=.*/
|
80
|
+
kernel_opts['root'] = kernel_line.split('=')[1].tr('\'', '')
|
81
|
+
end
|
82
|
+
if kernel_line =~ /(^|\s)insmod.*/
|
83
|
+
kernel_opts['insmod'].push(kernel_line.split(' ')[1])
|
84
|
+
end
|
85
|
+
else
|
86
|
+
menu_entry += 1
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
kernel_opts
|
92
|
+
end
|
93
|
+
|
94
|
+
###################################################################
|
95
|
+
# Grub1 aka legacy-grub config. Primarily used by Centos/Rhel 6.x #
|
96
|
+
###################################################################
|
97
|
+
|
98
|
+
def parse_kernel_lines(content, conf)
|
99
|
+
# Find all "title" lines and then parse them into arrays
|
100
|
+
menu_entry = 0
|
101
|
+
lines = content.split("\n")
|
102
|
+
kernel_opts = {}
|
103
|
+
lines.each_with_index do |file_line, index|
|
104
|
+
next unless file_line =~ /^title.*/
|
105
|
+
current_kernel = file_line.split(' ', 2)[1]
|
106
|
+
lines.drop(index+1).each do |kernel_line|
|
107
|
+
if kernel_line =~ /^\s.*/
|
108
|
+
option_type = kernel_line.split(' ')[0]
|
109
|
+
line_options = kernel_line.split(' ').drop(1)
|
110
|
+
if (menu_entry == conf['default'].to_i && @kernel == 'default') || current_kernel == @kernel
|
111
|
+
if option_type == 'kernel'
|
112
|
+
kernel_opts['kernel'] = line_options
|
113
|
+
else
|
114
|
+
kernel_opts[option_type] = line_options[0]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
else
|
118
|
+
menu_entry += 1
|
119
|
+
break
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
kernel_opts
|
124
|
+
end
|
125
|
+
|
126
|
+
def read_file(config_file)
|
127
|
+
file = inspec.file(config_file)
|
128
|
+
|
129
|
+
if !file.file? && !file.symlink?
|
130
|
+
skip_resource "Can't find file '#{@conf_path}'"
|
131
|
+
return @params = {}
|
132
|
+
end
|
133
|
+
|
134
|
+
content = file.content
|
135
|
+
|
136
|
+
if content.empty? && file.size > 0
|
137
|
+
skip_resource "Can't read file '#{@conf_path}'"
|
138
|
+
return @params = {}
|
139
|
+
end
|
140
|
+
|
141
|
+
content
|
142
|
+
end
|
143
|
+
|
144
|
+
def read_params
|
145
|
+
return @params if defined?(@params)
|
146
|
+
|
147
|
+
content = read_file(@conf_path)
|
148
|
+
|
149
|
+
if @version == 'legacy'
|
150
|
+
# parse the file
|
151
|
+
conf = SimpleConfig.new(
|
152
|
+
content,
|
153
|
+
multiple_values: true,
|
154
|
+
).params
|
155
|
+
# convert single entry arrays into strings
|
156
|
+
conf.each do |key, value|
|
157
|
+
if value.size == 1
|
158
|
+
conf[key] = conf[key][0].to_s
|
159
|
+
end
|
160
|
+
end
|
161
|
+
kernel_opts = parse_kernel_lines(content, conf)
|
162
|
+
@params = conf.merge(kernel_opts)
|
163
|
+
end
|
164
|
+
|
165
|
+
if @version == 'grub2'
|
166
|
+
# read defaults
|
167
|
+
defaults = read_file(@defaults_path)
|
168
|
+
|
169
|
+
conf = SimpleConfig.new(
|
170
|
+
defaults,
|
171
|
+
multiple_values: true,
|
172
|
+
).params
|
173
|
+
|
174
|
+
# convert single entry arrays into strings
|
175
|
+
conf.each do |key, value|
|
176
|
+
if value.size == 1
|
177
|
+
conf[key] = conf[key][0].to_s
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
kernel_opts = grub2_parse_kernel_lines(content, conf)
|
182
|
+
@params = conf.merge(kernel_opts)
|
183
|
+
end
|
184
|
+
@params
|
185
|
+
end
|
186
|
+
end
|
data/lib/resources/json.rb
CHANGED
@@ -10,7 +10,7 @@ module Inspec::Resources
|
|
10
10
|
desc 'Use the json InSpec audit resource to test data in a JSON file.'
|
11
11
|
example "
|
12
12
|
describe json('policyfile.lock.json') do
|
13
|
-
its('cookbook_locks
|
13
|
+
its(['cookbook_locks','omnibus','version']) { should eq('2.2.0') }
|
14
14
|
end
|
15
15
|
"
|
16
16
|
|
data/lib/resources/service.rb
CHANGED
@@ -94,7 +94,7 @@ module Inspec::Resources
|
|
94
94
|
return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
|
95
95
|
end
|
96
96
|
|
97
|
-
def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
97
|
+
def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
98
98
|
os = inspec.os
|
99
99
|
family = os[:family]
|
100
100
|
|
@@ -135,8 +135,14 @@ module Inspec::Resources
|
|
135
135
|
WindowsSrv.new(inspec)
|
136
136
|
elsif %w{freebsd}.include?(family)
|
137
137
|
BSDInit.new(inspec, service_ctl)
|
138
|
-
elsif %w{arch
|
138
|
+
elsif %w{arch}.include?(family)
|
139
139
|
Systemd.new(inspec, service_ctl)
|
140
|
+
elsif %w{suse opensuse}.include?(family)
|
141
|
+
if inspec.os[:release].to_i >= 12
|
142
|
+
Systemd.new(inspec, service_ctl)
|
143
|
+
else
|
144
|
+
SysV.new(inspec, service_ctl || '/sbin/service')
|
145
|
+
end
|
140
146
|
elsif %w{aix}.include?(family)
|
141
147
|
SrcMstr.new(inspec)
|
142
148
|
elsif %w{amazon}.include?(family)
|
@@ -214,7 +220,7 @@ module Inspec::Resources
|
|
214
220
|
running = params['SubState'] == 'running'
|
215
221
|
# test via systemctl --quiet is-enabled
|
216
222
|
# ActiveState values eg.g inactive, active
|
217
|
-
enabled = params['UnitFileState']
|
223
|
+
enabled = %w{enabled static}.include? params['UnitFileState']
|
218
224
|
|
219
225
|
{
|
220
226
|
name: params['Id'],
|
data/lib/utils/base_cli.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
class HashMap
|
6
|
+
class << self
|
7
|
+
def [](hash, *keys)
|
8
|
+
return hash if keys.empty? || hash.nil?
|
9
|
+
key = keys.shift
|
10
|
+
if hash.is_a?(Array)
|
11
|
+
map = hash.map { |i| [i, key] }
|
12
|
+
else
|
13
|
+
map = hash[key]
|
14
|
+
end
|
15
|
+
[map, *keys]
|
16
|
+
rescue NoMethodError => _
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class StringMap
|
23
|
+
class << self
|
24
|
+
def [](hash, *keys)
|
25
|
+
return hash if keys.empty? || hash.nil?
|
26
|
+
key = keys.shift
|
27
|
+
if hash.is_a?(Array)
|
28
|
+
map = hash.map { |i| [i, key] }
|
29
|
+
else
|
30
|
+
map = hash[key]
|
31
|
+
end
|
32
|
+
[map, *keys]
|
33
|
+
rescue NoMethodError => _
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|