inspec 1.48.0 → 1.49.2
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/.rubocop.yml +4 -0
- data/CHANGELOG.md +40 -16
- data/Rakefile +1 -1
- data/docs/resources/bond.md.erb +6 -1
- data/docs/resources/mysql_session.md.erb +24 -12
- data/docs/resources/passwd.md.erb +1 -1
- data/docs/resources/xml.md.erb +7 -2
- data/docs/shell.md +22 -0
- data/inspec.gemspec +1 -1
- data/lib/bundles/inspec-artifact/cli.rb +0 -2
- data/lib/bundles/inspec-compliance/api.rb +58 -3
- data/lib/bundles/inspec-compliance/cli.rb +1 -1
- data/lib/bundles/inspec-habitat/profile.rb +1 -1
- data/lib/fetchers/url.rb +1 -1
- data/lib/inspec/base_cli.rb +3 -1
- data/lib/inspec/cli.rb +11 -1
- data/lib/inspec/control_eval_context.rb +13 -2
- data/lib/inspec/dependencies/lockfile.rb +0 -2
- data/lib/inspec/dsl_shared.rb +8 -0
- data/lib/inspec/library_eval_context.rb +12 -1
- data/lib/inspec/metadata.rb +13 -44
- data/lib/inspec/objects/attribute.rb +1 -1
- data/lib/inspec/plugins/resource.rb +18 -2
- data/lib/inspec/profile.rb +17 -11
- data/lib/inspec/profile_context.rb +9 -3
- data/lib/inspec/profile_vendor.rb +1 -1
- data/lib/inspec/resource.rb +5 -0
- data/lib/inspec/rspec_json_formatter.rb +3 -3
- data/lib/inspec/rule.rb +1 -1
- data/lib/inspec/runner.rb +13 -5
- data/lib/inspec/schema.rb +1 -1
- data/lib/inspec/shell.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/aide_conf.rb +0 -2
- data/lib/resources/apache_conf.rb +9 -2
- data/lib/resources/auditd.rb +0 -1
- data/lib/resources/auditd_rules.rb +0 -2
- data/lib/resources/bond.rb +4 -0
- data/lib/resources/crontab.rb +1 -1
- data/lib/resources/docker.rb +1 -1
- data/lib/resources/elasticsearch.rb +1 -1
- data/lib/resources/file.rb +2 -0
- data/lib/resources/groups.rb +29 -5
- data/lib/resources/grub_conf.rb +1 -1
- data/lib/resources/os.rb +8 -20
- data/lib/resources/package.rb +20 -21
- data/lib/resources/platform.rb +112 -0
- data/lib/resources/port.rb +1 -1
- data/lib/resources/processes.rb +1 -1
- data/lib/resources/registry_key.rb +1 -1
- data/lib/resources/service.rb +1 -1
- data/lib/resources/virtualization.rb +1 -1
- data/lib/resources/x509_certificate.rb +1 -1
- data/lib/resources/xml.rb +1 -0
- metadata +5 -10
data/lib/inspec/schema.rb
CHANGED
data/lib/inspec/shell.rb
CHANGED
@@ -9,7 +9,7 @@ module Inspec
|
|
9
9
|
# A pry based shell for inspec. Given a runner (with a configured backend and
|
10
10
|
# all that jazz), this shell will produce a pry shell from which you can run
|
11
11
|
# inspec/ruby commands that will be run within the context of the runner.
|
12
|
-
class Shell
|
12
|
+
class Shell
|
13
13
|
def initialize(runner)
|
14
14
|
@runner = runner
|
15
15
|
end
|
data/lib/inspec/version.rb
CHANGED
data/lib/resources/aide_conf.rb
CHANGED
@@ -78,10 +78,17 @@ module Inspec::Resources
|
|
78
78
|
raw_conf = read_file(to_read[0])
|
79
79
|
@content += raw_conf
|
80
80
|
|
81
|
-
#
|
81
|
+
# An explaination of the below regular expression.
|
82
|
+
# Creates two capture groups.
|
83
|
+
# The first group captures the first group of non-whitespace character
|
84
|
+
# surrounded whitespace characters.
|
85
|
+
# The second group contains a conditional with a positive lookahead
|
86
|
+
# (does the line end with one or more spaces?). If the lookahead succeeds
|
87
|
+
# a non-greedy capture takes place, if it fails then a greedy capture takes place.
|
88
|
+
# The regex is terminated by an expression that matches zero or more spaces.
|
82
89
|
params = SimpleConfig.new(
|
83
90
|
raw_conf,
|
84
|
-
assignment_regex: /^\s*(\S+)\s+(
|
91
|
+
assignment_regex: /^\s*(\S+)\s+((?=.*\s+$).*?|.*)\s*$/,
|
85
92
|
multiple_values: true,
|
86
93
|
).params
|
87
94
|
@params.merge!(params)
|
data/lib/resources/auditd.rb
CHANGED
data/lib/resources/bond.rb
CHANGED
data/lib/resources/crontab.rb
CHANGED
@@ -4,7 +4,7 @@ require 'utils/parser'
|
|
4
4
|
require 'utils/filter'
|
5
5
|
|
6
6
|
module Inspec::Resources
|
7
|
-
class Crontab < Inspec.resource(1)
|
7
|
+
class Crontab < Inspec.resource(1)
|
8
8
|
name 'crontab'
|
9
9
|
desc 'Use the crontab InSpec audit resource to test the contents of the crontab for a given user which contains information about scheduled tasks owned by that user.'
|
10
10
|
example "
|
data/lib/resources/docker.rb
CHANGED
@@ -63,7 +63,7 @@ module Inspec::Resources
|
|
63
63
|
# For compatability with Serverspec we also offer the following resouses:
|
64
64
|
# - docker_container
|
65
65
|
# - docker_image
|
66
|
-
class Docker < Inspec.resource(1)
|
66
|
+
class Docker < Inspec.resource(1)
|
67
67
|
name 'docker'
|
68
68
|
|
69
69
|
desc "
|
@@ -5,7 +5,7 @@ require 'hashie/mash'
|
|
5
5
|
require 'resources/package'
|
6
6
|
|
7
7
|
module Inspec::Resources
|
8
|
-
class Elasticsearch < Inspec.resource(1)
|
8
|
+
class Elasticsearch < Inspec.resource(1)
|
9
9
|
name 'elasticsearch'
|
10
10
|
desc "Use the Elasticsearch InSpec audit resource to test the status of nodes in
|
11
11
|
an Elasticsearch cluster."
|
data/lib/resources/file.rb
CHANGED
@@ -269,6 +269,8 @@ module Inspec::Resources
|
|
269
269
|
translate_perm_names('full-control') + %w{ChangePermissions}
|
270
270
|
when 'take-ownership'
|
271
271
|
translate_perm_names('full-control') + %w{TakeOwnership}
|
272
|
+
when 'synchronize'
|
273
|
+
translate_perm_names('full-control') + %w{Synchronize}
|
272
274
|
end
|
273
275
|
end
|
274
276
|
|
data/lib/resources/groups.rb
CHANGED
@@ -13,11 +13,13 @@ module Inspec::Resources
|
|
13
13
|
# select group provider based on the operating system
|
14
14
|
# returns nil, if no group manager was found for the operating system
|
15
15
|
def select_group_manager(os)
|
16
|
-
if os.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
@group_provider = if os.darwin?
|
17
|
+
DarwinGroup.new(inspec)
|
18
|
+
elsif os.unix?
|
19
|
+
UnixGroup.new(inspec)
|
20
|
+
elsif os.windows?
|
21
|
+
WindowsGroup.new(inspec)
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
@@ -154,6 +156,28 @@ module Inspec::Resources
|
|
154
156
|
end
|
155
157
|
end
|
156
158
|
|
159
|
+
# OSX uses opendirectory for groups, so `/etc/group` may not be fully accurate
|
160
|
+
# This uses `dscacheutil` to get the group info instead of `etc_group`
|
161
|
+
class DarwinGroup < GroupInfo
|
162
|
+
def groups
|
163
|
+
group_info = inspec.command('dscacheutil -q group').stdout.split("\n\n")
|
164
|
+
|
165
|
+
groups = []
|
166
|
+
regex = /^([^:]*?)\s*:\s(.*?)\s*$/
|
167
|
+
group_info.each do |data|
|
168
|
+
groups << inspec.parse_config(data, assignment_regex: regex).params
|
169
|
+
end
|
170
|
+
|
171
|
+
# Convert the `dscacheutil` groups to match `inspec.etc_group.entries`
|
172
|
+
groups.each { |g| g['gid'] = g['gid'].to_i }
|
173
|
+
groups.each do |g|
|
174
|
+
next if g['users'].nil?
|
175
|
+
g['members'] = g.delete('users')
|
176
|
+
g['members'].tr!(' ', ',')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
157
181
|
class WindowsGroup < GroupInfo
|
158
182
|
# returns all local groups
|
159
183
|
def groups
|
data/lib/resources/grub_conf.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'utils/simpleconfig'
|
5
5
|
|
6
|
-
class GrubConfig < Inspec.resource(1)
|
6
|
+
class GrubConfig < Inspec.resource(1)
|
7
7
|
name 'grub_conf'
|
8
8
|
desc 'Use the grub_conf InSpec audit resource to test the boot config of Linux systems that use Grub.'
|
9
9
|
example "
|
data/lib/resources/os.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
# author: Dominik Richter
|
3
3
|
# author: Christoph Hartmann
|
4
4
|
|
5
|
+
require 'resources/platform'
|
6
|
+
|
5
7
|
module Inspec::Resources
|
6
|
-
class OSResource <
|
8
|
+
class OSResource < PlatformResource
|
7
9
|
name 'os'
|
8
10
|
desc 'Use the os InSpec audit resource to test the platform on which the system is running.'
|
9
11
|
example "
|
@@ -23,31 +25,17 @@ module Inspec::Resources
|
|
23
25
|
# reuse helper methods from backend
|
24
26
|
%w{aix? redhat? debian? suse? bsd? solaris? linux? unix? windows? hpux? darwin?}.each do |os_family|
|
25
27
|
define_method(os_family.to_sym) do
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def [](name)
|
31
|
-
# convert string to symbol
|
32
|
-
name = name.to_sym if name.is_a? String
|
33
|
-
inspec.backend.os[name]
|
34
|
-
end
|
35
|
-
|
36
|
-
# add helper methods for easy access of properties
|
37
|
-
# allows users to use os.name, os.family, os.release, os.arch
|
38
|
-
%w{name family release arch}.each do |property|
|
39
|
-
define_method(property.to_sym) do
|
40
|
-
inspec.backend.os[property.to_sym]
|
28
|
+
@platform.send(os_family)
|
41
29
|
end
|
42
30
|
end
|
43
31
|
|
44
32
|
# helper to collect a hash object easily
|
45
33
|
def params
|
46
34
|
{
|
47
|
-
name:
|
48
|
-
family:
|
49
|
-
release:
|
50
|
-
arch:
|
35
|
+
name: name,
|
36
|
+
family: @platform[:family],
|
37
|
+
release: @platform[:release],
|
38
|
+
arch: @platform[:arch],
|
51
39
|
}
|
52
40
|
end
|
53
41
|
|
data/lib/resources/package.rb
CHANGED
@@ -20,7 +20,7 @@ module Inspec::Resources
|
|
20
20
|
end
|
21
21
|
"
|
22
22
|
|
23
|
-
def initialize(package_name
|
23
|
+
def initialize(package_name, opts = {}) # rubocop:disable Metrics/AbcSize
|
24
24
|
@package_name = package_name
|
25
25
|
@name = @package_name
|
26
26
|
@cache = nil
|
@@ -45,7 +45,7 @@ module Inspec::Resources
|
|
45
45
|
elsif ['hpux'].include?(os[:family])
|
46
46
|
@pkgman = HpuxPkg.new(inspec)
|
47
47
|
else
|
48
|
-
|
48
|
+
raise Inspec::Exceptions::ResourceSkipped, 'The `package` resource is not supported on your OS yet.'
|
49
49
|
end
|
50
50
|
|
51
51
|
evaluate_missing_requirements
|
@@ -53,28 +53,23 @@ module Inspec::Resources
|
|
53
53
|
|
54
54
|
# returns true if the package is installed
|
55
55
|
def installed?(_provider = nil, _version = nil)
|
56
|
-
return false if info.nil?
|
57
56
|
info[:installed] == true
|
58
57
|
end
|
59
58
|
|
60
59
|
# returns true it the package is held (if the OS supports it)
|
61
60
|
def held?(_provider = nil, _version = nil)
|
62
|
-
return false if info.nil?
|
63
|
-
return false unless info.key?(:held)
|
64
61
|
info[:held] == true
|
65
62
|
end
|
66
63
|
|
67
64
|
# returns the package description
|
68
65
|
def info
|
69
66
|
return @cache if !@cache.nil?
|
70
|
-
return nil if @pkgman.nil?
|
71
67
|
@pkgman.info(@package_name)
|
72
68
|
end
|
73
69
|
|
74
70
|
# return the package version
|
75
71
|
def version
|
76
72
|
info = @pkgman.info(@package_name)
|
77
|
-
return nil if info.nil?
|
78
73
|
info[:version]
|
79
74
|
end
|
80
75
|
|
@@ -87,7 +82,7 @@ module Inspec::Resources
|
|
87
82
|
def evaluate_missing_requirements
|
88
83
|
missing_requirements_string = @pkgman.missing_requirements.uniq.join(', ')
|
89
84
|
return if missing_requirements_string.empty?
|
90
|
-
|
85
|
+
raise Inspec::Exceptions::ResourceSkipped, "The following requirements are not met for this resource: #{missing_requirements_string}"
|
91
86
|
end
|
92
87
|
end
|
93
88
|
|
@@ -99,7 +94,7 @@ module Inspec::Resources
|
|
99
94
|
|
100
95
|
def missing_requirements
|
101
96
|
# Each provider can provide an Array of missing requirements that will be
|
102
|
-
# combined into a `
|
97
|
+
# combined into a `ResourceSkipped` exception message.
|
103
98
|
[]
|
104
99
|
end
|
105
100
|
end
|
@@ -108,7 +103,7 @@ module Inspec::Resources
|
|
108
103
|
class Deb < PkgManagement
|
109
104
|
def info(package_name)
|
110
105
|
cmd = inspec.command("dpkg -s #{package_name}")
|
111
|
-
return
|
106
|
+
return {} if cmd.exit_status.to_i != 0
|
112
107
|
|
113
108
|
params = SimpleConfig.new(
|
114
109
|
cmd.stdout.chomp,
|
@@ -152,7 +147,7 @@ module Inspec::Resources
|
|
152
147
|
cmd = inspec.command(rpm_cmd)
|
153
148
|
# CentOS does not return an error code if the package is not installed,
|
154
149
|
# therefore we need to check for emptyness
|
155
|
-
return
|
150
|
+
return {} if cmd.exit_status.to_i != 0 || cmd.stdout.chomp.empty?
|
156
151
|
params = SimpleConfig.new(
|
157
152
|
cmd.stdout.chomp,
|
158
153
|
assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
@@ -195,7 +190,7 @@ module Inspec::Resources
|
|
195
190
|
def info(package_name)
|
196
191
|
brew_path = inspec.command('brew').exist? ? 'brew' : '/usr/local/bin/brew'
|
197
192
|
cmd = inspec.command("#{brew_path} info --json=v1 #{package_name}")
|
198
|
-
return
|
193
|
+
return {} if cmd.exit_status.to_i != 0
|
199
194
|
# parse data
|
200
195
|
pkg = JSON.parse(cmd.stdout)[0]
|
201
196
|
{
|
@@ -204,8 +199,10 @@ module Inspec::Resources
|
|
204
199
|
version: pkg['installed'][0]['version'],
|
205
200
|
type: 'brew',
|
206
201
|
}
|
207
|
-
rescue JSON::ParserError =>
|
208
|
-
|
202
|
+
rescue JSON::ParserError => e
|
203
|
+
raise Inspec::Exceptions::ResourceFailed,
|
204
|
+
'Failed to parse JSON from `brew` command. ' \
|
205
|
+
"Error: #{e}"
|
209
206
|
end
|
210
207
|
end
|
211
208
|
|
@@ -213,7 +210,7 @@ module Inspec::Resources
|
|
213
210
|
class Pacman < PkgManagement
|
214
211
|
def info(package_name)
|
215
212
|
cmd = inspec.command("pacman -Qi #{package_name}")
|
216
|
-
return
|
213
|
+
return {} if cmd.exit_status.to_i != 0
|
217
214
|
|
218
215
|
params = SimpleConfig.new(
|
219
216
|
cmd.stdout.chomp,
|
@@ -233,7 +230,7 @@ module Inspec::Resources
|
|
233
230
|
class HpuxPkg < PkgManagement
|
234
231
|
def info(package_name)
|
235
232
|
cmd = inspec.command("swlist -l product | grep #{package_name}")
|
236
|
-
return
|
233
|
+
return {} if cmd.exit_status.to_i != 0
|
237
234
|
pkg = cmd.stdout.strip.split(' ')
|
238
235
|
{
|
239
236
|
name: pkg[0],
|
@@ -268,8 +265,10 @@ module Inspec::Resources
|
|
268
265
|
|
269
266
|
begin
|
270
267
|
package = JSON.parse(cmd.stdout)
|
271
|
-
rescue JSON::ParserError =>
|
272
|
-
|
268
|
+
rescue JSON::ParserError => e
|
269
|
+
raise Inspec::Exceptions::ResourceFailed,
|
270
|
+
'Failed to parse JSON from PowerShell. ' \
|
271
|
+
"Error: #{e}"
|
273
272
|
end
|
274
273
|
|
275
274
|
# What if we match multiple packages? just pick the first one for now.
|
@@ -288,7 +287,7 @@ module Inspec::Resources
|
|
288
287
|
class BffPkg < PkgManagement
|
289
288
|
def info(package_name)
|
290
289
|
cmd = inspec.command("lslpp -cL #{package_name}")
|
291
|
-
return
|
290
|
+
return {} if cmd.exit_status.to_i != 0
|
292
291
|
|
293
292
|
bff_pkg = cmd.stdout.split("\n").last.split(':')
|
294
293
|
{
|
@@ -313,7 +312,7 @@ module Inspec::Resources
|
|
313
312
|
# solaris 10
|
314
313
|
def solaris10_info(package_name)
|
315
314
|
cmd = inspec.command("pkginfo -l #{package_name}")
|
316
|
-
return
|
315
|
+
return {} if cmd.exit_status.to_i != 0
|
317
316
|
|
318
317
|
params = SimpleConfig.new(
|
319
318
|
cmd.stdout.chomp,
|
@@ -334,7 +333,7 @@ module Inspec::Resources
|
|
334
333
|
# solaris 11
|
335
334
|
def solaris11_info(package_name)
|
336
335
|
cmd = inspec.command("pkg info #{package_name}")
|
337
|
-
return
|
336
|
+
return {} if cmd.exit_status.to_i != 0
|
338
337
|
|
339
338
|
params = SimpleConfig.new(
|
340
339
|
cmd.stdout.chomp,
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Inspec::Resources
|
4
|
+
class PlatformResource < Inspec.resource(1)
|
5
|
+
name 'platform'
|
6
|
+
desc 'Use the platform InSpec resource to test the platform on which the system is running.'
|
7
|
+
example "
|
8
|
+
describe platform do
|
9
|
+
its('name') { should eq 'redhat' }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe platform do
|
13
|
+
it { should be_in_family('unix') }
|
14
|
+
end
|
15
|
+
"
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@platform = inspec.backend.os
|
19
|
+
end
|
20
|
+
|
21
|
+
# add helper methods for easy access of properties
|
22
|
+
%w{family release arch}.each do |property|
|
23
|
+
define_method(property.to_sym) do
|
24
|
+
@platform.send(property)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# This is a string override for platform.name.
|
29
|
+
# TODO: removed in inspec 2.0
|
30
|
+
class NameCleaned < String
|
31
|
+
def ==(other)
|
32
|
+
if other =~ /[A-Z ]/
|
33
|
+
cleaned = other.downcase.tr(' ', '_')
|
34
|
+
Inspec::Log.warn "[DEPRECATED] Platform names will become lowercase in InSpec 2.0. Please match on '#{cleaned}' instead of '#{other}'"
|
35
|
+
super(cleaned)
|
36
|
+
else
|
37
|
+
super(other)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
NameCleaned.new(@platform.name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
# convert string to symbol
|
48
|
+
key = key.to_sym if key.is_a? String
|
49
|
+
return name if key == :name
|
50
|
+
|
51
|
+
@platform[key]
|
52
|
+
end
|
53
|
+
|
54
|
+
def platform?(name)
|
55
|
+
@platform.name == name ||
|
56
|
+
@platform.family_hierarchy.include?(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def in_family?(family)
|
60
|
+
@platform.family_hierarchy.include?(family)
|
61
|
+
end
|
62
|
+
|
63
|
+
def families
|
64
|
+
@platform.family_hierarchy
|
65
|
+
end
|
66
|
+
|
67
|
+
def supported?(supports)
|
68
|
+
return true if supports.nil? || supports.empty?
|
69
|
+
|
70
|
+
status = true
|
71
|
+
supports.each do |s|
|
72
|
+
s.each do |k, v|
|
73
|
+
# ignore the inspec check for supports
|
74
|
+
# TODO: remove in inspec 2.0
|
75
|
+
if k == :inspec
|
76
|
+
next
|
77
|
+
elsif %i(os_family os-family platform_family platform-family).include?(k)
|
78
|
+
status = in_family?(v)
|
79
|
+
elsif %i(os platform).include?(k)
|
80
|
+
status = platform?(v)
|
81
|
+
elsif %i(os_name os-name platform_name platform-name).include?(k)
|
82
|
+
status = name == v
|
83
|
+
elsif k == :release
|
84
|
+
status = check_release(v)
|
85
|
+
else
|
86
|
+
status = false
|
87
|
+
end
|
88
|
+
break if status == false
|
89
|
+
end
|
90
|
+
return true if status == true
|
91
|
+
end
|
92
|
+
|
93
|
+
status
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_s
|
97
|
+
'Platform Detection'
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def check_release(value)
|
103
|
+
# allow wild card matching
|
104
|
+
if value.include?('*')
|
105
|
+
cleaned = Regexp.escape(value).gsub('\*', '.*?')
|
106
|
+
!(release =~ /#{cleaned}/).nil?
|
107
|
+
else
|
108
|
+
release == value
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|