inspec 0.9.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 +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +65 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile +33 -0
- data/LICENSE +201 -0
- data/MAINTAINERS.md +28 -0
- data/MAINTAINERS.toml +42 -0
- data/README.md +257 -0
- data/Rakefile +47 -0
- data/bin/inspec +109 -0
- data/docs/ctl_inspec.rst +195 -0
- data/docs/dsl_inspec.rst +182 -0
- data/docs/readme.rst +100 -0
- data/docs/resources.rst +4319 -0
- data/docs/template.rst +51 -0
- data/examples/test-kitchen/.kitchen.yml +20 -0
- data/examples/test-kitchen/Berksfile +3 -0
- data/examples/test-kitchen/Gemfile +21 -0
- data/examples/test-kitchen/README.md +27 -0
- data/examples/test-kitchen/metadata.rb +7 -0
- data/examples/test-kitchen/recipes/default.rb +6 -0
- data/examples/test-kitchen/recipes/nginx.rb +30 -0
- data/examples/test-kitchen/test/integration/default/web_spec.rb +28 -0
- data/inspec.gemspec +30 -0
- data/lib/inspec.rb +20 -0
- data/lib/inspec/backend.rb +42 -0
- data/lib/inspec/dsl.rb +151 -0
- data/lib/inspec/log.rb +34 -0
- data/lib/inspec/metadata.rb +79 -0
- data/lib/inspec/plugins.rb +9 -0
- data/lib/inspec/plugins/resource.rb +62 -0
- data/lib/inspec/profile.rb +138 -0
- data/lib/inspec/profile_context.rb +170 -0
- data/lib/inspec/resource.rb +76 -0
- data/lib/inspec/rspec_json_formatter.rb +27 -0
- data/lib/inspec/rule.rb +170 -0
- data/lib/inspec/runner.rb +154 -0
- data/lib/inspec/shell.rb +66 -0
- data/lib/inspec/targets.rb +9 -0
- data/lib/inspec/targets/core.rb +27 -0
- data/lib/inspec/targets/dir.rb +67 -0
- data/lib/inspec/targets/file.rb +29 -0
- data/lib/inspec/targets/folder.rb +43 -0
- data/lib/inspec/targets/tar.rb +34 -0
- data/lib/inspec/targets/url.rb +39 -0
- data/lib/inspec/targets/zip.rb +47 -0
- data/lib/inspec/version.rb +7 -0
- data/lib/matchers/matchers.rb +221 -0
- data/lib/resources/apache.rb +29 -0
- data/lib/resources/apache_conf.rb +113 -0
- data/lib/resources/apt.rb +140 -0
- data/lib/resources/audit_policy.rb +63 -0
- data/lib/resources/auditd_conf.rb +56 -0
- data/lib/resources/auditd_rules.rb +53 -0
- data/lib/resources/bond.rb +65 -0
- data/lib/resources/bridge.rb +114 -0
- data/lib/resources/command.rb +57 -0
- data/lib/resources/csv.rb +32 -0
- data/lib/resources/directory.rb +15 -0
- data/lib/resources/etc_group.rb +150 -0
- data/lib/resources/file.rb +110 -0
- data/lib/resources/gem.rb +46 -0
- data/lib/resources/group.rb +132 -0
- data/lib/resources/host.rb +143 -0
- data/lib/resources/inetd_conf.rb +56 -0
- data/lib/resources/interface.rb +127 -0
- data/lib/resources/iptables.rb +65 -0
- data/lib/resources/json.rb +64 -0
- data/lib/resources/kernel_module.rb +40 -0
- data/lib/resources/kernel_parameter.rb +55 -0
- data/lib/resources/limits_conf.rb +55 -0
- data/lib/resources/login_def.rb +60 -0
- data/lib/resources/mysql.rb +81 -0
- data/lib/resources/mysql_conf.rb +116 -0
- data/lib/resources/mysql_session.rb +52 -0
- data/lib/resources/npm.rb +44 -0
- data/lib/resources/ntp_conf.rb +58 -0
- data/lib/resources/oneget.rb +63 -0
- data/lib/resources/os.rb +22 -0
- data/lib/resources/os_env.rb +34 -0
- data/lib/resources/package.rb +169 -0
- data/lib/resources/parse_config.rb +75 -0
- data/lib/resources/passwd.rb +93 -0
- data/lib/resources/pip.rb +75 -0
- data/lib/resources/port.rb +296 -0
- data/lib/resources/postgres.rb +37 -0
- data/lib/resources/postgres_conf.rb +87 -0
- data/lib/resources/postgres_session.rb +59 -0
- data/lib/resources/processes.rb +57 -0
- data/lib/resources/registry_key.rb +54 -0
- data/lib/resources/script.rb +34 -0
- data/lib/resources/security_policy.rb +73 -0
- data/lib/resources/service.rb +379 -0
- data/lib/resources/ssh_conf.rb +75 -0
- data/lib/resources/user.rb +374 -0
- data/lib/resources/windows_feature.rb +77 -0
- data/lib/resources/yaml.rb +23 -0
- data/lib/resources/yum.rb +154 -0
- data/lib/utils/convert.rb +12 -0
- data/lib/utils/detect.rb +15 -0
- data/lib/utils/find_files.rb +36 -0
- data/lib/utils/hash.rb +13 -0
- data/lib/utils/modulator.rb +12 -0
- data/lib/utils/parser.rb +61 -0
- data/lib/utils/simpleconfig.rb +115 -0
- data/tasks/maintainers.rb +213 -0
- data/test/docker_run.rb +156 -0
- data/test/docker_test.rb +51 -0
- data/test/helper.rb +200 -0
- data/test/integration/.kitchen.yml +42 -0
- data/test/integration/Berksfile +4 -0
- data/test/integration/cookbooks/os_prepare/metadata.rb +8 -0
- data/test/integration/cookbooks/os_prepare/recipes/apt.rb +20 -0
- data/test/integration/cookbooks/os_prepare/recipes/default.rb +9 -0
- data/test/integration/cookbooks/os_prepare/recipes/file.rb +21 -0
- data/test/integration/cookbooks/os_prepare/recipes/package.rb +26 -0
- data/test/integration/default/_debug_spec.rb +1 -0
- data/test/integration/default/apt_spec.rb +42 -0
- data/test/integration/default/file_spec.rb +109 -0
- data/test/integration/default/group_spec.rb +32 -0
- data/test/integration/default/kernel_module_spec.rb +17 -0
- data/test/integration/default/kernel_parameter_spec.rb +56 -0
- data/test/integration/default/package_spec.rb +11 -0
- data/test/integration/default/service_spec.rb +28 -0
- data/test/integration/default/user_spec.rb +44 -0
- data/test/resource/command_test.rb +33 -0
- data/test/resource/dsl_test.rb +45 -0
- data/test/resource/file_test.rb +130 -0
- data/test/resource/ssh_config.rb +9 -0
- data/test/resource/sshd_config.rb +9 -0
- data/test/test-extra.yaml +11 -0
- data/test/test.yaml +11 -0
- data/test/unit/mock/cmd/Get-NetAdapter +24 -0
- data/test/unit/mock/cmd/GetUserAccount +33 -0
- data/test/unit/mock/cmd/GetWin32Group +23 -0
- data/test/unit/mock/cmd/PATH +1 -0
- data/test/unit/mock/cmd/Resolve-DnsName +26 -0
- data/test/unit/mock/cmd/Test-NetConnection +4 -0
- data/test/unit/mock/cmd/auditctl +7 -0
- data/test/unit/mock/cmd/auditpol +2 -0
- data/test/unit/mock/cmd/brew-info-jq +1 -0
- data/test/unit/mock/cmd/chage-l-root +7 -0
- data/test/unit/mock/cmd/dpkg-s-curl +21 -0
- data/test/unit/mock/cmd/dscl +5 -0
- data/test/unit/mock/cmd/etc-apt +7 -0
- data/test/unit/mock/cmd/find-etc-rc-d-name-S +12 -0
- data/test/unit/mock/cmd/find-net-interface +9 -0
- data/test/unit/mock/cmd/gem-list-local-a-q-rubocop +1 -0
- data/test/unit/mock/cmd/get-net-tcpconnection +24 -0
- data/test/unit/mock/cmd/get-netadapter-binding-bridge +4 -0
- data/test/unit/mock/cmd/get-package-firefox +30 -0
- data/test/unit/mock/cmd/get-package-ruby +18 -0
- data/test/unit/mock/cmd/get-service-dhcp +10 -0
- data/test/unit/mock/cmd/get-windows-feature +7 -0
- data/test/unit/mock/cmd/getent-hosts-example.com +1 -0
- data/test/unit/mock/cmd/getent-passwd-root +1 -0
- data/test/unit/mock/cmd/id-chartmann +1 -0
- data/test/unit/mock/cmd/id-root +1 -0
- data/test/unit/mock/cmd/initctl-show-config-ssh +3 -0
- data/test/unit/mock/cmd/initctl-status-ssh +1 -0
- data/test/unit/mock/cmd/iptables-s +6 -0
- data/test/unit/mock/cmd/launchctl-list +3 -0
- data/test/unit/mock/cmd/ls-1-etc-init.d +2 -0
- data/test/unit/mock/cmd/ls-sys-class-net-br +2 -0
- data/test/unit/mock/cmd/lsmod +2 -0
- data/test/unit/mock/cmd/lsof-np-itcp +4 -0
- data/test/unit/mock/cmd/netstat-tulpen +5 -0
- data/test/unit/mock/cmd/npm-ls-g--json-bower +9 -0
- data/test/unit/mock/cmd/pacman-qi-curl +21 -0
- data/test/unit/mock/cmd/ping-example.com +6 -0
- data/test/unit/mock/cmd/pip-show-jinja2 +11 -0
- data/test/unit/mock/cmd/ps-aux +3 -0
- data/test/unit/mock/cmd/pw-usershow-root-7 +1 -0
- data/test/unit/mock/cmd/reg_schedule +1 -0
- data/test/unit/mock/cmd/rpm-qia-curl +24 -0
- data/test/unit/mock/cmd/sbin_sysctl +1 -0
- data/test/unit/mock/cmd/secedit-export +7 -0
- data/test/unit/mock/cmd/service-e +2 -0
- data/test/unit/mock/cmd/service-sendmail-onestatus +3 -0
- data/test/unit/mock/cmd/service-sshd-status +1 -0
- data/test/unit/mock/cmd/sockstat +5 -0
- data/test/unit/mock/cmd/success +0 -0
- data/test/unit/mock/cmd/systemctl-show-all-sshd +6 -0
- data/test/unit/mock/cmd/win32_product +8 -0
- data/test/unit/mock/cmd/yum-repolist-all +52 -0
- data/test/unit/mock/files/auditd.conf +4 -0
- data/test/unit/mock/files/bond0 +37 -0
- data/test/unit/mock/files/etcgroup +3 -0
- data/test/unit/mock/files/example.csv +6 -0
- data/test/unit/mock/files/inetd.conf +2 -0
- data/test/unit/mock/files/kitchen.yml +7 -0
- data/test/unit/mock/files/limits.conf +5 -0
- data/test/unit/mock/files/login.defs +5 -0
- data/test/unit/mock/files/mysql.conf +8 -0
- data/test/unit/mock/files/mysql2.conf +2 -0
- data/test/unit/mock/files/ntp.conf +5 -0
- data/test/unit/mock/files/passwd +2 -0
- data/test/unit/mock/files/policyfile.lock.json +12 -0
- data/test/unit/mock/files/ssh_config +5 -0
- data/test/unit/mock/files/sshd_config +7 -0
- data/test/unit/mock/profiles/empty/metadata.rb +0 -0
- data/test/unit/mock/profiles/metadata/metadata.rb +1 -0
- data/test/unit/profile_context_test.rb +140 -0
- data/test/unit/profile_test.rb +49 -0
- data/test/unit/resources/apt_test.rb +46 -0
- data/test/unit/resources/audit_policy_test.rb +13 -0
- data/test/unit/resources/auditd_conf_test.rb +15 -0
- data/test/unit/resources/auditd_rules_test.rb +21 -0
- data/test/unit/resources/bond_test.rb +24 -0
- data/test/unit/resources/bridge_test.rb +56 -0
- data/test/unit/resources/csv_test.rb +35 -0
- data/test/unit/resources/etc_group_test.rb +37 -0
- data/test/unit/resources/gem_test.rb +20 -0
- data/test/unit/resources/group_test.rb +96 -0
- data/test/unit/resources/host_test.rb +38 -0
- data/test/unit/resources/inetd_conf_test.rb +15 -0
- data/test/unit/resources/interface_test.rb +54 -0
- data/test/unit/resources/iptables_test.rb +30 -0
- data/test/unit/resources/json_test.rb +36 -0
- data/test/unit/resources/kernel_module_test.rb +23 -0
- data/test/unit/resources/kernel_parameter_test.rb +13 -0
- data/test/unit/resources/limits_conf_test.rb +14 -0
- data/test/unit/resources/login_def_test.rb +16 -0
- data/test/unit/resources/mysql_conf_test.rb +14 -0
- data/test/unit/resources/npm_test.rb +20 -0
- data/test/unit/resources/ntp_conf_test.rb +16 -0
- data/test/unit/resources/oneget_test.rb +45 -0
- data/test/unit/resources/os_env_test.rb +13 -0
- data/test/unit/resources/package_test.rb +51 -0
- data/test/unit/resources/passwd_test.rb +24 -0
- data/test/unit/resources/pip_test.rb +15 -0
- data/test/unit/resources/port_test.rb +46 -0
- data/test/unit/resources/processes_test.rb +32 -0
- data/test/unit/resources/registry_key_test.rb +19 -0
- data/test/unit/resources/script_test.rb +19 -0
- data/test/unit/resources/security_policy_test.rb +16 -0
- data/test/unit/resources/service_test.rb +116 -0
- data/test/unit/resources/ssh_conf_test.rb +33 -0
- data/test/unit/resources/user_test.rb +93 -0
- data/test/unit/resources/windows_feature.rb +17 -0
- data/test/unit/resources/yaml_test.rb +34 -0
- data/test/unit/resources/yum_test.rb +68 -0
- data/test/unit/simpleconfig_test.rb +80 -0
- data/test/unit/utils/content_parser_test.rb +30 -0
- metadata +555 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
# author: Christoph Hartmann
|
|
5
|
+
# license: All rights reserved
|
|
6
|
+
|
|
7
|
+
class MysqlSession < Inspec.resource(1)
|
|
8
|
+
name 'mysql_session'
|
|
9
|
+
|
|
10
|
+
def initialize(user = nil, pass = nil)
|
|
11
|
+
@user = user
|
|
12
|
+
@pass = pass
|
|
13
|
+
init_fallback if user.nil? or pass.nil?
|
|
14
|
+
skip_resource("Can't run MySQL SQL checks without authentication") if @user.nil? or @pass.nil?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def query(q, db = '')
|
|
18
|
+
# TODO: simple escape, must be handled by a library
|
|
19
|
+
# that does this securely
|
|
20
|
+
escaped_query = q.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$')
|
|
21
|
+
|
|
22
|
+
# run the query
|
|
23
|
+
cmd = inspec.command("mysql -u#{@user} -p#{@pass} #{db} -s -e \"#{escaped_query}\"")
|
|
24
|
+
out = cmd.stdout + "\n" + cmd.stderr
|
|
25
|
+
if out =~ /Can't connect to .* MySQL server/ or
|
|
26
|
+
out.downcase =~ /^error/
|
|
27
|
+
# skip this test if the server can't run the query
|
|
28
|
+
skip_resource("Can't connect to MySQL instance for SQL checks.")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# return the raw command output
|
|
32
|
+
cmd
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
'MySQL Session'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def init_fallback
|
|
42
|
+
# support debian mysql administration login
|
|
43
|
+
debian = inspec.command('test -f /etc/mysql/debian.cnf && cat /etc/mysql/debian.cnf').stdout
|
|
44
|
+
return if debian.empty?
|
|
45
|
+
|
|
46
|
+
user = debian.match(/^\s*user\s*=\s*([^ ]*)\s*$/)
|
|
47
|
+
pass = debian.match(/^\s*password\s*=\s*([^ ]*)\s*$/)
|
|
48
|
+
return if user.nil? or pass.nil?
|
|
49
|
+
@user = user[1]
|
|
50
|
+
@pass = pass[1]
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
# Usage:
|
|
6
|
+
# describe npm('bower') do
|
|
7
|
+
# it { should be_installed }
|
|
8
|
+
# end
|
|
9
|
+
class NpmPackage < Inspec.resource(1)
|
|
10
|
+
name 'npm'
|
|
11
|
+
|
|
12
|
+
def initialize(package_name)
|
|
13
|
+
@package_name = package_name
|
|
14
|
+
@cache = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def info
|
|
18
|
+
return @info if defined?(@info)
|
|
19
|
+
|
|
20
|
+
cmd = inspec.command("npm ls -g --json #{@package_name}")
|
|
21
|
+
@info = {
|
|
22
|
+
name: @package_name,
|
|
23
|
+
type: 'npm',
|
|
24
|
+
installed: cmd.exit_status == 0,
|
|
25
|
+
}
|
|
26
|
+
return @info unless @info[:installed]
|
|
27
|
+
|
|
28
|
+
pkgs = JSON.parse(cmd.stdout)
|
|
29
|
+
@info[:version] = pkgs['dependencies'][@package_name]['version']
|
|
30
|
+
@info
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def installed?
|
|
34
|
+
info[:installed] == true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def version
|
|
38
|
+
info[:version]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
"Npm Package #{@package_name}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
# author: Dominik Richter
|
|
5
|
+
# license: All rights reserved
|
|
6
|
+
|
|
7
|
+
require 'utils/simpleconfig'
|
|
8
|
+
|
|
9
|
+
# Usage:
|
|
10
|
+
#
|
|
11
|
+
# describe ntp_conf do
|
|
12
|
+
# its('server') { should_not eq nil }
|
|
13
|
+
# its('restrict') { should include '-4 default kod notrap nomodify nopeer noquery'}
|
|
14
|
+
# end
|
|
15
|
+
|
|
16
|
+
class NtpConf < Inspec.resource(1)
|
|
17
|
+
name 'ntp_conf'
|
|
18
|
+
|
|
19
|
+
def initialize(path = nil)
|
|
20
|
+
@conf_path = path || '/etc/ntp.conf'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def method_missing(name)
|
|
24
|
+
param = read_params[name.to_s]
|
|
25
|
+
# extract first value if we have only one value in array
|
|
26
|
+
return param[0] if param.is_a?(Array) and param.length == 1
|
|
27
|
+
param
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_s
|
|
31
|
+
'ntp.conf'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def read_params
|
|
37
|
+
return @params if defined?(@params)
|
|
38
|
+
|
|
39
|
+
if !inspec.file(@conf_path).file?
|
|
40
|
+
skip_resource "Can't find file \"#{@conf_path}\""
|
|
41
|
+
return @params = {}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
content = inspec.file(@conf_path).content
|
|
45
|
+
if content.empty? && inspec.file(@conf_path).size > 0
|
|
46
|
+
skip_resource "Can't read file \"#{@conf_path}\""
|
|
47
|
+
return @params = {}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# parse the file
|
|
51
|
+
conf = SimpleConfig.new(
|
|
52
|
+
content,
|
|
53
|
+
assignment_re: /^\s*(\S+)\s+(.*)\s*$/,
|
|
54
|
+
multiple_values: true,
|
|
55
|
+
)
|
|
56
|
+
@params = conf.params
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
# This resource talks with OneGet (https://github.com/OneGet/oneget)
|
|
6
|
+
# Its part of Windows Management Framework 5.0 and part of Windows 10
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# describe oneget('zoomit') do
|
|
10
|
+
# it { should be_installed }
|
|
11
|
+
# end
|
|
12
|
+
class OneGetPackage < Inspec.resource(1)
|
|
13
|
+
name 'oneget'
|
|
14
|
+
|
|
15
|
+
def initialize(package_name)
|
|
16
|
+
@package_name = package_name
|
|
17
|
+
|
|
18
|
+
# verify that this resource is only supported on Windows
|
|
19
|
+
return skip_resource 'The `oneget` resource is not supported on your OS.' if inspec.os[:family] != 'windows'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def info
|
|
23
|
+
return @info if defined?(@info)
|
|
24
|
+
|
|
25
|
+
@info = {}
|
|
26
|
+
@info[:type] = 'oneget'
|
|
27
|
+
@info[:installed] = false
|
|
28
|
+
|
|
29
|
+
cmd = inspec.command("Get-Package -Name '#{@package_name}' | ConvertTo-Json")
|
|
30
|
+
# cannot rely on exit code for now, successful command returns exit code 1
|
|
31
|
+
# return nil if cmd.exit_status != 0
|
|
32
|
+
# try to parse json
|
|
33
|
+
|
|
34
|
+
begin
|
|
35
|
+
pkgs = JSON.parse(cmd.stdout)
|
|
36
|
+
@info[:installed] = true
|
|
37
|
+
|
|
38
|
+
# sometimes we get multiple values
|
|
39
|
+
if pkgs.is_a?(Array)
|
|
40
|
+
# select the first entry
|
|
41
|
+
pkgs = pkgs.first
|
|
42
|
+
end
|
|
43
|
+
rescue JSON::ParserError => _e
|
|
44
|
+
return @info
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@info[:name] = pkgs['Name'] if pkgs.key?('Name')
|
|
48
|
+
@info[:version] = pkgs['Version'] if pkgs.key?('Version')
|
|
49
|
+
@info
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def installed?
|
|
53
|
+
info[:installed] == true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def version
|
|
57
|
+
info[:version]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_s
|
|
61
|
+
"OneGet Package #{@package_name}"
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/resources/os.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Dominik Richter
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
|
|
5
|
+
class OS < Inspec.resource(1)
|
|
6
|
+
name 'os'
|
|
7
|
+
|
|
8
|
+
# reuse helper methods from backend
|
|
9
|
+
%w{redhat? debian? suse? bsd? solaris? linux? unix? windows?}.each do |os_family|
|
|
10
|
+
define_method((os_family).to_sym) do
|
|
11
|
+
inspec.backend.os.send(os_family)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def [](name)
|
|
16
|
+
inspec.backend.os[name]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
'Operating System Detection'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
# author: Dominik Richter
|
|
5
|
+
# license: All rights reserved
|
|
6
|
+
|
|
7
|
+
# Usage:
|
|
8
|
+
#
|
|
9
|
+
# describe os_env('PATH') do
|
|
10
|
+
# its(:split) { should_not include('') }
|
|
11
|
+
# its(:split) { should_not include('.') }
|
|
12
|
+
# end
|
|
13
|
+
|
|
14
|
+
class OsEnv < Inspec.resource(1)
|
|
15
|
+
name 'os_env'
|
|
16
|
+
|
|
17
|
+
attr_reader :content
|
|
18
|
+
def initialize(env)
|
|
19
|
+
@osenv = env
|
|
20
|
+
cmd = inspec.command("su - root -c 'echo $#{env}'")
|
|
21
|
+
@content = cmd.stdout.chomp
|
|
22
|
+
@content = nil if cmd.exit_status != 0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def split
|
|
26
|
+
# -1 is required to catch cases like dir1::dir2:
|
|
27
|
+
# where we have a trailing :
|
|
28
|
+
@content.nil? ? [] : @content.split(':', -1)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
"Environment Variable #{@osenv}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
# Resource to determine package information
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# describe package('nginx') do
|
|
9
|
+
# it { should be_installed }
|
|
10
|
+
# end
|
|
11
|
+
class Package < Inspec.resource(1)
|
|
12
|
+
name 'package'
|
|
13
|
+
|
|
14
|
+
def initialize(package_name = nil)
|
|
15
|
+
@package_name = package_name
|
|
16
|
+
@name = @package_name
|
|
17
|
+
@cache = nil
|
|
18
|
+
|
|
19
|
+
# select package manager
|
|
20
|
+
@pkgman = nil
|
|
21
|
+
case inspec.os[:family]
|
|
22
|
+
when 'ubuntu', 'debian'
|
|
23
|
+
@pkgman = Deb.new(inspec)
|
|
24
|
+
when 'redhat', 'fedora', 'centos', 'opensuse'
|
|
25
|
+
@pkgman = Rpm.new(inspec)
|
|
26
|
+
when 'arch'
|
|
27
|
+
@pkgman = Pacman.new(inspec)
|
|
28
|
+
when 'darwin'
|
|
29
|
+
@pkgman = Brew.new(inspec)
|
|
30
|
+
when 'windows'
|
|
31
|
+
@pkgman = WindowsPkg.new(inspec)
|
|
32
|
+
else
|
|
33
|
+
return skip_resource 'The `package` resource is not supported on your OS yet.'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# returns true if the package is installed
|
|
38
|
+
def installed?(_provider = nil, _version = nil)
|
|
39
|
+
return false if info.nil?
|
|
40
|
+
info[:installed] == true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# returns the package description
|
|
44
|
+
def info
|
|
45
|
+
return @cache if !@cache.nil?
|
|
46
|
+
return nil if @pkgman.nil?
|
|
47
|
+
@pkgman.info(@package_name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# return the package version
|
|
51
|
+
def version
|
|
52
|
+
info = @pkgman.info(@package_name)
|
|
53
|
+
return nil if info.nil?
|
|
54
|
+
info[:version]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_s
|
|
58
|
+
"System Package #{@package_name}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class PkgManagement
|
|
63
|
+
attr_reader :inspec
|
|
64
|
+
def initialize(inspec)
|
|
65
|
+
@inspec = inspec
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Debian / Ubuntu
|
|
70
|
+
class Deb < PkgManagement
|
|
71
|
+
def info(package_name)
|
|
72
|
+
cmd = inspec.command("dpkg -s #{package_name}")
|
|
73
|
+
return nil if cmd.exit_status.to_i != 0
|
|
74
|
+
|
|
75
|
+
params = SimpleConfig.new(
|
|
76
|
+
cmd.stdout.chomp,
|
|
77
|
+
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
78
|
+
multiple_values: false,
|
|
79
|
+
).params
|
|
80
|
+
{
|
|
81
|
+
name: params['Package'],
|
|
82
|
+
installed: true,
|
|
83
|
+
version: params['Version'],
|
|
84
|
+
type: 'deb',
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# RHEL family
|
|
90
|
+
class Rpm < PkgManagement
|
|
91
|
+
def info(package_name)
|
|
92
|
+
cmd = inspec.command("rpm -qia #{package_name}")
|
|
93
|
+
# CentOS does not return an error code if the package is not installed,
|
|
94
|
+
# therefore we need to check for emptyness
|
|
95
|
+
return nil if cmd.exit_status.to_i != 0 || cmd.stdout.chomp.empty?
|
|
96
|
+
params = SimpleConfig.new(
|
|
97
|
+
cmd.stdout.chomp,
|
|
98
|
+
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
99
|
+
multiple_values: false,
|
|
100
|
+
).params
|
|
101
|
+
{
|
|
102
|
+
name: params['Name'],
|
|
103
|
+
installed: true,
|
|
104
|
+
version: params['Version'],
|
|
105
|
+
type: 'rpm',
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# MacOS / Darwin implementation
|
|
111
|
+
class Brew < PkgManagement
|
|
112
|
+
def info(package_name)
|
|
113
|
+
cmd = inspec.command("brew info --json=v1 #{package_name}")
|
|
114
|
+
return nil if cmd.exit_status.to_i != 0
|
|
115
|
+
# parse data
|
|
116
|
+
pkg = JSON.parse(cmd.stdout)[0]
|
|
117
|
+
{
|
|
118
|
+
name: "#{pkg.name}",
|
|
119
|
+
installed: true,
|
|
120
|
+
version: "#{pkg.installed.version}",
|
|
121
|
+
type: 'brew',
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Arch Linux
|
|
127
|
+
class Pacman < PkgManagement
|
|
128
|
+
def info(package_name)
|
|
129
|
+
cmd = inspec.command("pacman -Qi #{package_name}")
|
|
130
|
+
return nil if cmd.exit_status.to_i != 0
|
|
131
|
+
|
|
132
|
+
params = SimpleConfig.new(
|
|
133
|
+
cmd.stdout.chomp,
|
|
134
|
+
assignment_re: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
135
|
+
multiple_values: false,
|
|
136
|
+
).params
|
|
137
|
+
|
|
138
|
+
{
|
|
139
|
+
name: params['Name'],
|
|
140
|
+
installed: true,
|
|
141
|
+
version: params['Version'],
|
|
142
|
+
type: 'pacman',
|
|
143
|
+
}
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Determines the installed packages on Windows
|
|
148
|
+
# Currently we use 'Get-WmiObject -Class Win32_Product' as a detection method
|
|
149
|
+
# TODO: evaluate if alternative methods as proposed by Microsoft are still valid:
|
|
150
|
+
# @see: http://blogs.technet.com/b/heyscriptingguy/archive/2013/11/15/use-powershell-to-find-installed-software.aspx
|
|
151
|
+
class WindowsPkg < PkgManagement
|
|
152
|
+
def info(package_name)
|
|
153
|
+
# Find the package
|
|
154
|
+
cmd = inspec.command("Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq '#{package_name}'} | Select-Object -Property Name,Version,Vendor,PackageCode,Caption,Description | ConvertTo-Json")
|
|
155
|
+
|
|
156
|
+
begin
|
|
157
|
+
package = JSON.parse(cmd.stdout)
|
|
158
|
+
rescue JSON::ParserError => _e
|
|
159
|
+
return nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
{
|
|
163
|
+
name: package['Name'],
|
|
164
|
+
installed: true,
|
|
165
|
+
version: package['Version'],
|
|
166
|
+
type: 'windows',
|
|
167
|
+
}
|
|
168
|
+
end
|
|
169
|
+
end
|