inspec 0.14.8 → 0.15.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 +25 -2
- data/bin/inspec +3 -4
- data/examples/inheritance/README.md +19 -0
- data/examples/inheritance/controls/example.rb +11 -0
- data/examples/inheritance/inspec.yml +10 -0
- data/lib/bundles/inspec-compliance/cli.rb +1 -4
- data/lib/bundles/inspec-supermarket/cli.rb +1 -4
- data/lib/inspec/dsl.rb +48 -55
- data/lib/inspec/profile.rb +6 -2
- data/lib/inspec/profile_context.rb +21 -8
- data/lib/inspec/runner.rb +17 -12
- data/lib/inspec/runner_rspec.rb +1 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/resources/apache.rb +20 -18
- data/lib/resources/apache_conf.rb +92 -90
- data/lib/resources/apt.rb +92 -90
- data/lib/resources/audit_policy.rb +35 -33
- data/lib/resources/auditd_conf.rb +41 -39
- data/lib/resources/auditd_rules.rb +155 -153
- data/lib/resources/bond.rb +1 -1
- data/lib/resources/bridge.rb +97 -95
- data/lib/resources/command.rb +47 -45
- data/lib/resources/csv.rb +23 -21
- data/lib/resources/directory.rb +1 -1
- data/lib/resources/etc_group.rb +116 -114
- data/lib/resources/file.rb +1 -1
- data/lib/resources/gem.rb +39 -37
- data/lib/resources/group.rb +100 -98
- data/lib/resources/host.rb +103 -101
- data/lib/resources/inetd_conf.rb +42 -40
- data/lib/resources/ini.rb +15 -13
- data/lib/resources/interface.rb +106 -104
- data/lib/resources/iptables.rb +36 -34
- data/lib/resources/json.rb +64 -62
- data/lib/resources/kernel_module.rb +30 -28
- data/lib/resources/kernel_parameter.rb +44 -42
- data/lib/resources/limits_conf.rb +41 -39
- data/lib/resources/login_def.rb +38 -36
- data/lib/resources/mount.rb +43 -41
- data/lib/resources/mysql.rb +67 -65
- data/lib/resources/mysql_conf.rb +89 -87
- data/lib/resources/mysql_session.rb +46 -44
- data/lib/resources/npm.rb +35 -33
- data/lib/resources/ntp_conf.rb +44 -42
- data/lib/resources/oneget.rb +46 -44
- data/lib/resources/os.rb +22 -20
- data/lib/resources/os_env.rb +47 -45
- data/lib/resources/package.rb +213 -211
- data/lib/resources/parse_config.rb +59 -57
- data/lib/resources/passwd.rb +89 -87
- data/lib/resources/pip.rb +60 -58
- data/lib/resources/port.rb +352 -350
- data/lib/resources/postgres.rb +26 -24
- data/lib/resources/postgres_conf.rb +66 -64
- data/lib/resources/postgres_session.rb +47 -45
- data/lib/resources/processes.rb +56 -54
- data/lib/resources/registry_key.rb +150 -148
- data/lib/resources/script.rb +30 -28
- data/lib/resources/security_policy.rb +56 -54
- data/lib/resources/service.rb +638 -636
- data/lib/resources/shadow.rb +98 -96
- data/lib/resources/ssh_conf.rb +58 -56
- data/lib/resources/user.rb +363 -361
- data/lib/resources/windows_feature.rb +46 -44
- data/lib/resources/xinetd.rb +111 -109
- data/lib/resources/yaml.rb +16 -14
- data/lib/resources/yum.rb +107 -105
- data/lib/utils/base_cli.rb +18 -0
- data/test/helper.rb +2 -2
- data/test/unit/profile_context_test.rb +1 -1
- data/test/unit/resources/file_test.rb +1 -1
- data/test/unit/resources/mount_test.rb +1 -1
- metadata +5 -2
@@ -13,77 +13,79 @@
|
|
13
13
|
# }
|
14
14
|
# describe parse_config(audit, options ) do
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
module Inspec::Resources
|
17
|
+
class PConfig < Inspec.resource(1)
|
18
|
+
name 'parse_config'
|
19
|
+
desc 'Use the parse_config InSpec audit resource to test arbitrary configuration files.'
|
20
|
+
example "
|
21
|
+
output = command('some-command').stdout
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
describe parse_config(output, { data_config_option: value } ) do
|
24
|
+
its('setting') { should eq 1 }
|
25
|
+
end
|
26
|
+
"
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
def initialize(content = nil, useropts = nil)
|
29
|
+
@opts = {}
|
30
|
+
@opts = useropts.dup unless useropts.nil?
|
31
|
+
@files_contents = {}
|
32
|
+
@params = nil
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
@content = content
|
35
|
+
read_content if @content.nil?
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
def method_missing(name)
|
39
|
+
@params || read_content
|
40
|
+
@params[name.to_s]
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
def parse_file(conf_path)
|
44
|
+
@conf_path = conf_path
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
# read the file
|
47
|
+
if !inspec.file(conf_path).file?
|
48
|
+
return skip_resource "Can't find file \"#{conf_path}\""
|
49
|
+
end
|
50
|
+
@content = read_file(conf_path)
|
51
|
+
if @content.empty? && inspec.file(conf_path).size > 0
|
52
|
+
return skip_resource "Can't read file \"#{conf_path}\""
|
53
|
+
end
|
54
|
+
|
55
|
+
read_content
|
52
56
|
end
|
53
57
|
|
54
|
-
|
55
|
-
|
58
|
+
def read_file(path)
|
59
|
+
@files_contents[path] ||= inspec.file(path).content
|
60
|
+
end
|
56
61
|
|
57
|
-
|
58
|
-
|
59
|
-
|
62
|
+
def read_content
|
63
|
+
# parse the file
|
64
|
+
@params = SimpleConfig.new(@content, @opts).params
|
65
|
+
@content
|
66
|
+
end
|
60
67
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
@content
|
68
|
+
def to_s
|
69
|
+
"Parse Config #{@conf_path}"
|
70
|
+
end
|
65
71
|
end
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
73
|
+
class PConfigFile < PConfig
|
74
|
+
name 'parse_config_file'
|
75
|
+
desc 'Use the parse_config_file InSpec audit resource to test arbitrary configuration files. It works identiacal to parse_config. Instead of using a command output, this resource works with files.'
|
76
|
+
example "
|
77
|
+
describe parse_config_file('/path/to/file') do
|
78
|
+
its('setting') { should eq 1 }
|
79
|
+
end
|
80
|
+
"
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
example "
|
76
|
-
describe parse_config_file('/path/to/file') do
|
77
|
-
its('setting') { should eq 1 }
|
82
|
+
def initialize(path, opts = nil)
|
83
|
+
super(nil, opts)
|
84
|
+
parse_file(path)
|
78
85
|
end
|
79
|
-
"
|
80
|
-
|
81
|
-
def initialize(path, opts = nil)
|
82
|
-
super(nil, opts)
|
83
|
-
parse_file(path)
|
84
|
-
end
|
85
86
|
|
86
|
-
|
87
|
-
|
87
|
+
def to_s
|
88
|
+
"Parse Config File #{@conf_path}"
|
89
|
+
end
|
88
90
|
end
|
89
91
|
end
|
data/lib/resources/passwd.rb
CHANGED
@@ -15,112 +15,114 @@
|
|
15
15
|
|
16
16
|
require 'utils/parser'
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
module Inspec::Resources
|
19
|
+
class Passwd < Inspec.resource(1)
|
20
|
+
name 'passwd'
|
21
|
+
desc 'Use the passwd InSpec audit resource to test the contents of /etc/passwd, which contains the following information for users that may log into the system and/or as users that own running processes.'
|
22
|
+
example "
|
23
|
+
describe passwd do
|
24
|
+
its('users') { should_not include 'forbidden_user' }
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
describe passwd.uids(0) do
|
28
|
+
its('users') { should cmp 'root' }
|
29
|
+
its('count') { should eq 1 }
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
describe passwd.shells(/nologin/) do
|
33
|
+
# find all users with a nologin shell
|
34
|
+
its('users') { should_not include 'my_login_user' }
|
35
|
+
end
|
36
|
+
"
|
37
|
+
|
38
|
+
include PasswdParser
|
39
|
+
|
40
|
+
attr_reader :uid
|
41
|
+
attr_reader :params
|
42
|
+
attr_reader :content
|
43
|
+
attr_reader :lines
|
44
|
+
|
45
|
+
def initialize(path = nil, opts = nil)
|
46
|
+
opts ||= {}
|
47
|
+
@path = path || '/etc/passwd'
|
48
|
+
@content = opts[:content] || inspec.file(@path).content
|
49
|
+
@lines = @content.to_s.split("\n")
|
50
|
+
@filters = opts[:filters] || ''
|
51
|
+
@params = parse_passwd(@content)
|
34
52
|
end
|
35
|
-
"
|
36
|
-
|
37
|
-
include PasswdParser
|
38
|
-
|
39
|
-
attr_reader :uid
|
40
|
-
attr_reader :params
|
41
|
-
attr_reader :content
|
42
|
-
attr_reader :lines
|
43
|
-
|
44
|
-
def initialize(path = nil, opts = nil)
|
45
|
-
opts ||= {}
|
46
|
-
@path = path || '/etc/passwd'
|
47
|
-
@content = opts[:content] || inspec.file(@path).content
|
48
|
-
@lines = @content.to_s.split("\n")
|
49
|
-
@filters = opts[:filters] || ''
|
50
|
-
@params = parse_passwd(@content)
|
51
|
-
end
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
def filter(hm = {})
|
55
|
+
return self if hm.nil? || hm.empty?
|
56
|
+
res = @params
|
57
|
+
filters = ''
|
58
|
+
hm.each do |attr, condition|
|
59
|
+
condition = condition.to_s if condition.is_a? Integer
|
60
|
+
filters += " #{attr} = #{condition.inspect}"
|
61
|
+
res = res.find_all do |line|
|
62
|
+
case line[attr.to_s]
|
63
|
+
when condition
|
64
|
+
true
|
65
|
+
else
|
66
|
+
false
|
67
|
+
end
|
66
68
|
end
|
67
69
|
end
|
70
|
+
content = res.map { |x| x.values.join(':') }.join("\n")
|
71
|
+
Passwd.new(@path, content: content, filters: @filters + filters)
|
68
72
|
end
|
69
|
-
content = res.map { |x| x.values.join(':') }.join("\n")
|
70
|
-
Passwd.new(@path, content: content, filters: @filters + filters)
|
71
|
-
end
|
72
73
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
def usernames
|
75
|
+
warn '[DEPRECATION] `passwd.usernames` is deprecated. Please use `passwd.users` instead. It will be removed in version 1.0.0.'
|
76
|
+
users
|
77
|
+
end
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
def username
|
80
|
+
warn '[DEPRECATION] `passwd.user` is deprecated. Please use `passwd.users` instead. It will be removed in version 1.0.0.'
|
81
|
+
users[0]
|
82
|
+
end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
def uid(x)
|
85
|
+
warn '[DEPRECATION] `passwd.uid(arg)` is deprecated. Please use `passwd.uids(arg)` instead. It will be removed in version 1.0.0.'
|
86
|
+
uids(x)
|
87
|
+
end
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
89
|
+
def users(name = nil)
|
90
|
+
name.nil? ? map_data('user') : filter(user: name)
|
91
|
+
end
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
def passwords(password = nil)
|
94
|
+
password.nil? ? map_data('password') : filter(password: password)
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
def uids(uid = nil)
|
98
|
+
uid.nil? ? map_data('uid') : filter(uid: uid)
|
99
|
+
end
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
def gids(gid = nil)
|
102
|
+
gid.nil? ? map_data('gid') : filter(gid: gid)
|
103
|
+
end
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
def homes(home = nil)
|
106
|
+
home.nil? ? map_data('home') : filter(home: home)
|
107
|
+
end
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
109
|
+
def shells(shell = nil)
|
110
|
+
shell.nil? ? map_data('shell') : filter(shell: shell)
|
111
|
+
end
|
111
112
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
def to_s
|
114
|
+
f = @filters.empty? ? '' : ' with'+@filters
|
115
|
+
"/etc/passwd#{f}"
|
116
|
+
end
|
116
117
|
|
117
|
-
|
118
|
-
|
119
|
-
|
118
|
+
def count
|
119
|
+
@params.length
|
120
|
+
end
|
120
121
|
|
121
|
-
|
122
|
+
private
|
122
123
|
|
123
|
-
|
124
|
-
|
124
|
+
def map_data(id)
|
125
|
+
@params.map { |x| x[id] }
|
126
|
+
end
|
125
127
|
end
|
126
128
|
end
|
data/lib/resources/pip.rb
CHANGED
@@ -7,75 +7,77 @@
|
|
7
7
|
# it { should be_installed }
|
8
8
|
# end
|
9
9
|
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
module Inspec::Resources
|
11
|
+
class PipPackage < Inspec.resource(1)
|
12
|
+
name 'pip'
|
13
|
+
desc 'Use the pip InSpec audit resource to test packages that are installed using the pip installer.'
|
14
|
+
example "
|
15
|
+
describe pip('Jinja2') do
|
16
|
+
it { should be_installed }
|
17
|
+
end
|
18
|
+
"
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def initialize(package_name)
|
21
|
+
@package_name = package_name
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
def info
|
25
|
+
return @info if defined?(@info)
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
@info = {}
|
28
|
+
@info[:type] = 'pip'
|
29
|
+
cmd = inspec.command("#{pip_cmd} show #{@package_name}")
|
30
|
+
return @info if cmd.exit_status != 0
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
params = SimpleConfig.new(
|
33
|
+
cmd.stdout,
|
34
|
+
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
35
|
+
multiple_values: false,
|
36
|
+
).params
|
37
|
+
@info[:name] = params['Name']
|
38
|
+
@info[:version] = params['Version']
|
39
|
+
@info[:installed] = true
|
40
|
+
@info
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
def installed?
|
44
|
+
info[:installed] == true
|
45
|
+
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
def version
|
48
|
+
info[:version]
|
49
|
+
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
def to_s
|
52
|
+
"Pip Package #{@package_name}"
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
+
private
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
57
|
+
def pip_cmd
|
58
|
+
# Pip is not on the default path for Windows, therefore we do some logic
|
59
|
+
# to find the binary on Windows
|
60
|
+
family = inspec.os[:family]
|
61
|
+
case family
|
62
|
+
when 'windows'
|
63
|
+
# we need to detect the pip command on Windows
|
64
|
+
cmd = inspec.command('New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Pip -Value (Invoke-Command -ScriptBlock {where.exe pip}) -PassThru | Add-Member -MemberType NoteProperty -Name Python -Value (Invoke-Command -ScriptBlock {where.exe python}) -PassThru | ConvertTo-Json')
|
65
|
+
begin
|
66
|
+
paths = JSON.parse(cmd.stdout)
|
67
|
+
# use pip if it on system path
|
68
|
+
pipcmd = paths['Pip']
|
69
|
+
# calculate path on windows
|
70
|
+
if defined?(paths['Python']) && pipcmd.nil?
|
71
|
+
pipdir = paths['Python'].split('\\')
|
72
|
+
# remove python.exe
|
73
|
+
pipdir.pop
|
74
|
+
pipcmd = pipdir.push('Scripts').push('pip.exe').join('/')
|
75
|
+
end
|
76
|
+
rescue JSON::ParserError => _e
|
77
|
+
return nil
|
74
78
|
end
|
75
|
-
rescue JSON::ParserError => _e
|
76
|
-
return nil
|
77
79
|
end
|
80
|
+
pipcmd || 'pip'
|
78
81
|
end
|
79
|
-
pipcmd || 'pip'
|
80
82
|
end
|
81
83
|
end
|