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,76 @@
|
|
|
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
|
+
require 'inspec/plugins'
|
|
8
|
+
|
|
9
|
+
module Inspec
|
|
10
|
+
class Resource
|
|
11
|
+
def self.registry
|
|
12
|
+
@registry ||= {}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.resource(version)
|
|
17
|
+
if version != 1
|
|
18
|
+
fail 'Only resource version 1 is supported!'
|
|
19
|
+
end
|
|
20
|
+
Inspec::Plugins::Resource
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require 'resources/apache'
|
|
25
|
+
require 'resources/apache_conf'
|
|
26
|
+
require 'resources/apt'
|
|
27
|
+
require 'resources/audit_policy'
|
|
28
|
+
require 'resources/auditd_conf'
|
|
29
|
+
require 'resources/auditd_rules'
|
|
30
|
+
require 'resources/bond'
|
|
31
|
+
require 'resources/bridge'
|
|
32
|
+
require 'resources/command'
|
|
33
|
+
require 'resources/directory'
|
|
34
|
+
require 'resources/etc_group'
|
|
35
|
+
require 'resources/file'
|
|
36
|
+
require 'resources/gem'
|
|
37
|
+
require 'resources/group'
|
|
38
|
+
require 'resources/host'
|
|
39
|
+
require 'resources/inetd_conf'
|
|
40
|
+
require 'resources/interface'
|
|
41
|
+
require 'resources/iptables'
|
|
42
|
+
require 'resources/json'
|
|
43
|
+
require 'resources/kernel_module'
|
|
44
|
+
require 'resources/kernel_parameter'
|
|
45
|
+
require 'resources/limits_conf'
|
|
46
|
+
require 'resources/login_def'
|
|
47
|
+
require 'resources/mysql'
|
|
48
|
+
require 'resources/mysql_conf'
|
|
49
|
+
require 'resources/mysql_session'
|
|
50
|
+
require 'resources/npm'
|
|
51
|
+
require 'resources/ntp_conf'
|
|
52
|
+
require 'resources/oneget'
|
|
53
|
+
require 'resources/os'
|
|
54
|
+
require 'resources/os_env'
|
|
55
|
+
require 'resources/package'
|
|
56
|
+
require 'resources/parse_config'
|
|
57
|
+
require 'resources/passwd'
|
|
58
|
+
require 'resources/pip'
|
|
59
|
+
require 'resources/port'
|
|
60
|
+
require 'resources/postgres'
|
|
61
|
+
require 'resources/postgres_conf'
|
|
62
|
+
require 'resources/postgres_session'
|
|
63
|
+
require 'resources/processes'
|
|
64
|
+
require 'resources/registry_key'
|
|
65
|
+
require 'resources/script'
|
|
66
|
+
require 'resources/security_policy'
|
|
67
|
+
require 'resources/service'
|
|
68
|
+
require 'resources/ssh_conf'
|
|
69
|
+
require 'resources/user'
|
|
70
|
+
require 'resources/windows_feature'
|
|
71
|
+
require 'resources/yum'
|
|
72
|
+
|
|
73
|
+
# file formats, depend on json implementation
|
|
74
|
+
require 'resources/json'
|
|
75
|
+
require 'resources/yaml'
|
|
76
|
+
require 'resources/csv'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Dominik Richter
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
|
|
5
|
+
require 'rspec/core'
|
|
6
|
+
|
|
7
|
+
# Extend the basic RSpec JSON Formatter
|
|
8
|
+
# to give us an ID in its output
|
|
9
|
+
# TODO: remove once RSpec has IDs in stable (probably v3.3/v4.0)
|
|
10
|
+
module RSpec::Core::Formatters
|
|
11
|
+
class JsonFormatter
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def format_example(example)
|
|
15
|
+
{
|
|
16
|
+
description: example.description,
|
|
17
|
+
full_description: example.full_description,
|
|
18
|
+
status: example.execution_result.status.to_s,
|
|
19
|
+
file_path: example.metadata['file_path'],
|
|
20
|
+
line_number: example.metadata['line_number'],
|
|
21
|
+
run_time: example.execution_result.run_time,
|
|
22
|
+
pending_message: example.execution_result.pending_message,
|
|
23
|
+
id: example.metadata[:id],
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/inspec/rule.rb
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
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 'rspec/expectations'
|
|
8
|
+
require 'method_source'
|
|
9
|
+
|
|
10
|
+
module Inspec
|
|
11
|
+
class ExpectationTarget
|
|
12
|
+
attr_reader :calls, :value, :block
|
|
13
|
+
def initialize(value, &block)
|
|
14
|
+
@value = value
|
|
15
|
+
@block = block
|
|
16
|
+
@calls = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to(*args, &block)
|
|
20
|
+
@calls.push([:to, args, block, caller])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def not_to(*args, &block)
|
|
24
|
+
@calls.push([:not_to, args, block, caller])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def example_group
|
|
28
|
+
that = self
|
|
29
|
+
|
|
30
|
+
opts = { 'caller' => calls[0][3] }
|
|
31
|
+
if !calls[0][3].nil? && !calls[0][3].empty? &&
|
|
32
|
+
(m = calls[0][3][0].match(/^([^:]*):(\d+):/))
|
|
33
|
+
opts['file_path'] = m[0]
|
|
34
|
+
opts['line_number'] = m[1]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
RSpec::Core::ExampleGroup.describe(that.value, opts) do
|
|
38
|
+
that.calls.each do |method, args, block, clr|
|
|
39
|
+
it(nil, caller: clr) do
|
|
40
|
+
x = expect(that.value, &that.block).method(method)
|
|
41
|
+
x.call(*args, &block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Rule
|
|
49
|
+
include ::RSpec::Matchers
|
|
50
|
+
|
|
51
|
+
def initialize(id, _opts, &block)
|
|
52
|
+
@id = id
|
|
53
|
+
@impact = nil
|
|
54
|
+
@__block = block
|
|
55
|
+
@__code = __get_block_source(&block)
|
|
56
|
+
@title = nil
|
|
57
|
+
@desc = nil
|
|
58
|
+
# not changeable by the user:
|
|
59
|
+
@profile_id = nil
|
|
60
|
+
@checks = []
|
|
61
|
+
# evaluate the given definition
|
|
62
|
+
instance_eval(&block) if block_given?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def id(*_)
|
|
66
|
+
# never overwrite the ID
|
|
67
|
+
@id
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def impact(v = nil)
|
|
71
|
+
@impact = v unless v.nil?
|
|
72
|
+
@impact
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def title(v = nil)
|
|
76
|
+
@title = v unless v.nil?
|
|
77
|
+
@title
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def desc(v = nil)
|
|
81
|
+
@desc = unindent(v) unless v.nil?
|
|
82
|
+
@desc
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def describe(value, &block)
|
|
86
|
+
@checks.push(['describe', [value], block])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def expect(value, &block)
|
|
90
|
+
target = ExpectationTarget.new(value, &block)
|
|
91
|
+
@checks.push(['expect', [value], target])
|
|
92
|
+
target
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.merge(dst, src)
|
|
96
|
+
if src.id != dst.id
|
|
97
|
+
# TODO: register an error, this case should not happen
|
|
98
|
+
return
|
|
99
|
+
end
|
|
100
|
+
sp = src.instance_variable_get(:@profile_id)
|
|
101
|
+
dp = dst.instance_variable_get(:@profile_id)
|
|
102
|
+
if sp != dp
|
|
103
|
+
# TODO: register an error, this case should not happen
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
# merge all fields
|
|
107
|
+
dst.impact(src.impact) unless src.impact.nil?
|
|
108
|
+
dst.title(src.title) unless src.title.nil?
|
|
109
|
+
dst.desc(src.desc) unless src.desc.nil?
|
|
110
|
+
# merge indirect fields
|
|
111
|
+
# checks defined in the source will completely eliminate
|
|
112
|
+
# all checks that were defined in the destination
|
|
113
|
+
sc = src.instance_variable_get(:@checks)
|
|
114
|
+
unless sc.nil? || sc.empty?
|
|
115
|
+
dst.instance_variable_set(:@checks, sc)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Get the full id consisting of profile id + rule id
|
|
120
|
+
# for the rule. If the rule's profile id is empty,
|
|
121
|
+
# the given profile_id will be used instead and also
|
|
122
|
+
# set for the rule.
|
|
123
|
+
def self.full_id(profile_id, rule)
|
|
124
|
+
if rule.is_a?(String) or rule.nil?
|
|
125
|
+
rid = rule
|
|
126
|
+
else
|
|
127
|
+
# As the profile context is exclusively pulled with a
|
|
128
|
+
# profile ID, attach it to the rule if necessary.
|
|
129
|
+
rid = rule.instance_variable_get(:@id)
|
|
130
|
+
if rid.nil?
|
|
131
|
+
# TODO: Message about skipping this rule
|
|
132
|
+
# due to missing ID
|
|
133
|
+
return nil
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
pid = rule.instance_variable_get(:@profile_id)
|
|
137
|
+
if pid.nil?
|
|
138
|
+
rule.instance_variable_set(:@profile_id, profile_id)
|
|
139
|
+
pid = profile_id
|
|
140
|
+
end
|
|
141
|
+
if pid.nil? or pid.empty?
|
|
142
|
+
return rid
|
|
143
|
+
else
|
|
144
|
+
return "#{pid}/#{rid}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
# Idio(ma)tic unindent
|
|
151
|
+
# TODO: replace this
|
|
152
|
+
#
|
|
153
|
+
# @param [String] text string which needs to be unindented
|
|
154
|
+
# @return [String] input with indentation removed
|
|
155
|
+
def unindent(text)
|
|
156
|
+
return '' if text.nil?
|
|
157
|
+
text.strip.split("\n").map(&:strip)
|
|
158
|
+
.map { |x| x.empty? ? "\n" : x }
|
|
159
|
+
.join(' ')
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# get the rule's source code
|
|
163
|
+
def __get_block_source(&block)
|
|
164
|
+
return '' unless block_given?
|
|
165
|
+
block.source.to_s
|
|
166
|
+
rescue MethodSource::SourceNotFoundError
|
|
167
|
+
''
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
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 'uri'
|
|
8
|
+
require 'inspec/backend'
|
|
9
|
+
require 'inspec/profile_context'
|
|
10
|
+
require 'inspec/targets'
|
|
11
|
+
# spec requirements
|
|
12
|
+
require 'rspec'
|
|
13
|
+
require 'rspec/its'
|
|
14
|
+
require 'inspec/rspec_json_formatter'
|
|
15
|
+
|
|
16
|
+
module Inspec
|
|
17
|
+
class Runner # rubocop:disable Metrics/ClassLength
|
|
18
|
+
attr_reader :tests, :backend, :rules
|
|
19
|
+
def initialize(conf = {})
|
|
20
|
+
@rules = {}
|
|
21
|
+
@profile_id = conf[:id]
|
|
22
|
+
@conf = conf.dup
|
|
23
|
+
@conf[:logger] ||= Logger.new(nil)
|
|
24
|
+
@tests = RSpec::Core::World.new
|
|
25
|
+
|
|
26
|
+
configure_output
|
|
27
|
+
configure_transport
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def normalize_map(hm)
|
|
31
|
+
res = {}
|
|
32
|
+
hm.each {|k, v|
|
|
33
|
+
res[k.to_s] = v
|
|
34
|
+
}
|
|
35
|
+
res
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def configure_output
|
|
39
|
+
RSpec.configuration.add_formatter(@conf['format'] || 'progress')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def configure_transport
|
|
43
|
+
@backend = Inspec::Backend.create(@conf)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_tests(tests)
|
|
47
|
+
# retrieve the raw ruby code of all tests
|
|
48
|
+
items = tests.map do |test|
|
|
49
|
+
Inspec::Targets.resolve(test)
|
|
50
|
+
end.flatten
|
|
51
|
+
|
|
52
|
+
tests = items.find_all { |i| i[:type] == :test }
|
|
53
|
+
libs = items.find_all { |i| i[:type] == :library }
|
|
54
|
+
|
|
55
|
+
# add all tests (raw) to the runtime
|
|
56
|
+
tests.flatten.each do |test|
|
|
57
|
+
add_content(test, libs)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def create_context
|
|
62
|
+
Inspec::ProfileContext.new(@profile_id, @backend)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_content(test, libs)
|
|
66
|
+
content = test[:content]
|
|
67
|
+
return if content.nil? || content.empty?
|
|
68
|
+
|
|
69
|
+
# load all libraries
|
|
70
|
+
ctx = create_context
|
|
71
|
+
libs.each do |lib|
|
|
72
|
+
ctx.load(lib[:content].to_s, lib[:ref], lib[:line] || 1)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# evaluate the test content
|
|
76
|
+
ctx.load(content, test[:ref], test[:line] || 1)
|
|
77
|
+
|
|
78
|
+
# process the resulting rules
|
|
79
|
+
ctx.rules.each do |rule_id, rule|
|
|
80
|
+
register_rule(ctx, rule_id, rule)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def run
|
|
85
|
+
run_with(RSpec::Core::Runner.new(nil))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def run_with(rspec_runner)
|
|
89
|
+
rspec_runner.run_specs(@tests.ordered_example_groups)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def get_check_example(method_name, arg, block)
|
|
95
|
+
opts = {}
|
|
96
|
+
if !block.nil? && block.respond_to?(:source_location)
|
|
97
|
+
file_path, line = block.source_location
|
|
98
|
+
opts['file_path'] = file_path
|
|
99
|
+
opts['line_number'] = line
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if !arg.empty? &&
|
|
103
|
+
arg[0].respond_to?(:resource_skipped) &&
|
|
104
|
+
!arg[0].resource_skipped.nil?
|
|
105
|
+
return RSpec::Core::ExampleGroup.describe(*arg, opts) do
|
|
106
|
+
it arg[0].resource_skipped
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
# add the resource
|
|
110
|
+
case method_name
|
|
111
|
+
when 'describe'
|
|
112
|
+
return RSpec::Core::ExampleGroup.describe(*arg, opts, &block)
|
|
113
|
+
when 'expect'
|
|
114
|
+
return block.example_group
|
|
115
|
+
else
|
|
116
|
+
fail "A rule was registered with #{method_name.inspect}, "\
|
|
117
|
+
"which isn't understood and cannot be processed."
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def register_rule(ctx, rule_id, rule)
|
|
124
|
+
@rules[rule_id] = rule
|
|
125
|
+
checks = rule.instance_variable_get(:@checks)
|
|
126
|
+
checks.each do |m, a, b|
|
|
127
|
+
# resource skipping
|
|
128
|
+
example = get_check_example(m, a, b)
|
|
129
|
+
|
|
130
|
+
# TODO: Remove this!! It is very dangerous to do this here.
|
|
131
|
+
# The goal of this is to make the audit DSL available to all
|
|
132
|
+
# describe blocks. Right now, these blocks are executed outside
|
|
133
|
+
# the scope of this run, thus not gaining ony of the DSL pieces.
|
|
134
|
+
# To circumvent this, the full DSL is attached to the example's
|
|
135
|
+
# scope.
|
|
136
|
+
dsl = ctx.method(:create_inner_dsl).call(backend)
|
|
137
|
+
example.send(:include, dsl)
|
|
138
|
+
|
|
139
|
+
set_rspec_ids(example, rule_id)
|
|
140
|
+
@tests.register(example)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def set_rspec_ids(example, id)
|
|
145
|
+
example.metadata[:id] = id
|
|
146
|
+
example.filtered_examples.each do |e|
|
|
147
|
+
e.metadata[:id] = id
|
|
148
|
+
end
|
|
149
|
+
example.children.each do |child|
|
|
150
|
+
set_rspec_ids(child, id)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
data/lib/inspec/shell.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Dominik Richter
|
|
3
|
+
# author: Christoph Hartmann
|
|
4
|
+
|
|
5
|
+
module Inspec
|
|
6
|
+
class Shell
|
|
7
|
+
def initialize(runner)
|
|
8
|
+
@runner = runner
|
|
9
|
+
# load and configure pry
|
|
10
|
+
require 'pry'
|
|
11
|
+
configure_pry
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def start
|
|
15
|
+
# store context to run commands in this context
|
|
16
|
+
@runner.add_content('binding.pry', __FILE__, __LINE__)
|
|
17
|
+
@runner.run
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configure_pry
|
|
21
|
+
# Remove all hooks and checks
|
|
22
|
+
Pry.hooks.clear_all
|
|
23
|
+
that = self
|
|
24
|
+
|
|
25
|
+
# Add the help command
|
|
26
|
+
Pry::Commands.block_command 'usage', 'Show examples' do
|
|
27
|
+
that.usage
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Add a help menu as the default intro
|
|
31
|
+
Pry.hooks.add_hook(:before_session, :intro) do
|
|
32
|
+
intro
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def mark(x)
|
|
37
|
+
"\033[1m#{x}\033[0m"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def intro
|
|
41
|
+
puts 'Welcome to the interactive Inspec Shell'
|
|
42
|
+
puts "To find out how to use it, type: #{mark 'usage'}"
|
|
43
|
+
puts
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def usage
|
|
47
|
+
ctx = @runner.backend
|
|
48
|
+
puts <<EOF
|
|
49
|
+
|
|
50
|
+
Welcome to the interactive Inspec Shell.
|
|
51
|
+
|
|
52
|
+
You can use resources in this environment to test the target machine.
|
|
53
|
+
For example:
|
|
54
|
+
|
|
55
|
+
command('uname -a').stdout
|
|
56
|
+
file('/proc/cpuinfo').content
|
|
57
|
+
|
|
58
|
+
You are currently running on:
|
|
59
|
+
|
|
60
|
+
OS family: #{mark ctx.os[:family] || 'unknown'}
|
|
61
|
+
OS release: #{mark ctx.os[:release] || 'unknown'}
|
|
62
|
+
|
|
63
|
+
EOF
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|