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,23 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
require 'yaml'
|
|
6
|
+
|
|
7
|
+
# Parses a yaml document
|
|
8
|
+
# Usage:
|
|
9
|
+
# describe yaml('.kitchen.yaml') do
|
|
10
|
+
# its('driver.name') { should eq('vagrant') }
|
|
11
|
+
# end
|
|
12
|
+
class YamlConfig < JsonConfig
|
|
13
|
+
name 'yaml'
|
|
14
|
+
|
|
15
|
+
# override file load and parse hash from yaml
|
|
16
|
+
def parse(content)
|
|
17
|
+
YAML.load(content)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
"YAML #{@path}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
require 'resources/file'
|
|
6
|
+
|
|
7
|
+
# Usage:
|
|
8
|
+
# describe yum do
|
|
9
|
+
# its('repos') { should exist }
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# describe yum do
|
|
13
|
+
# its('repos') { should include 'base/7/x86_64' }
|
|
14
|
+
# its('epel') { should exist }
|
|
15
|
+
# its('epel') { should be_enabled }
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# Filter for a specific repo by name
|
|
19
|
+
# - use full identifier e.g. 'updates/7/x86_64'
|
|
20
|
+
# - use short identifier e.g. 'updates'
|
|
21
|
+
#
|
|
22
|
+
# describe yum.repo('epel') do
|
|
23
|
+
# it { should exist }
|
|
24
|
+
# it { should be_enabled }
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# deprecated:
|
|
28
|
+
# describe yumrepo('epel') do
|
|
29
|
+
# it { should exist }
|
|
30
|
+
# it { should be_enabled }
|
|
31
|
+
# end
|
|
32
|
+
|
|
33
|
+
class Yum < Inspec.resource(1)
|
|
34
|
+
name 'yum'
|
|
35
|
+
|
|
36
|
+
# returns all repositories
|
|
37
|
+
# works as following:
|
|
38
|
+
# search for Repo-id
|
|
39
|
+
# parse data in hashmap
|
|
40
|
+
# store data in object
|
|
41
|
+
# until \n
|
|
42
|
+
def repositories
|
|
43
|
+
return @cache if defined?(@cache)
|
|
44
|
+
# parse the repository data from yum
|
|
45
|
+
# we cannot use -C, because this is not reliable and may lead to errors
|
|
46
|
+
@command_result = inspec.command('yum -v repolist all')
|
|
47
|
+
@content = @command_result.stdout
|
|
48
|
+
@cache = []
|
|
49
|
+
repo = {}
|
|
50
|
+
in_repo = false
|
|
51
|
+
@content.each_line do |line|
|
|
52
|
+
# detect repo start
|
|
53
|
+
in_repo = true if line.match(/^\s*Repo-id\s*:\s*(.*)\b/)
|
|
54
|
+
# detect repo end
|
|
55
|
+
if line == "\n" && in_repo
|
|
56
|
+
in_repo = false
|
|
57
|
+
@cache.push(repo)
|
|
58
|
+
repo = {}
|
|
59
|
+
end
|
|
60
|
+
# parse repo content
|
|
61
|
+
if in_repo == true
|
|
62
|
+
val = /^\s*([^:]*?)\s*:\s*(.*?)\s*$/.match(line)
|
|
63
|
+
repo[repo_key(strip(val[1]))] = strip(val[2])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
@cache
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def repos
|
|
70
|
+
repositories.map { |repo| repo['id'] }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def repo(repo)
|
|
74
|
+
YumRepo.new(self, repo)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# alias for yum.repo('reponame')
|
|
78
|
+
def method_missing(name)
|
|
79
|
+
repo(name.to_s) if !name.nil?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def to_s
|
|
83
|
+
'Yum Repository'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
# Removes lefthand and righthand whitespace
|
|
89
|
+
def strip(value)
|
|
90
|
+
value.lstrip.rstrip if !value.nil?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Optimize the key value
|
|
94
|
+
def repo_key(key)
|
|
95
|
+
return key if key.nil?
|
|
96
|
+
key.gsub('Repo-', '').downcase
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class YumRepo
|
|
101
|
+
def initialize(yum, reponame)
|
|
102
|
+
@yum = yum
|
|
103
|
+
@reponame = reponame
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# extracts the shortname from a repo id
|
|
107
|
+
# e.g. extras/7/x86_64 -> extras
|
|
108
|
+
def shortname(id)
|
|
109
|
+
val = %r{^\s*([^/]*?)/(.*?)\s*$}.match(id)
|
|
110
|
+
val.nil? ? nil : val[1]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def info
|
|
114
|
+
return @cache if defined?(@cache)
|
|
115
|
+
selection = @yum.repositories.select { |e| e['id'] == @reponame || shortname(e['id']) == @reponame }
|
|
116
|
+
@cache = selection[0] if !selection.nil? && selection.length == 1
|
|
117
|
+
@cache
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def exist?
|
|
121
|
+
!info.nil?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def enabled?
|
|
125
|
+
repo = info
|
|
126
|
+
return false if repo.nil?
|
|
127
|
+
info['status'] == 'enabled'
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# for compatability with serverspec
|
|
132
|
+
# this is deprecated syntax and will be removed in future versions
|
|
133
|
+
class YumRepoLegacy < Yum
|
|
134
|
+
name 'yumrepo'
|
|
135
|
+
|
|
136
|
+
def initialize(name)
|
|
137
|
+
super()
|
|
138
|
+
@repository = repo(name)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def exists?
|
|
142
|
+
deprecated
|
|
143
|
+
@repository.exist?
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def enabled?
|
|
147
|
+
deprecated
|
|
148
|
+
@repository.enabled?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def deprecated
|
|
152
|
+
warn '[DEPRECATION] `yumrepo(reponame)` is deprecated. Please use `yum.repo(reponame)` instead.'
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Dominik Richter
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
|
|
5
|
+
module Converter
|
|
6
|
+
# convert the value to an integer if we have numbers only
|
|
7
|
+
# otherwise we return the string
|
|
8
|
+
def convert_to_i(val)
|
|
9
|
+
val = val.to_i if val.match(/^\d+$/)
|
|
10
|
+
val
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/utils/detect.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# Copyright 2015, Vulcano Security GmbH
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
# author: Dominik Richter
|
|
5
|
+
# Tiny test file to return OS info of the tested node
|
|
6
|
+
|
|
7
|
+
# print OS detection infos
|
|
8
|
+
conf = {
|
|
9
|
+
name: os[:name],
|
|
10
|
+
family: os[:family],
|
|
11
|
+
release: os[:release],
|
|
12
|
+
arch: os[:arch],
|
|
13
|
+
}
|
|
14
|
+
puts JSON.dump(conf)
|
|
15
|
+
exit 0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# copyright: 2015, Vulcano Security GmbH
|
|
3
|
+
# license: All rights reserved
|
|
4
|
+
# author: Dominik Richter
|
|
5
|
+
# author: Christoph Hartmann
|
|
6
|
+
|
|
7
|
+
module FindFiles
|
|
8
|
+
TYPES = {
|
|
9
|
+
block: 'b',
|
|
10
|
+
character: 'c',
|
|
11
|
+
directory: 'd',
|
|
12
|
+
pipe: 'p',
|
|
13
|
+
file: 'f',
|
|
14
|
+
link: 'l',
|
|
15
|
+
socket: 's',
|
|
16
|
+
door: 'D',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
def find_files(path, opts = {})
|
|
20
|
+
depth = opts[:depth]
|
|
21
|
+
type = TYPES[opts[:type].to_sym]
|
|
22
|
+
|
|
23
|
+
cmd = "find #{path}"
|
|
24
|
+
cmd += " -maxdepth #{depth.to_i}" if depth.to_i > 0
|
|
25
|
+
cmd += " -type #{type}" unless type.nil?
|
|
26
|
+
|
|
27
|
+
result = inspec.run_command(cmd)
|
|
28
|
+
exit_status = result.exit_status
|
|
29
|
+
|
|
30
|
+
return [nil, exit_status] unless exit_status == 0
|
|
31
|
+
files = result.stdout.split("\n")
|
|
32
|
+
.map(&:strip)
|
|
33
|
+
.find_all { |x| !x.empty? }
|
|
34
|
+
[files, exit_status]
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/utils/hash.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# Inspired by: http://stackoverflow.com/a/9381776
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
# author: Christoph Hartmann
|
|
5
|
+
|
|
6
|
+
class ::Hash
|
|
7
|
+
def deep_merge(second)
|
|
8
|
+
merger = proc { |_key, v1, v2|
|
|
9
|
+
v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2, &merger) : v2
|
|
10
|
+
}
|
|
11
|
+
merge(second, &merger)
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/utils/parser.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Christoph Hartmann
|
|
3
|
+
# author: Dominik Richter
|
|
4
|
+
|
|
5
|
+
module ContentParser
|
|
6
|
+
# Parse /etc/passwd files.
|
|
7
|
+
#
|
|
8
|
+
# @param [String] content the raw content of /etc/passwd
|
|
9
|
+
# @return [Array] Collection of passwd entries
|
|
10
|
+
def parse_passwd(content)
|
|
11
|
+
content.to_s.split("\n").map do |line|
|
|
12
|
+
parse_passwd_line(line)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Parse a line of /etc/passwd
|
|
17
|
+
#
|
|
18
|
+
# @param [String] line a line of /etc/passwd
|
|
19
|
+
# @return [Hash] Map of entries in this line
|
|
20
|
+
def parse_passwd_line(line)
|
|
21
|
+
x = line.split(':')
|
|
22
|
+
{
|
|
23
|
+
'name' => x.at(0),
|
|
24
|
+
'password' => x.at(1),
|
|
25
|
+
'uid' => x.at(2),
|
|
26
|
+
'gid' => x.at(3),
|
|
27
|
+
'desc' => x.at(4),
|
|
28
|
+
'home' => x.at(5),
|
|
29
|
+
'shell' => x.at(6),
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Parse a line with a command. For example: `a = b # comment`.
|
|
34
|
+
# Retrieves the actual content.
|
|
35
|
+
#
|
|
36
|
+
# @param [String] raw the content lines you want to be parsed
|
|
37
|
+
# @param [Hash] opts optional configuration
|
|
38
|
+
# @return [Array] contains the actual line and the position of the line end
|
|
39
|
+
def parse_comment_line(raw, opts)
|
|
40
|
+
idx_nl = raw.index("\n")
|
|
41
|
+
idx_comment = raw.index(opts[:comment_char])
|
|
42
|
+
idx_nl = raw.length if idx_nl.nil?
|
|
43
|
+
idx_comment = idx_nl + 1 if idx_comment.nil?
|
|
44
|
+
line = ''
|
|
45
|
+
|
|
46
|
+
# is a comment inside this line
|
|
47
|
+
if idx_comment < idx_nl && idx_comment != 0
|
|
48
|
+
line = raw[0..(idx_comment - 1)]
|
|
49
|
+
# in case we don't allow comments at the end
|
|
50
|
+
# of an assignment/statement, ignore it and fall
|
|
51
|
+
# back to treating this as a regular line
|
|
52
|
+
if opts[:standalone_comments] && !is_empty_line(line)
|
|
53
|
+
line = raw[0..(idx_nl - 1)]
|
|
54
|
+
end
|
|
55
|
+
# if there is no comment in this line
|
|
56
|
+
elsif idx_comment > idx_nl && idx_nl != 0
|
|
57
|
+
line = raw[0..(idx_nl - 1)]
|
|
58
|
+
end
|
|
59
|
+
[line, idx_nl]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# copyright: 2015, Dominik Richter
|
|
3
|
+
# license: All rights reserved
|
|
4
|
+
# author: Dominik Richter
|
|
5
|
+
# author: Christoph Hartmann
|
|
6
|
+
|
|
7
|
+
require 'utils/parser'
|
|
8
|
+
|
|
9
|
+
class SimpleConfig
|
|
10
|
+
include ContentParser
|
|
11
|
+
|
|
12
|
+
attr_reader :params, :groups
|
|
13
|
+
def initialize(raw_data, opts = {})
|
|
14
|
+
parse(raw_data, opts)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Parse some data
|
|
18
|
+
# quotes: quoting characters, which are parsed, so everything inside
|
|
19
|
+
# it will be part of a string
|
|
20
|
+
# multiline: allow quoted text to span multiple lines
|
|
21
|
+
# comment_char: char which identifies comments
|
|
22
|
+
# standalone_comments: comments must appear alone in a line; if set to true,
|
|
23
|
+
# no comments can be added to the end of an assignment/statement line
|
|
24
|
+
def parse(raw_data, opts = nil)
|
|
25
|
+
@params = {}
|
|
26
|
+
@groups = []
|
|
27
|
+
@vals = @params
|
|
28
|
+
options = default_options.merge(opts || {})
|
|
29
|
+
return if raw_data.nil?
|
|
30
|
+
|
|
31
|
+
# prepare raw data if required
|
|
32
|
+
if !options[:line_separator].nil?
|
|
33
|
+
raw_data = raw_data.tr(options[:line_separator], "\n")
|
|
34
|
+
end
|
|
35
|
+
rest = raw_data
|
|
36
|
+
rest = parse_rest(rest, options) while rest.length > 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def parse_values(match, values)
|
|
42
|
+
start_idx = 2
|
|
43
|
+
i = 0
|
|
44
|
+
count = values - 1
|
|
45
|
+
return match[start_idx] if (values == 1)
|
|
46
|
+
|
|
47
|
+
# iterate over expected parameters
|
|
48
|
+
values = []
|
|
49
|
+
loop do
|
|
50
|
+
values.push(match[start_idx + i])
|
|
51
|
+
i += 1
|
|
52
|
+
break if i > count
|
|
53
|
+
end
|
|
54
|
+
values
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def parse_params_line(line, opts)
|
|
58
|
+
# now line contains what we are interested in parsing
|
|
59
|
+
# check if it is an assignment
|
|
60
|
+
m = opts[:assignment_re].match(line)
|
|
61
|
+
return nil if m.nil?
|
|
62
|
+
|
|
63
|
+
if opts[:multiple_values]
|
|
64
|
+
@vals[m[1]] ||= []
|
|
65
|
+
@vals[m[1]].push(parse_values(m, opts[:key_vals]))
|
|
66
|
+
else
|
|
67
|
+
@vals[m[1]] = parse_values(m, opts[:key_vals])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_group_line(line, opts)
|
|
72
|
+
return nil if opts[:group_re].nil?
|
|
73
|
+
m = opts[:group_re].match(line)
|
|
74
|
+
return nil if m.nil?
|
|
75
|
+
@groups.push(m[1])
|
|
76
|
+
@vals = @params[m[1]] = {}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def parse_implicit_assignment_line(line, opts)
|
|
80
|
+
return nil if is_empty_line(line)
|
|
81
|
+
if opts[:multiple_values]
|
|
82
|
+
@vals[line.strip] ||= []
|
|
83
|
+
else
|
|
84
|
+
@vals[line.strip] = ''
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_rest(rest, opts)
|
|
89
|
+
line, idx_nl = parse_comment_line(rest, opts)
|
|
90
|
+
parse_params_line(line, opts) or
|
|
91
|
+
parse_group_line(line, opts) or
|
|
92
|
+
parse_implicit_assignment_line(line, opts)
|
|
93
|
+
|
|
94
|
+
# return whatever is left
|
|
95
|
+
rest[(idx_nl + 1)..-1] || ''
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def is_empty_line(l)
|
|
99
|
+
l =~ /^\s*$/
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def default_options
|
|
103
|
+
{
|
|
104
|
+
quotes: '',
|
|
105
|
+
multiline: false,
|
|
106
|
+
comment_char: '#',
|
|
107
|
+
line_separator: nil, # uses this char to seperate lines before parsing
|
|
108
|
+
assignment_re: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
|
|
109
|
+
group_re: /\[([^\]]+)\]\s*$/,
|
|
110
|
+
key_vals: 1, # default for key=value, may require for 'key val1 val2 val3'
|
|
111
|
+
standalone_comments: false,
|
|
112
|
+
multiple_values: false,
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end
|