inspec 1.0.0 → 1.35.1
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 +933 -101
- data/Gemfile +8 -17
- data/MAINTAINERS.md +2 -1
- data/MAINTAINERS.toml +9 -4
- data/README.md +49 -28
- data/Rakefile +54 -39
- data/bin/inspec +1 -1
- data/docs/dsl_inspec.md +17 -4
- data/docs/dsl_resource.md +1 -1
- data/docs/habitat.md +192 -0
- data/docs/inspec_and_friends.md +4 -2
- data/docs/matchers.md +11 -0
- data/docs/migration.md +293 -0
- data/docs/profiles.md +124 -76
- data/docs/resources/aide_conf.md.erb +81 -0
- data/docs/resources/apache_conf.md.erb +10 -10
- data/docs/resources/apt.md.erb +13 -13
- data/docs/resources/audit_policy.md.erb +10 -10
- data/docs/resources/auditd_conf.md.erb +10 -10
- data/docs/resources/auditd_rules.md.erb +11 -11
- data/docs/resources/bash.md.erb +12 -12
- data/docs/resources/bond.md.erb +15 -15
- data/docs/resources/bridge.md.erb +11 -11
- data/docs/resources/bsd_service.md.erb +11 -11
- data/docs/resources/command.md.erb +23 -23
- data/docs/resources/crontab.md.erb +84 -0
- data/docs/resources/csv.md.erb +10 -10
- data/docs/resources/dh_params.md +191 -0
- data/docs/resources/directory.md.erb +8 -8
- data/docs/resources/docker.md.erb +160 -0
- data/docs/resources/docker_container.md.erb +89 -0
- data/docs/resources/docker_image.md.erb +86 -0
- data/docs/resources/etc_group.md.erb +16 -16
- data/docs/resources/etc_hosts.md.erb +62 -0
- data/docs/resources/file.md.erb +80 -58
- data/docs/resources/gem.md.erb +32 -13
- data/docs/resources/group.md.erb +12 -12
- data/docs/resources/grub_conf.md.erb +11 -11
- data/docs/resources/host.md.erb +27 -18
- data/docs/resources/http.md.erb +104 -0
- data/docs/resources/iis_app.md.erb +126 -0
- data/docs/resources/iis_site.md.erb +17 -17
- data/docs/resources/inetd_conf.md.erb +10 -10
- data/docs/resources/ini.md.erb +9 -9
- data/docs/resources/interface.md.erb +13 -13
- data/docs/resources/iptables.md.erb +21 -14
- data/docs/resources/json.md.erb +11 -11
- data/docs/resources/kernel_module.md.erb +73 -12
- data/docs/resources/kernel_parameter.md.erb +12 -12
- data/docs/resources/key_rsa.md.erb +70 -0
- data/docs/resources/launchd_service.md.erb +11 -11
- data/docs/resources/limits_conf.md.erb +10 -10
- data/docs/resources/login_def.md.erb +12 -12
- data/docs/resources/mount.md.erb +14 -14
- data/docs/resources/mssql_session.md.erb +62 -0
- data/docs/resources/mysql_conf.md.erb +14 -14
- data/docs/resources/mysql_session.md.erb +22 -10
- data/docs/resources/npm.md.erb +13 -13
- data/docs/resources/ntp_conf.md.erb +9 -9
- data/docs/resources/oneget.md.erb +11 -11
- data/docs/resources/oracledb_session.md.erb +53 -0
- data/docs/resources/os.md.erb +17 -17
- data/docs/resources/os_env.md.erb +12 -12
- data/docs/resources/package.md.erb +29 -16
- data/docs/resources/parse_config.md.erb +18 -18
- data/docs/resources/parse_config_file.md.erb +29 -23
- data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +17 -17
- data/docs/resources/pip.md.erb +15 -15
- data/docs/resources/port.md.erb +23 -23
- data/docs/resources/postgres_conf.md.erb +15 -13
- data/docs/resources/postgres_hba_conf.md.erb +104 -0
- data/docs/resources/postgres_ident_conf.md.erb +87 -0
- data/docs/resources/postgres_session.md.erb +28 -21
- data/docs/resources/powershell.md.erb +14 -14
- data/docs/resources/processes.md.erb +123 -0
- data/docs/resources/rabbitmq_config.md.erb +55 -0
- data/docs/resources/registry_key.md.erb +44 -21
- data/docs/resources/runit_service.md.erb +11 -11
- data/docs/resources/security_policy.md.erb +10 -10
- data/docs/resources/service.md.erb +18 -18
- data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +19 -19
- data/docs/resources/ssh_config.md.erb +13 -13
- data/docs/resources/sshd_config.md.erb +15 -15
- data/docs/resources/ssl.md.erb +13 -13
- data/docs/resources/sys_info.md.erb +10 -10
- data/docs/resources/systemd_service.md.erb +11 -11
- data/docs/resources/sysv_service.md.erb +11 -11
- data/docs/resources/upstart_service.md.erb +11 -11
- data/docs/resources/user.md.erb +20 -20
- data/docs/resources/users.md.erb +19 -19
- data/docs/resources/vbscript.md.erb +13 -13
- data/docs/resources/virtualization.md.erb +71 -0
- data/docs/resources/windows_feature.md.erb +10 -10
- data/docs/resources/windows_task.md.erb +103 -0
- data/docs/resources/wmi.md.erb +10 -10
- data/docs/resources/x509_certificate.md.erb +146 -0
- data/docs/resources/xinetd_conf.md.erb +17 -17
- data/docs/resources/xml.md.erb +75 -0
- data/docs/resources/yaml.md.erb +25 -11
- data/docs/resources/yum.md.erb +24 -16
- data/docs/resources/zfs_dataset.md.erb +63 -0
- data/docs/resources/zfs_pool.md.erb +57 -0
- data/docs/ruby_usage.md +50 -0
- data/docs/shared/matcher_cmp.md.erb +4 -6
- data/examples/inheritance/README.md +49 -3
- data/examples/inheritance/controls/example.rb +4 -1
- data/examples/inheritance/inspec.yml +3 -1
- data/examples/meta-profile/README.md +29 -3
- data/examples/meta-profile/controls/example.rb +10 -5
- data/examples/meta-profile/inspec.yml +4 -8
- data/examples/profile/README.md +1 -1
- data/examples/profile/controls/example.rb +0 -1
- data/examples/profile/controls/gordon.rb +0 -1
- data/examples/profile/inspec.yml +1 -1
- data/examples/profile-attribute/inspec.yml +1 -1
- data/examples/profile-sensitive/README.md +29 -0
- data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
- data/examples/profile-sensitive/controls/sensitive.rb +9 -0
- data/examples/profile-sensitive/inspec.yml +8 -0
- data/inspec.gemspec +10 -2
- data/lib/bundles/inspec-artifact/README.md +1 -0
- data/lib/bundles/inspec-artifact/cli.rb +284 -0
- data/lib/bundles/inspec-artifact.rb +7 -0
- data/lib/bundles/inspec-compliance/README.md +44 -15
- data/lib/bundles/inspec-compliance/api.rb +135 -29
- data/lib/bundles/inspec-compliance/cli.rb +128 -21
- data/lib/bundles/inspec-compliance/configuration.rb +8 -0
- data/lib/bundles/inspec-compliance/http.rb +26 -19
- data/lib/bundles/inspec-compliance/target.rb +50 -25
- data/lib/bundles/inspec-habitat/cli.rb +31 -0
- data/lib/bundles/inspec-habitat/log.rb +10 -0
- data/lib/bundles/inspec-habitat/profile.rb +372 -0
- data/lib/bundles/inspec-habitat.rb +12 -0
- data/lib/bundles/inspec-init/templates/profile/controls/example.rb +0 -1
- data/lib/bundles/inspec-init/templates/profile/inspec.yml +1 -1
- data/lib/bundles/inspec-supermarket/api.rb +7 -5
- data/lib/bundles/inspec-supermarket/cli.rb +2 -2
- data/lib/fetchers/git.rb +4 -2
- data/lib/fetchers/local.rb +4 -1
- data/lib/fetchers/url.rb +64 -10
- data/lib/inspec/archive/tar.rb +1 -1
- data/lib/inspec/backend.rb +26 -3
- data/lib/inspec/base_cli.rb +44 -7
- data/lib/inspec/cached_fetcher.rb +2 -2
- data/lib/inspec/cli.rb +34 -12
- data/lib/inspec/completions/fish.sh.erb +34 -0
- data/lib/inspec/control_eval_context.rb +0 -2
- data/lib/inspec/dependencies/cache.rb +0 -1
- data/lib/inspec/dependencies/dependency_set.rb +2 -2
- data/lib/inspec/dependencies/lockfile.rb +13 -6
- data/lib/inspec/dependencies/requirement.rb +6 -6
- data/lib/inspec/dependencies/resolver.rb +4 -4
- data/lib/inspec/dsl.rb +3 -5
- data/lib/inspec/env_printer.rb +9 -1
- data/lib/inspec/exceptions.rb +8 -0
- data/lib/inspec/fetcher.rb +1 -1
- data/lib/inspec/file_provider.rb +47 -11
- data/lib/inspec/library_eval_context.rb +1 -1
- data/lib/inspec/metadata.rb +62 -18
- data/lib/inspec/method_source.rb +24 -0
- data/lib/inspec/objects/attribute.rb +21 -0
- data/lib/inspec/objects/control.rb +21 -3
- data/lib/inspec/objects/each_loop.rb +2 -1
- data/lib/inspec/objects/list.rb +1 -1
- data/lib/inspec/objects/or_test.rb +17 -2
- data/lib/inspec/objects/tag.rb +27 -0
- data/lib/inspec/objects/test.rb +9 -8
- data/lib/inspec/objects.rb +1 -0
- data/lib/inspec/plugins/fetcher.rb +4 -5
- data/lib/inspec/plugins/resource.rb +1 -2
- data/lib/inspec/plugins/source_reader.rb +3 -3
- data/lib/inspec/plugins.rb +1 -1
- data/lib/inspec/polyfill.rb +0 -1
- data/lib/inspec/profile.rb +92 -23
- data/lib/inspec/profile_context.rb +1 -1
- data/lib/inspec/profile_vendor.rb +66 -0
- data/lib/inspec/resource.rb +29 -3
- data/lib/inspec/rspec_json_formatter.rb +672 -285
- data/lib/inspec/rule.rb +12 -16
- data/lib/inspec/runner.rb +26 -15
- data/lib/inspec/runner_rspec.rb +1 -0
- data/lib/inspec/runtime_profile.rb +26 -0
- data/lib/inspec/schema.rb +185 -0
- data/lib/inspec/secrets/yaml.rb +8 -1
- data/lib/inspec/secrets.rb +1 -1
- data/lib/inspec/shell.rb +92 -22
- data/lib/inspec/source_reader.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec.rb +1 -1
- data/lib/matchers/matchers.rb +67 -17
- data/lib/resources/aide_conf.rb +162 -0
- data/lib/resources/apache.rb +0 -1
- data/lib/resources/apache_conf.rb +3 -3
- data/lib/resources/apt.rb +2 -1
- data/lib/resources/audit_policy.rb +0 -1
- data/lib/resources/auditd_conf.rb +1 -2
- data/lib/resources/auditd_rules.rb +5 -5
- data/lib/resources/bond.rb +1 -1
- data/lib/resources/bridge.rb +1 -1
- data/lib/resources/command.rb +5 -3
- data/lib/resources/crontab.rb +102 -0
- data/lib/resources/csv.rb +18 -1
- data/lib/resources/dh_params.rb +84 -0
- data/lib/resources/directory.rb +7 -3
- data/lib/resources/docker.rb +198 -0
- data/lib/resources/docker_container.rb +114 -0
- data/lib/resources/docker_image.rb +96 -0
- data/lib/resources/etc_group.rb +2 -3
- data/lib/resources/etc_hosts.rb +81 -0
- data/lib/resources/file.rb +88 -30
- data/lib/resources/gem.rb +26 -6
- data/lib/resources/groups.rb +4 -5
- data/lib/resources/grub_conf.rb +3 -4
- data/lib/resources/host.rb +175 -35
- data/lib/resources/http.rb +73 -0
- data/lib/resources/iis_app.rb +103 -0
- data/lib/resources/iis_site.rb +23 -0
- data/lib/resources/inetd_conf.rb +9 -4
- data/lib/resources/interface.rb +4 -3
- data/lib/resources/json.rb +37 -14
- data/lib/resources/kernel_module.rb +77 -10
- data/lib/resources/kernel_parameter.rb +0 -1
- data/lib/resources/key_rsa.rb +67 -0
- data/lib/resources/limits_conf.rb +3 -4
- data/lib/resources/login_def.rb +2 -3
- data/lib/resources/mount.rb +34 -4
- data/lib/resources/mssql_session.rb +81 -12
- data/lib/resources/mysql.rb +0 -1
- data/lib/resources/mysql_conf.rb +1 -2
- data/lib/resources/mysql_session.rb +18 -7
- data/lib/resources/nginx_conf.rb +95 -0
- data/lib/resources/ntp_conf.rb +2 -3
- data/lib/resources/oracledb_session.rb +138 -0
- data/lib/resources/os_env.rb +7 -5
- data/lib/resources/package.rb +70 -13
- data/lib/resources/packages.rb +111 -0
- data/lib/resources/parse_config.rb +3 -4
- data/lib/resources/passwd.rb +4 -5
- data/lib/resources/pip.rb +29 -21
- data/lib/resources/port.rb +133 -14
- data/lib/resources/postgres.rb +53 -43
- data/lib/resources/postgres_conf.rb +40 -13
- data/lib/resources/postgres_hba_conf.rb +101 -0
- data/lib/resources/postgres_ident_conf.rb +79 -0
- data/lib/resources/postgres_session.rb +28 -20
- data/lib/resources/powershell.rb +2 -2
- data/lib/resources/processes.rb +61 -26
- data/lib/resources/rabbitmq_conf.rb +53 -0
- data/lib/resources/registry_key.rb +34 -11
- data/lib/resources/security_policy.rb +2 -2
- data/lib/resources/service.rb +17 -7
- data/lib/resources/ssh_conf.rb +17 -6
- data/lib/resources/ssl.rb +3 -4
- data/lib/resources/sys_info.rb +1 -1
- data/lib/resources/toml.rb +26 -0
- data/lib/resources/users.rb +41 -41
- data/lib/resources/virtualization.rb +252 -0
- data/lib/resources/windows_task.rb +106 -0
- data/lib/resources/x509_certificate.rb +143 -0
- data/lib/resources/xinetd.rb +18 -2
- data/lib/resources/xml.rb +27 -0
- data/lib/resources/yaml.rb +10 -2
- data/lib/resources/yum.rb +25 -7
- data/lib/resources/zfs_dataset.rb +60 -0
- data/lib/resources/zfs_pool.rb +49 -0
- data/lib/source_readers/flat.rb +2 -1
- data/lib/source_readers/inspec.rb +30 -11
- data/lib/utils/command_wrapper.rb +3 -3
- data/lib/utils/database_helpers.rb +77 -0
- data/lib/utils/erlang_parser.rb +192 -0
- data/lib/utils/filter.rb +2 -1
- data/lib/utils/filter_array.rb +0 -1
- data/lib/utils/find_files.rb +1 -2
- data/lib/utils/latest_version.rb +21 -0
- data/lib/utils/nginx_parser.rb +76 -0
- data/lib/utils/object_traversal.rb +5 -4
- data/lib/utils/parser.rb +23 -4
- data/lib/utils/plugin_registry.rb +3 -3
- data/lib/utils/simpleconfig.rb +25 -8
- data/lib/utils/spdx.rb +13 -0
- data/lib/utils/spdx.txt +344 -0
- metadata +168 -22
- data/docs/cli.md +0 -342
- data/docs/resources/process.md.erb +0 -73
- /data/docs/{plugin_kitchen_inspec.html.md → plugin_kitchen_inspec.md} +0 -0
data/lib/resources/file.rb
CHANGED
|
@@ -2,12 +2,24 @@
|
|
|
2
2
|
# copyright: 2015, Vulcano Security GmbH
|
|
3
3
|
# author: Dominik Richter
|
|
4
4
|
# author: Christoph Hartmann
|
|
5
|
-
# license: All rights reserved
|
|
6
5
|
|
|
7
6
|
require 'shellwords'
|
|
8
7
|
|
|
9
8
|
module Inspec::Resources
|
|
10
|
-
|
|
9
|
+
module FilePermissionsSelector
|
|
10
|
+
def select_file_perms_style(os)
|
|
11
|
+
if os.unix?
|
|
12
|
+
UnixFilePermissions.new(inspec)
|
|
13
|
+
elsif os.windows?
|
|
14
|
+
WindowsFilePermissions.new(inspec)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class FileResource < Inspec.resource(1)
|
|
20
|
+
include FilePermissionsSelector
|
|
21
|
+
include LinuxMountParser
|
|
22
|
+
|
|
11
23
|
name 'file'
|
|
12
24
|
desc 'Use the file InSpec audit resource to test all system file types, including files, directories, symbolic links, named pipes, sockets, character devices, block devices, and doors.'
|
|
13
25
|
example "
|
|
@@ -16,14 +28,16 @@ module Inspec::Resources
|
|
|
16
28
|
it { should be_file }
|
|
17
29
|
it { should be_readable }
|
|
18
30
|
it { should be_writable }
|
|
31
|
+
it { should be_executable.by_user('root') }
|
|
19
32
|
it { should be_owned_by 'root' }
|
|
20
33
|
its('mode') { should cmp '0644' }
|
|
21
34
|
end
|
|
22
35
|
"
|
|
23
|
-
include MountParser
|
|
24
36
|
|
|
25
37
|
attr_reader :file, :mount_options
|
|
26
38
|
def initialize(path)
|
|
39
|
+
# select permissions style
|
|
40
|
+
@perms_provider = select_file_perms_style(inspec.os)
|
|
27
41
|
@file = inspec.backend.file(path)
|
|
28
42
|
end
|
|
29
43
|
|
|
@@ -46,25 +60,28 @@ module Inspec::Resources
|
|
|
46
60
|
end
|
|
47
61
|
|
|
48
62
|
def contain(*_)
|
|
49
|
-
|
|
63
|
+
raise 'Contain is not supported. Please use standard RSpec matchers.'
|
|
50
64
|
end
|
|
51
65
|
|
|
52
66
|
def readable?(by_usergroup, by_specific_user)
|
|
53
67
|
return false unless exist?
|
|
68
|
+
return skip_resource '`readable?` is not supported on your OS yet.' if @perms_provider.nil?
|
|
54
69
|
|
|
55
|
-
file_permission_granted?('
|
|
70
|
+
file_permission_granted?('read', by_usergroup, by_specific_user)
|
|
56
71
|
end
|
|
57
72
|
|
|
58
73
|
def writable?(by_usergroup, by_specific_user)
|
|
59
74
|
return false unless exist?
|
|
75
|
+
return skip_resource '`writable?` is not supported on your OS yet.' if @perms_provider.nil?
|
|
60
76
|
|
|
61
|
-
file_permission_granted?('
|
|
77
|
+
file_permission_granted?('write', by_usergroup, by_specific_user)
|
|
62
78
|
end
|
|
63
79
|
|
|
64
80
|
def executable?(by_usergroup, by_specific_user)
|
|
65
81
|
return false unless exist?
|
|
82
|
+
return skip_resource '`executable?` is not supported on your OS yet.' if @perms_provider.nil?
|
|
66
83
|
|
|
67
|
-
file_permission_granted?('
|
|
84
|
+
file_permission_granted?('execute', by_usergroup, by_specific_user)
|
|
68
85
|
end
|
|
69
86
|
|
|
70
87
|
def mounted?(expected_options = nil, identical = false)
|
|
@@ -109,35 +126,65 @@ module Inspec::Resources
|
|
|
109
126
|
|
|
110
127
|
private
|
|
111
128
|
|
|
112
|
-
def file_permission_granted?(
|
|
113
|
-
|
|
114
|
-
|
|
129
|
+
def file_permission_granted?(access_type, by_usergroup, by_specific_user)
|
|
130
|
+
raise '`file_permission_granted?` is not supported on your OS' if @perms_provider.nil?
|
|
131
|
+
if by_specific_user.nil? || by_specific_user.empty?
|
|
132
|
+
@perms_provider.check_file_permission_by_mask(file, access_type, by_usergroup, by_specific_user)
|
|
133
|
+
else
|
|
134
|
+
@perms_provider.check_file_permission_by_user(access_type, by_specific_user, source_path)
|
|
115
135
|
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
116
138
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
139
|
+
class FilePermissions
|
|
140
|
+
attr_reader :inspec
|
|
141
|
+
def initialize(inspec)
|
|
142
|
+
@inspec = inspec
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
class UnixFilePermissions < FilePermissions
|
|
147
|
+
def permission_flag(access_type)
|
|
148
|
+
case access_type
|
|
149
|
+
when 'read'
|
|
150
|
+
'r'
|
|
151
|
+
when 'write'
|
|
152
|
+
'w'
|
|
153
|
+
when 'execute'
|
|
154
|
+
'x'
|
|
120
155
|
else
|
|
121
|
-
|
|
156
|
+
raise 'Invalid access_type provided'
|
|
122
157
|
end
|
|
123
158
|
end
|
|
124
159
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
160
|
+
def usergroup_for(usergroup, specific_user)
|
|
161
|
+
if usergroup == 'others'
|
|
162
|
+
'other'
|
|
163
|
+
elsif (usergroup.nil? || usergroup.empty?) && specific_user.nil?
|
|
164
|
+
'all'
|
|
165
|
+
else
|
|
166
|
+
usergroup
|
|
167
|
+
end
|
|
168
|
+
end
|
|
128
169
|
|
|
170
|
+
def check_file_permission_by_mask(file, access_type, usergroup, specific_user)
|
|
171
|
+
usergroup = usergroup_for(usergroup, specific_user)
|
|
172
|
+
flag = permission_flag(access_type)
|
|
173
|
+
mask = file.unix_mode_mask(usergroup, flag)
|
|
174
|
+
raise 'Invalid usergroup/owner provided' if mask.nil?
|
|
129
175
|
(file.mode & mask) != 0
|
|
130
176
|
end
|
|
131
177
|
|
|
132
|
-
def check_file_permission_by_user(user,
|
|
178
|
+
def check_file_permission_by_user(access_type, user, path)
|
|
179
|
+
flag = permission_flag(access_type)
|
|
133
180
|
if inspec.os.linux?
|
|
134
|
-
perm_cmd = "su -s /bin/sh -c \"test -#{flag} #{
|
|
181
|
+
perm_cmd = "su -s /bin/sh -c \"test -#{flag} #{path}\" #{user}"
|
|
135
182
|
elsif inspec.os.bsd? || inspec.os.solaris?
|
|
136
|
-
perm_cmd = "sudo -u #{user} test -#{flag} #{
|
|
183
|
+
perm_cmd = "sudo -u #{user} test -#{flag} #{path}"
|
|
137
184
|
elsif inspec.os.aix?
|
|
138
|
-
perm_cmd = "su #{user} -c test -#{flag} #{
|
|
185
|
+
perm_cmd = "su #{user} -c test -#{flag} #{path}"
|
|
139
186
|
elsif inspec.os.hpux?
|
|
140
|
-
perm_cmd = "su #{user} -c \"test -#{flag} #{
|
|
187
|
+
perm_cmd = "su #{user} -c \"test -#{flag} #{path}\""
|
|
141
188
|
else
|
|
142
189
|
return skip_resource 'The `file` resource does not support `by_user` on your OS.'
|
|
143
190
|
end
|
|
@@ -145,15 +192,26 @@ module Inspec::Resources
|
|
|
145
192
|
cmd = inspec.command(perm_cmd)
|
|
146
193
|
cmd.exit_status == 0 ? true : false
|
|
147
194
|
end
|
|
195
|
+
end
|
|
148
196
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
197
|
+
class WindowsFilePermissions < FilePermissions
|
|
198
|
+
def check_file_permission_by_mask(_file, _access_type, _usergroup, _specific_user)
|
|
199
|
+
raise '`check_file_permission_by_mask` is not supported on Windows'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def check_file_permission_by_user(access_type, user, path)
|
|
203
|
+
access_rule = case access_type
|
|
204
|
+
when 'read'
|
|
205
|
+
'@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'Read\', \'ListDirectory\')'
|
|
206
|
+
when 'write'
|
|
207
|
+
'@(\'FullControl\', \'Modify\', \'Write\')'
|
|
208
|
+
when 'execute'
|
|
209
|
+
'@(\'FullControl\', \'Modify\', \'ReadAndExecute\', \'ExecuteFile\')'
|
|
210
|
+
else
|
|
211
|
+
raise 'Invalid access_type provided'
|
|
212
|
+
end
|
|
213
|
+
cmd = inspec.command("@(@((Get-Acl '#{path}').access | Where-Object {$_.AccessControlType -eq 'Allow' -and $_.IdentityReference -eq '#{user}' }) | Where-Object {($_.FileSystemRights.ToString().Split(',') | % {$_.trim()} | ? {#{access_rule} -contains $_}) -ne $null}) | measure | % { $_.Count }")
|
|
214
|
+
cmd.stdout.chomp == '0' ? false : true
|
|
157
215
|
end
|
|
158
216
|
end
|
|
159
217
|
end
|
data/lib/resources/gem.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# author: Christoph Hartmann
|
|
3
3
|
# author: Dominik Richter
|
|
4
|
+
# author: Joe Nuspl
|
|
4
5
|
|
|
5
6
|
module Inspec::Resources
|
|
6
7
|
class GemPackage < Inspec.resource(1)
|
|
@@ -13,23 +14,42 @@ module Inspec::Resources
|
|
|
13
14
|
end
|
|
14
15
|
"
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
attr_reader :gem_binary
|
|
18
|
+
|
|
19
|
+
def initialize(package_name, gem_binary = nil)
|
|
17
20
|
@package_name = package_name
|
|
21
|
+
@gem_binary = case gem_binary
|
|
22
|
+
when nil
|
|
23
|
+
'gem'
|
|
24
|
+
when :chef
|
|
25
|
+
if inspec.os.windows?
|
|
26
|
+
'c:\opscode\chef\embedded\bin\gem.bat'
|
|
27
|
+
else
|
|
28
|
+
'/opt/chef/embedded/bin/gem'
|
|
29
|
+
end
|
|
30
|
+
when :chef_server
|
|
31
|
+
'/opt/opscode/embedded/bin/gem'
|
|
32
|
+
else
|
|
33
|
+
gem_binary
|
|
34
|
+
end
|
|
35
|
+
skip_resource 'Unable to retrieve gem information' if info.empty?
|
|
18
36
|
end
|
|
19
37
|
|
|
20
38
|
def info
|
|
21
39
|
return @info if defined?(@info)
|
|
22
40
|
|
|
23
|
-
cmd = inspec.command("
|
|
41
|
+
cmd = inspec.command("#{@gem_binary} list --local -a -q \^#{@package_name}\$")
|
|
42
|
+
return {} unless cmd.exit_status.zero?
|
|
43
|
+
|
|
44
|
+
# extract package name and version
|
|
45
|
+
# parses data like winrm (1.3.4, 1.3.3)
|
|
46
|
+
params = /^\s*([^\(]*?)\s*\((.*?)\)\s*$/.match(cmd.stdout.chomp)
|
|
24
47
|
@info = {
|
|
25
|
-
installed:
|
|
48
|
+
installed: !params.nil?,
|
|
26
49
|
type: 'gem',
|
|
27
50
|
}
|
|
28
51
|
return @info unless @info[:installed]
|
|
29
52
|
|
|
30
|
-
# extract package name and version
|
|
31
|
-
# parses data like winrm (1.3.4, 1.3.3)
|
|
32
|
-
params = /^\s*([^\(]*?)\s*\((.*?)\)\s*$/.match(cmd.stdout.chomp)
|
|
33
53
|
versions = params[2].split(',')
|
|
34
54
|
@info[:name] = params[1]
|
|
35
55
|
@info[:version] = versions[0]
|
data/lib/resources/groups.rb
CHANGED
|
@@ -90,7 +90,6 @@ module Inspec::Resources
|
|
|
90
90
|
|
|
91
91
|
def initialize(groupname)
|
|
92
92
|
@group = groupname
|
|
93
|
-
@group = @group.downcase unless inspec.os.windows?
|
|
94
93
|
|
|
95
94
|
# select group manager
|
|
96
95
|
@group_provider = select_group_manager(inspec.os)
|
|
@@ -99,18 +98,18 @@ module Inspec::Resources
|
|
|
99
98
|
|
|
100
99
|
# verifies if a group exists
|
|
101
100
|
def exists?
|
|
102
|
-
group_info.entries.
|
|
101
|
+
!group_info.entries.empty?
|
|
103
102
|
end
|
|
104
103
|
|
|
105
104
|
def gid
|
|
106
105
|
gids = group_info.gids
|
|
107
|
-
if gids.
|
|
106
|
+
if gids.empty?
|
|
108
107
|
nil
|
|
109
108
|
# the default case should be one group
|
|
110
109
|
elsif gids.size == 1
|
|
111
110
|
gids.entries[0]
|
|
112
111
|
else
|
|
113
|
-
|
|
112
|
+
raise 'found more than one group with the same name, please use `groups` resource'
|
|
114
113
|
end
|
|
115
114
|
end
|
|
116
115
|
|
|
@@ -144,7 +143,7 @@ module Inspec::Resources
|
|
|
144
143
|
end
|
|
145
144
|
|
|
146
145
|
def groups
|
|
147
|
-
|
|
146
|
+
raise 'group provider must implement the `groups` method'
|
|
148
147
|
end
|
|
149
148
|
end
|
|
150
149
|
|
data/lib/resources/grub_conf.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# author: Thomas Cate
|
|
3
|
-
# license: All rights reserved
|
|
4
3
|
|
|
5
4
|
require 'utils/simpleconfig'
|
|
6
5
|
|
|
@@ -38,11 +37,11 @@ class GrubConfig < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
|
|
38
37
|
@conf_path = path || '/boot/grub/grub.cfg'
|
|
39
38
|
@defaults_path = '/etc/default/grub'
|
|
40
39
|
@version = 'grub2'
|
|
41
|
-
elsif os[:name] == 'amazon'
|
|
40
|
+
elsif os[:name] == 'amazon'
|
|
42
41
|
@conf_path = path || '/etc/grub.conf'
|
|
43
42
|
@version = 'legacy'
|
|
44
43
|
else
|
|
45
|
-
|
|
44
|
+
raise UnknownGrubConfig
|
|
46
45
|
end
|
|
47
46
|
end
|
|
48
47
|
|
|
@@ -145,7 +144,7 @@ class GrubConfig < Inspec.resource(1) # rubocop:disable Metrics/ClassLength
|
|
|
145
144
|
|
|
146
145
|
content = file.content
|
|
147
146
|
|
|
148
|
-
if content.empty? && file.
|
|
147
|
+
if content.empty? && !file.empty?
|
|
149
148
|
skip_resource "Can't read file '#{@conf_path}'"
|
|
150
149
|
return @params = {}
|
|
151
150
|
end
|
data/lib/resources/host.rb
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# end
|
|
11
11
|
#
|
|
12
12
|
# To verify a hostname with protocol and port
|
|
13
|
-
# describe host('example.com', port:
|
|
13
|
+
# describe host('example.com', port: 443, protocol: 'tcp') do
|
|
14
14
|
# it { should be_reachable }
|
|
15
15
|
# end
|
|
16
16
|
#
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
# it { should be_resolvable.by('dns') }
|
|
25
25
|
# end
|
|
26
26
|
|
|
27
|
+
require 'resolv'
|
|
28
|
+
|
|
27
29
|
module Inspec::Resources
|
|
28
30
|
class Host < Inspec.resource(1)
|
|
29
31
|
name 'host'
|
|
@@ -31,26 +33,51 @@ module Inspec::Resources
|
|
|
31
33
|
example "
|
|
32
34
|
describe host('example.com') do
|
|
33
35
|
it { should be_reachable }
|
|
36
|
+
it { should be_resolvable }
|
|
37
|
+
its('ipaddress') { should include '12.34.56.78' }
|
|
34
38
|
end
|
|
35
39
|
|
|
36
|
-
describe host('example.com', port: '80') do
|
|
40
|
+
describe host('example.com', port: '80', protocol: 'tcp') do
|
|
37
41
|
it { should be_reachable }
|
|
38
42
|
end
|
|
39
43
|
"
|
|
40
44
|
|
|
45
|
+
attr_reader :hostname, :port, :protocol
|
|
46
|
+
|
|
41
47
|
def initialize(hostname, params = {})
|
|
42
48
|
@hostname = hostname
|
|
43
|
-
@port = params[:port]
|
|
44
|
-
|
|
49
|
+
@port = params[:port]
|
|
50
|
+
|
|
51
|
+
if params[:proto]
|
|
52
|
+
warn '[DEPRECATION] The `proto` parameter is deprecated. Use `protocol` instead.'
|
|
53
|
+
@protocol = params[:proto]
|
|
54
|
+
else
|
|
55
|
+
@protocol = params.fetch(:protocol, 'icmp')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return skip_resource 'Invalid protocol: only `tcp` and `icmp` protocols are support for the `host` resource.' unless
|
|
59
|
+
%w{icmp tcp}.include?(@protocol)
|
|
45
60
|
|
|
46
61
|
@host_provider = nil
|
|
47
62
|
if inspec.os.linux?
|
|
48
63
|
@host_provider = LinuxHostProvider.new(inspec)
|
|
49
64
|
elsif inspec.os.windows?
|
|
50
65
|
@host_provider = WindowsHostProvider.new(inspec)
|
|
66
|
+
elsif inspec.os.darwin?
|
|
67
|
+
@host_provider = DarwinHostProvider.new(inspec)
|
|
51
68
|
else
|
|
52
69
|
return skip_resource 'The `host` resource is not supported on your OS yet.'
|
|
53
70
|
end
|
|
71
|
+
|
|
72
|
+
missing_requirements = @host_provider.missing_requirements(protocol)
|
|
73
|
+
unless missing_requirements.empty?
|
|
74
|
+
return skip_resource "The following requirements are not met for this resource: #{missing_requirements.join(', ')}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def proto
|
|
79
|
+
warn '[DEPRECATION] The `proto` method is deprecated. Use `protocol` instead.'
|
|
80
|
+
protocol
|
|
54
81
|
end
|
|
55
82
|
|
|
56
83
|
# if we get the IP address, the host is resolvable
|
|
@@ -59,9 +86,25 @@ module Inspec::Resources
|
|
|
59
86
|
resolve.nil? || resolve.empty? ? false : true
|
|
60
87
|
end
|
|
61
88
|
|
|
62
|
-
def reachable?
|
|
63
|
-
|
|
64
|
-
ping.
|
|
89
|
+
def reachable?
|
|
90
|
+
# ping checks do not require port or protocol
|
|
91
|
+
return ping.fetch(:success, false) if protocol == 'icmp'
|
|
92
|
+
|
|
93
|
+
# if either port or protocol are specified but not both, we cannot proceed.
|
|
94
|
+
if port.nil? || protocol.nil?
|
|
95
|
+
raise "Protocol required with port. Use `host` resource with host('#{hostname}', port: 1234, proto: 'tcp') parameters." if port.nil? || protocol.nil?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# perform the protocol-specific reachability test
|
|
99
|
+
ping.fetch(:success, false)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def connection
|
|
103
|
+
ping[:connection]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def socket
|
|
107
|
+
ping[:socket]
|
|
65
108
|
end
|
|
66
109
|
|
|
67
110
|
# returns all A records of the IP address, will return an array
|
|
@@ -70,19 +113,21 @@ module Inspec::Resources
|
|
|
70
113
|
end
|
|
71
114
|
|
|
72
115
|
def to_s
|
|
73
|
-
"Host #{
|
|
116
|
+
"Host #{hostname}"
|
|
74
117
|
end
|
|
75
118
|
|
|
76
119
|
private
|
|
77
120
|
|
|
78
121
|
def ping
|
|
79
122
|
return @ping_cache if defined?(@ping_cache)
|
|
80
|
-
|
|
123
|
+
return {} if @host_provider.nil?
|
|
124
|
+
|
|
125
|
+
@ping_cache = @host_provider.ping(hostname, port, protocol)
|
|
81
126
|
end
|
|
82
127
|
|
|
83
128
|
def resolve
|
|
84
129
|
return @ip_cache if defined?(@ip_cache)
|
|
85
|
-
@ip_cache = @host_provider.resolve(
|
|
130
|
+
@ip_cache = @host_provider.resolve(hostname) if !@host_provider.nil?
|
|
86
131
|
end
|
|
87
132
|
end
|
|
88
133
|
|
|
@@ -91,25 +136,128 @@ module Inspec::Resources
|
|
|
91
136
|
def initialize(inspec)
|
|
92
137
|
@inspec = inspec
|
|
93
138
|
end
|
|
139
|
+
|
|
140
|
+
def missing_requirements(_protocol)
|
|
141
|
+
# each provider can return an array of missing requirements that can
|
|
142
|
+
# be enumerated in a skip_resource message
|
|
143
|
+
[]
|
|
144
|
+
end
|
|
94
145
|
end
|
|
95
146
|
|
|
96
|
-
class
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
147
|
+
class UnixHostProvider < HostProvider
|
|
148
|
+
def resolve_with_dig(hostname)
|
|
149
|
+
addresses = []
|
|
150
|
+
|
|
151
|
+
# look for IPv4 addresses
|
|
152
|
+
cmd = inspec.command("dig +short A #{hostname}")
|
|
153
|
+
cmd.stdout.lines.each do |line|
|
|
154
|
+
matched = line.chomp.match(Resolv::IPv4::Regex)
|
|
155
|
+
addresses << matched.to_s unless matched.nil?
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# look for IPv6 addresses
|
|
159
|
+
cmd = inspec.command("dig +short AAAA #{hostname}")
|
|
160
|
+
cmd.stdout.lines.each do |line|
|
|
161
|
+
matched = line.chomp.match(Resolv::IPv6::Regex)
|
|
162
|
+
addresses << matched.to_s unless matched.nil?
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
addresses.empty? ? nil : addresses
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def resolve_with_getent(hostname)
|
|
169
|
+
cmd = inspec.command("getent ahosts #{hostname}")
|
|
170
|
+
return nil unless cmd.exit_status.to_i.zero?
|
|
171
|
+
|
|
172
|
+
# getent ahosts output is formatted like so:
|
|
173
|
+
# $ getent ahosts www.google.com
|
|
174
|
+
# 172.217.8.4 STREAM www.google.com
|
|
175
|
+
# 172.217.8.4 DGRAM
|
|
176
|
+
# 172.217.8.4 RAW
|
|
177
|
+
# 2607:f8b0:4004:803::2004 STREAM
|
|
178
|
+
# 2607:f8b0:4004:803::2004 DGRAM
|
|
179
|
+
# 2607:f8b0:4004:803::2004 RAW
|
|
180
|
+
addresses = []
|
|
181
|
+
cmd.stdout.lines.each do |line|
|
|
182
|
+
ip, = line.split(/\s+/, 2)
|
|
183
|
+
next unless ip.match(Resolv::IPv4::Regex) || ip.match(Resolv::IPv6::Regex)
|
|
184
|
+
addresses << ip unless addresses.include?(ip)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
addresses
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
class DarwinHostProvider < UnixHostProvider
|
|
192
|
+
def missing_requirements(protocol)
|
|
193
|
+
missing = []
|
|
194
|
+
|
|
195
|
+
if protocol == 'tcp'
|
|
196
|
+
missing << 'netcat must be installed' unless inspec.command('nc').exist?
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
missing
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def ping(hostname, port, protocol)
|
|
203
|
+
if protocol == 'tcp'
|
|
204
|
+
resp = inspec.command("nc -vz -G 1 #{hostname} #{port}")
|
|
205
|
+
else
|
|
206
|
+
resp = inspec.command("ping -W 1 -c 1 #{hostname}")
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
{
|
|
210
|
+
success: resp.exit_status.to_i.zero?,
|
|
211
|
+
connection: resp.stderr,
|
|
212
|
+
socket: resp.stdout,
|
|
213
|
+
}
|
|
103
214
|
end
|
|
104
215
|
|
|
105
216
|
def resolve(hostname)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
217
|
+
resolve_with_dig(hostname)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
class LinuxHostProvider < UnixHostProvider
|
|
222
|
+
def missing_requirements(protocol)
|
|
223
|
+
missing = []
|
|
109
224
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
225
|
+
if protocol == 'tcp' && (!inspec.command('nc').exist? && !inspec.command('ncat').exist?)
|
|
226
|
+
missing << 'netcat must be installed'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
missing
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def ping(hostname, port, protocol)
|
|
233
|
+
if protocol == 'tcp'
|
|
234
|
+
resp = inspec.command(tcp_check_command(hostname, port))
|
|
235
|
+
else
|
|
236
|
+
# fall back to ping, but we can only test ICMP packages with ping
|
|
237
|
+
resp = inspec.command("ping -w 1 -c 1 #{hostname}")
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
{
|
|
241
|
+
success: resp.exit_status.to_i.zero?,
|
|
242
|
+
connection: resp.stderr,
|
|
243
|
+
socket: resp.stdout,
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def tcp_check_command(hostname, port)
|
|
248
|
+
if inspec.command('nc').exist?
|
|
249
|
+
base_cmd = 'nc'
|
|
250
|
+
elsif inspec.command('ncat').exist?
|
|
251
|
+
base_cmd = 'ncat'
|
|
252
|
+
else
|
|
253
|
+
return
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
"echo | #{base_cmd} -v -w 1 #{hostname} #{port}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def resolve(hostname)
|
|
260
|
+
resolve_with_getent(hostname)
|
|
113
261
|
end
|
|
114
262
|
end
|
|
115
263
|
|
|
@@ -118,13 +266,10 @@ module Inspec::Resources
|
|
|
118
266
|
# @see http://blogs.technet.com/b/josebda/archive/2015/04/18/windows-powershell-equivalents-for-common-networking-commands-ipconfig-ping-nslookup.aspx
|
|
119
267
|
# @see http://blogs.technet.com/b/heyscriptingguy/archive/2014/03/19/creating-a-port-scanner-with-windows-powershell.aspx
|
|
120
268
|
class WindowsHostProvider < HostProvider
|
|
121
|
-
def ping(hostname, port = nil,
|
|
122
|
-
# TODO: abort if we cannot run it via udp
|
|
123
|
-
return nil if proto == 'udp'
|
|
124
|
-
|
|
269
|
+
def ping(hostname, port = nil, _proto = nil)
|
|
125
270
|
# ICMP: Test-NetConnection www.microsoft.com
|
|
126
271
|
# TCP and port: Test-NetConnection -ComputerName www.microsoft.com -RemotePort 80
|
|
127
|
-
request = "Test-NetConnection -ComputerName #{hostname}"
|
|
272
|
+
request = "Test-NetConnection -ComputerName #{hostname} -WarningAction SilentlyContinue"
|
|
128
273
|
request += " -RemotePort #{port}" unless port.nil?
|
|
129
274
|
request += '| Select-Object -Property ComputerName, TcpTestSucceeded, PingSucceeded | ConvertTo-Json'
|
|
130
275
|
cmd = inspec.command(request)
|
|
@@ -132,15 +277,10 @@ module Inspec::Resources
|
|
|
132
277
|
begin
|
|
133
278
|
ping = JSON.parse(cmd.stdout)
|
|
134
279
|
rescue JSON::ParserError => _e
|
|
135
|
-
return
|
|
280
|
+
return {}
|
|
136
281
|
end
|
|
137
282
|
|
|
138
|
-
|
|
139
|
-
if port.nil?
|
|
140
|
-
ping['PingSucceeded']
|
|
141
|
-
else
|
|
142
|
-
ping['TcpTestSucceeded']
|
|
143
|
-
end
|
|
283
|
+
{ success: port.nil? ? ping['PingSucceeded'] : ping['TcpTestSucceeded'] }
|
|
144
284
|
end
|
|
145
285
|
|
|
146
286
|
def resolve(hostname)
|