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/matchers/matchers.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
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
|
RSpec::Matchers.define :be_readable do
|
|
8
7
|
match do |file|
|
|
@@ -70,7 +69,7 @@ end
|
|
|
70
69
|
# matcher to check /etc/passwd, /etc/shadow and /etc/group
|
|
71
70
|
RSpec::Matchers.define :contain_legacy_plus do
|
|
72
71
|
match do |file|
|
|
73
|
-
warn '[DEPRECATION] `contain_legacy_plus` is deprecated and will be removed
|
|
72
|
+
warn '[DEPRECATION] `contain_legacy_plus` is deprecated and will be removed in the next major version. Please use `describe file(\'/etc/passwd\') do its(\'content\') { should_not match /^\+:/ } end`'
|
|
74
73
|
file.content =~ /^\+:/
|
|
75
74
|
end
|
|
76
75
|
end
|
|
@@ -78,7 +77,7 @@ end
|
|
|
78
77
|
# verifies that no entry in an array contains a value
|
|
79
78
|
RSpec::Matchers.define :contain_match do |regex|
|
|
80
79
|
match do |arr|
|
|
81
|
-
warn '[DEPRECATION] `contain_match` is deprecated and will be removed
|
|
80
|
+
warn '[DEPRECATION] `contain_match` is deprecated and will be removed in the next major version. See https://github.com/chef/inspec/issues/738 for more details'
|
|
82
81
|
arr.inject { |result, i|
|
|
83
82
|
result = i.match(regex)
|
|
84
83
|
result || i.match(/$/)
|
|
@@ -88,7 +87,6 @@ end
|
|
|
88
87
|
|
|
89
88
|
RSpec::Matchers.define :contain_duplicates do
|
|
90
89
|
match do |arr|
|
|
91
|
-
warn '[DEPRECATION] `contain_duplicates` is deprecated and will be removed for InSpec 1.0. See https://github.com/chef/inspec/issues/738 for more details'
|
|
92
90
|
dup = arr.select { |element| arr.count(element) > 1 }
|
|
93
91
|
!dup.uniq.empty?
|
|
94
92
|
end
|
|
@@ -105,7 +103,7 @@ RSpec::Matchers.define :be_installed do
|
|
|
105
103
|
end
|
|
106
104
|
|
|
107
105
|
chain :by do
|
|
108
|
-
|
|
106
|
+
raise "[UNSUPPORTED] Please use the new resources 'gem', 'npm' or 'pip'."
|
|
109
107
|
end
|
|
110
108
|
|
|
111
109
|
chain :with_version do |version|
|
|
@@ -121,7 +119,7 @@ RSpec::Matchers.define :be_enabled do
|
|
|
121
119
|
end
|
|
122
120
|
|
|
123
121
|
chain :with_level do |_level|
|
|
124
|
-
|
|
122
|
+
raise '[UNSUPPORTED] with level is not supported'
|
|
125
123
|
end
|
|
126
124
|
|
|
127
125
|
failure_message do |service|
|
|
@@ -137,7 +135,7 @@ RSpec::Matchers.define :be_running do
|
|
|
137
135
|
end
|
|
138
136
|
|
|
139
137
|
chain :under do |_under|
|
|
140
|
-
|
|
138
|
+
raise '[UNSUPPORTED] under is not supported'
|
|
141
139
|
end
|
|
142
140
|
|
|
143
141
|
failure_message do |service|
|
|
@@ -178,7 +176,7 @@ RSpec::Matchers.define :be_reachable do
|
|
|
178
176
|
end
|
|
179
177
|
|
|
180
178
|
chain :with do |_attr|
|
|
181
|
-
|
|
179
|
+
raise '[UNSUPPORTED] `with` is not supported in combination with `be_reachable`'
|
|
182
180
|
end
|
|
183
181
|
|
|
184
182
|
failure_message do |host|
|
|
@@ -193,7 +191,7 @@ RSpec::Matchers.define :be_resolvable do
|
|
|
193
191
|
end
|
|
194
192
|
|
|
195
193
|
chain :by do |_type|
|
|
196
|
-
|
|
194
|
+
raise "[UNSUPPORTED] `by` is not supported in combination with `be_resolvable`. Please use the following syntax `host('example.com', port: 53, proto: 'udp')`."
|
|
197
195
|
end
|
|
198
196
|
|
|
199
197
|
failure_message do |host|
|
|
@@ -208,18 +206,57 @@ RSpec::Matchers.define :have_rule do |rule|
|
|
|
208
206
|
end
|
|
209
207
|
|
|
210
208
|
chain :with_table do |_table|
|
|
211
|
-
|
|
209
|
+
raise "[UNSUPPORTED] `with_table` is not supported in combination with `have_rule`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
|
212
210
|
end
|
|
213
211
|
|
|
214
212
|
chain :with_chain do |_chain|
|
|
215
|
-
|
|
213
|
+
raise "[UNSUPPORTED] `with_table` is not supported in combination with `with_chain`. Please use the following syntax `iptables(table:'mangle', chain: 'input')`."
|
|
216
214
|
end
|
|
217
215
|
end
|
|
218
216
|
|
|
219
|
-
#
|
|
220
|
-
RSpec::Matchers.define :contain do |
|
|
221
|
-
match do |
|
|
222
|
-
|
|
217
|
+
# deprecated
|
|
218
|
+
RSpec::Matchers.define :contain do |rule|
|
|
219
|
+
match do |resource|
|
|
220
|
+
warn "[DEPRECATION] `contain` matcher. Please use the following syntax `its('content') { should include('value') }`."
|
|
221
|
+
expect(resource).to include(rule)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# `be_in` matcher
|
|
226
|
+
# You can use it in the following cases:
|
|
227
|
+
# - check if an item or array is included in a given array
|
|
228
|
+
# eg:
|
|
229
|
+
# describe nginx do
|
|
230
|
+
# its('user') { should be_in AUTHORIZED_USER_LIST }
|
|
231
|
+
# end
|
|
232
|
+
# describe nginx do
|
|
233
|
+
# its('module_list') { should be_in AUTHORIZED_MODULE_LIST }
|
|
234
|
+
# end
|
|
235
|
+
RSpec::Matchers.define :be_in do |list|
|
|
236
|
+
match do |item|
|
|
237
|
+
# Handle both single item and array
|
|
238
|
+
item.is_a?(Array) ? (item - list).empty? : list.include?(item)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
match_when_negated do |item|
|
|
242
|
+
# Handle both single item and array
|
|
243
|
+
item.is_a?(Array) ? (item & list).empty? : !list.include?(item)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
failure_message do |item|
|
|
247
|
+
if item.is_a?(Array)
|
|
248
|
+
"expected `#{item}` to be in the list: `#{list}` \nDiff:\n #{(item - list)}"
|
|
249
|
+
else
|
|
250
|
+
"expected `#{item}` to be in the list: `#{list}`"
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
failure_message_when_negated do |item|
|
|
255
|
+
if item.is_a?(Array)
|
|
256
|
+
"expected `#{item}` not to be in the list: `#{list}` \nComm:\n #{(item & list)}"
|
|
257
|
+
else
|
|
258
|
+
"expected `#{item}` not to be in the list: `#{list}`"
|
|
259
|
+
end
|
|
223
260
|
end
|
|
224
261
|
end
|
|
225
262
|
|
|
@@ -251,6 +288,13 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
|
251
288
|
%w{true false}.include?(value.downcase)
|
|
252
289
|
end
|
|
253
290
|
|
|
291
|
+
def version?(value)
|
|
292
|
+
Gem::Version.new(value)
|
|
293
|
+
true
|
|
294
|
+
rescue ArgumentError => _ex
|
|
295
|
+
false
|
|
296
|
+
end
|
|
297
|
+
|
|
254
298
|
# expects that the values have been checked with boolean?
|
|
255
299
|
def to_boolean(value)
|
|
256
300
|
value.casecmp('true') == 0
|
|
@@ -260,6 +304,8 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
|
260
304
|
# if actual and expected are strings
|
|
261
305
|
if expected.is_a?(String) && actual.is_a?(String)
|
|
262
306
|
return actual.casecmp(expected) == 0 if op == :==
|
|
307
|
+
return Gem::Version.new(actual).method(op).call(Gem::Version.new(expected)) if
|
|
308
|
+
version?(expected) && version?(actual)
|
|
263
309
|
elsif expected.is_a?(Regexp) && (actual.is_a?(String) || actual.is_a?(Integer))
|
|
264
310
|
return !actual.to_s.match(expected).nil?
|
|
265
311
|
elsif expected.is_a?(String) && integer?(expected) && actual.is_a?(Integer)
|
|
@@ -305,14 +351,18 @@ RSpec::Matchers.define :cmp do |first_expected|
|
|
|
305
351
|
end
|
|
306
352
|
|
|
307
353
|
failure_message do |actual|
|
|
308
|
-
actual = '0' + actual.to_s(8) if octal?(@expected)
|
|
354
|
+
actual = ('0' + actual.to_s(8)).inspect if octal?(@expected)
|
|
309
355
|
"\n" + format_expectation(false) + "\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
|
|
310
356
|
end
|
|
311
357
|
|
|
312
358
|
failure_message_when_negated do |actual|
|
|
313
|
-
actual = '0' + actual.to_s(8) if octal?(@expected)
|
|
359
|
+
actual = ('0' + actual.to_s(8)).inspect if octal?(@expected)
|
|
314
360
|
"\n" + format_expectation(true) + "\n got: #{actual}\n\n(compared using `cmp` matcher)\n"
|
|
315
361
|
end
|
|
362
|
+
|
|
363
|
+
description do
|
|
364
|
+
"cmp #{@operation} #{@expected.inspect}"
|
|
365
|
+
end
|
|
316
366
|
end
|
|
317
367
|
|
|
318
368
|
# user resource matcher for serverspec compatibility
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Jen Burns, burnsjennifere@gmail.com
|
|
3
|
+
|
|
4
|
+
require 'utils/filter'
|
|
5
|
+
require 'utils/parser'
|
|
6
|
+
|
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
|
8
|
+
module Inspec::Resources
|
|
9
|
+
class AideConf < Inspec.resource(1)
|
|
10
|
+
name 'aide_conf'
|
|
11
|
+
desc 'Use the aide_conf InSpec audit resource to test the rules established for
|
|
12
|
+
the file integrity tool AIDE. Controlled by the aide.conf file typically at /etc/aide.conf.'
|
|
13
|
+
example "
|
|
14
|
+
describe aide_conf do
|
|
15
|
+
its('selection_lines') { should include '/sbin' }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe aide_conf.where { selection_line == '/bin' } do
|
|
19
|
+
its('rules.flatten') { should include 'r' }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe aide_conf.all_have_rule('sha512') do
|
|
23
|
+
it { should eq true }
|
|
24
|
+
end
|
|
25
|
+
"
|
|
26
|
+
|
|
27
|
+
attr_reader :params
|
|
28
|
+
|
|
29
|
+
include CommentParser
|
|
30
|
+
|
|
31
|
+
def initialize(aide_conf_path = nil)
|
|
32
|
+
return skip_resource 'The `aide_conf` resource is not supported on your OS.' unless inspec.os.linux?
|
|
33
|
+
@conf_path = aide_conf_path || '/etc/aide.conf'
|
|
34
|
+
@content = nil
|
|
35
|
+
@rules = nil
|
|
36
|
+
read_content
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def all_have_rule(rule)
|
|
40
|
+
# Case when file didn't exist or perms didn't allow an open
|
|
41
|
+
return false if @content.nil?
|
|
42
|
+
|
|
43
|
+
lines = @params.reject { |line| line['rules'].include? rule }
|
|
44
|
+
lines.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
filter = FilterTable.create
|
|
48
|
+
filter.add_accessor(:where)
|
|
49
|
+
.add_accessor(:entries)
|
|
50
|
+
.add(:selection_lines, field: 'selection_line')
|
|
51
|
+
.add(:rules, field: 'rules')
|
|
52
|
+
|
|
53
|
+
filter.connect(self, :params)
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def read_content
|
|
58
|
+
return @content unless @content.nil?
|
|
59
|
+
@rules = {}
|
|
60
|
+
|
|
61
|
+
file = inspec.file(@conf_path)
|
|
62
|
+
if !file.file?
|
|
63
|
+
return skip_resource "Can't find file \"#{@conf_path}\""
|
|
64
|
+
end
|
|
65
|
+
raw_conf = file.content
|
|
66
|
+
if raw_conf.nil?
|
|
67
|
+
return skip_resource "File can't be opened or is empty \"#{@conf_path}\""
|
|
68
|
+
end
|
|
69
|
+
if raw_conf.empty? && !file.empty?
|
|
70
|
+
return skip_resource "Can't read file \"#{@conf_path}\""
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# If there is a file and it contains content, continue
|
|
74
|
+
@content = filter_comments(inspec.file(@conf_path).content.lines)
|
|
75
|
+
@params = parse_conf(@content)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def filter_comments(data)
|
|
79
|
+
content = []
|
|
80
|
+
data.each do |line|
|
|
81
|
+
content_line, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
|
|
82
|
+
content.push(content_line)
|
|
83
|
+
end
|
|
84
|
+
content
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def parse_conf(content)
|
|
88
|
+
params = []
|
|
89
|
+
content.each do |line|
|
|
90
|
+
param = parse_line(line)
|
|
91
|
+
if !param['selection_line'].nil?
|
|
92
|
+
params.push(param)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
params
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def parse_line(line)
|
|
99
|
+
line_and_rules = {}
|
|
100
|
+
# Case when line is a rule line
|
|
101
|
+
if line.include?(' = ')
|
|
102
|
+
parse_rule_line(line)
|
|
103
|
+
# Case when line is a selection line
|
|
104
|
+
elsif line.start_with?('/', '!', '=')
|
|
105
|
+
line_and_rules = parse_selection_line(line)
|
|
106
|
+
end
|
|
107
|
+
line_and_rules
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def parse_rule_line(line)
|
|
111
|
+
line.gsub!(/\s+/, '')
|
|
112
|
+
rule_line_arr = line.split('=')
|
|
113
|
+
rules_list = rule_line_arr.last.split('+')
|
|
114
|
+
rule_name = rule_line_arr.first
|
|
115
|
+
rules_list.each_index do |i|
|
|
116
|
+
# Cases where rule respresents one or more other rules
|
|
117
|
+
if @rules.key?(rules_list[i])
|
|
118
|
+
rules_list[i] = @rules[rules_list[i]]
|
|
119
|
+
end
|
|
120
|
+
rules_list[i] = handle_multi_rule(rules_list, i)
|
|
121
|
+
end
|
|
122
|
+
@rules[rule_name] = rules_list.flatten
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def parse_selection_line(line)
|
|
126
|
+
selec_line_arr = line.split(' ')
|
|
127
|
+
selection_line = selec_line_arr.first
|
|
128
|
+
selection_line.chop! if selection_line.end_with?('/')
|
|
129
|
+
rule_list = selec_line_arr.last.split('+')
|
|
130
|
+
rule_list.each_index do |i|
|
|
131
|
+
hash_list = @rules[rule_list[i]]
|
|
132
|
+
# Cases where rule respresents one or more other rules
|
|
133
|
+
if !hash_list.nil?
|
|
134
|
+
rule_list[i] = hash_list
|
|
135
|
+
end
|
|
136
|
+
rule_list[i] = handle_multi_rule(rule_list, i)
|
|
137
|
+
end
|
|
138
|
+
rule_list.flatten!
|
|
139
|
+
{
|
|
140
|
+
'selection_line' => selection_line,
|
|
141
|
+
'rules' => rule_list,
|
|
142
|
+
}
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def handle_multi_rule(rule_list, i)
|
|
146
|
+
# Rules that represent multiple rules (R,L,>)
|
|
147
|
+
r_rules = %w{p i l n u g s m c md5}
|
|
148
|
+
l_rules = %w{p i l n u g}
|
|
149
|
+
grow_log_rules = %w{p l u g i n S}
|
|
150
|
+
|
|
151
|
+
case rule_list[i]
|
|
152
|
+
when 'R'
|
|
153
|
+
return r_rules
|
|
154
|
+
when 'L'
|
|
155
|
+
return l_rules
|
|
156
|
+
when '>'
|
|
157
|
+
return grow_log_rules
|
|
158
|
+
end
|
|
159
|
+
rule_list[i]
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
data/lib/resources/apache.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
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 'utils/simpleconfig'
|
|
8
7
|
require 'utils/find_files'
|
|
@@ -70,7 +69,7 @@ module Inspec::Resources
|
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
raw_conf = file.content
|
|
73
|
-
if raw_conf.empty? && file.
|
|
72
|
+
if raw_conf.empty? && !file.empty?
|
|
74
73
|
return skip_resource("Can't read file \"#{@conf_path}\"")
|
|
75
74
|
end
|
|
76
75
|
|
|
@@ -82,7 +81,7 @@ module Inspec::Resources
|
|
|
82
81
|
# parse include file parameters
|
|
83
82
|
params = SimpleConfig.new(
|
|
84
83
|
raw_conf,
|
|
85
|
-
|
|
84
|
+
assignment_regex: /^\s*(\S+)\s+(.*)\s*$/,
|
|
86
85
|
multiple_values: true,
|
|
87
86
|
).params
|
|
88
87
|
@params.merge!(params)
|
|
@@ -107,6 +106,7 @@ module Inspec::Resources
|
|
|
107
106
|
(include_files + include_files_optional).each do |f|
|
|
108
107
|
id = Pathname.new(f).absolute? ? f : File.join(@conf_dir, f)
|
|
109
108
|
files = find_files(id, depth: 1, type: 'file')
|
|
109
|
+
files += find_files(id, depth: 1, type: 'link')
|
|
110
110
|
|
|
111
111
|
includes.push(files) if files
|
|
112
112
|
end
|
data/lib/resources/apt.rb
CHANGED
|
@@ -89,7 +89,8 @@ module Inspec::Resources
|
|
|
89
89
|
active = false if raw_line != line
|
|
90
90
|
|
|
91
91
|
# eg.: deb http://archive.ubuntu.com/ubuntu/ wily main restricted
|
|
92
|
-
|
|
92
|
+
# or : deb [trusted=yes] http://archive.ubuntu.com/ubuntu/ wily main restricted
|
|
93
|
+
parse_repo = /^\s*(\S+)\s+(?:\[\S+\])?\s*"?([^ "\t\r\n\f]+)"?\s+(\S+)\s+(.*)$/.match(line)
|
|
93
94
|
|
|
94
95
|
# check if we got any result and the second param is an url
|
|
95
96
|
next if parse_repo.nil? || !parse_repo[2] =~ HTTP_URL_RE
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
# copyright: 2015, Vulcano Security GmbH
|
|
3
3
|
# author: Christoph Hartmann
|
|
4
4
|
# author: Dominik Richter
|
|
5
|
-
# license: All rights reserved
|
|
6
5
|
|
|
7
6
|
# Advanced Auditing:
|
|
8
7
|
# As soon as you start applying Advanced Audit Configuration Policy, legacy policies will be completely ignored.
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
# copyright: 2015, Vulcano Security GmbH
|
|
3
3
|
# author: Christoph Hartmann
|
|
4
4
|
# author: Dominik Richter
|
|
5
|
-
# license: All rights reserved
|
|
6
5
|
|
|
7
6
|
require 'utils/simpleconfig'
|
|
8
7
|
|
|
@@ -41,7 +40,7 @@ module Inspec::Resources
|
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
content = file.content
|
|
44
|
-
if content.empty? && file.
|
|
43
|
+
if content.empty? && !file.empty?
|
|
45
44
|
skip_resource "Can't read file '#{@conf_path}'"
|
|
46
45
|
return @params = {}
|
|
47
46
|
end
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
# copyright: 2015, Vulcano Security GmbH
|
|
3
3
|
# author: Christoph Hartmann
|
|
4
4
|
# author: Dominik Richter
|
|
5
|
-
# license: All rights reserved
|
|
6
5
|
|
|
7
6
|
require 'forwardable'
|
|
8
7
|
require 'utils/filter_array'
|
|
@@ -12,7 +11,7 @@ module Inspec::Resources
|
|
|
12
11
|
def initialize(content)
|
|
13
12
|
@content = content
|
|
14
13
|
@opts = {
|
|
15
|
-
|
|
14
|
+
assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
16
15
|
multiple_values: true,
|
|
17
16
|
}
|
|
18
17
|
end
|
|
@@ -27,7 +26,7 @@ module Inspec::Resources
|
|
|
27
26
|
|
|
28
27
|
def status(name)
|
|
29
28
|
@status_opts = {
|
|
30
|
-
|
|
29
|
+
assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
31
30
|
multiple_values: false,
|
|
32
31
|
}
|
|
33
32
|
@status_content ||= inspec.command('/sbin/auditctl -s').stdout.chomp
|
|
@@ -86,6 +85,7 @@ module Inspec::Resources
|
|
|
86
85
|
@legacy = AuditdRulesLegacy.new(@content)
|
|
87
86
|
else
|
|
88
87
|
parse_content
|
|
88
|
+
@legacy = nil
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
@@ -93,7 +93,7 @@ module Inspec::Resources
|
|
|
93
93
|
# rubocop:disable Style/MethodName
|
|
94
94
|
def LIST_RULES
|
|
95
95
|
return @legacy.LIST_RULES if @legacy
|
|
96
|
-
|
|
96
|
+
raise 'Using legacy auditd_rules LIST_RULES interface with non-legacy audit package. Please use the new syntax.'
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
def status(name = nil)
|
|
@@ -177,7 +177,7 @@ module Inspec::Resources
|
|
|
177
177
|
|
|
178
178
|
# NB only in file lines
|
|
179
179
|
def get_key(line)
|
|
180
|
-
line.match(/-k ([^ ]+)/)[1]
|
|
180
|
+
line.match(/-k ([^ ]+)/)[1] if line.include?('-k ')
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
# NOTE there are NO precautions wrt. filenames containing spaces in auditctl
|
data/lib/resources/bond.rb
CHANGED
|
@@ -28,7 +28,7 @@ module Inspec::Resources
|
|
|
28
28
|
@content = @file.content
|
|
29
29
|
@params = SimpleConfig.new(
|
|
30
30
|
@file.content,
|
|
31
|
-
|
|
31
|
+
assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
|
|
32
32
|
multiple_values: true,
|
|
33
33
|
).params if @file.exist?
|
|
34
34
|
@loaded = true
|
data/lib/resources/bridge.rb
CHANGED
|
@@ -115,7 +115,7 @@ module Inspec::Resources
|
|
|
115
115
|
adapter_collection.push(info) if info[:name].casecmp(bridge_name) == 0
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
return nil if bridges.
|
|
118
|
+
return nil if bridges.empty?
|
|
119
119
|
warn "[Possible Error] detected multiple bridges interfaces with the name #{bridge_name}" if bridges.size > 1
|
|
120
120
|
bridges[0]
|
|
121
121
|
end
|
data/lib/resources/command.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
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
|
module Inspec::Resources
|
|
8
7
|
class Cmd < Inspec.resource(1)
|
|
@@ -24,6 +23,9 @@ module Inspec::Resources
|
|
|
24
23
|
attr_reader :command
|
|
25
24
|
|
|
26
25
|
def initialize(cmd)
|
|
26
|
+
if cmd.nil?
|
|
27
|
+
raise 'InSpec `command` was called with `nil` as the argument. This is not supported. Please provide a valid command instead.'
|
|
28
|
+
end
|
|
27
29
|
@command = cmd
|
|
28
30
|
end
|
|
29
31
|
|
|
@@ -45,12 +47,12 @@ module Inspec::Resources
|
|
|
45
47
|
|
|
46
48
|
def exist?
|
|
47
49
|
# silent for mock resources
|
|
48
|
-
return false if inspec.os
|
|
50
|
+
return false if inspec.os.name.nil?
|
|
49
51
|
|
|
50
52
|
if inspec.os.linux?
|
|
51
53
|
res = inspec.backend.run_command("bash -c 'type \"#{@command}\"'")
|
|
52
54
|
elsif inspec.os.windows?
|
|
53
|
-
res = inspec.backend.run_command("
|
|
55
|
+
res = inspec.backend.run_command("Get-Command \"#{@command}\"")
|
|
54
56
|
elsif inspec.os.unix?
|
|
55
57
|
res = inspec.backend.run_command("type \"#{@command}\"")
|
|
56
58
|
else
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Adam Leff
|
|
3
|
+
|
|
4
|
+
require 'utils/parser'
|
|
5
|
+
require 'utils/filter'
|
|
6
|
+
|
|
7
|
+
module Inspec::Resources
|
|
8
|
+
class Crontab < Inspec.resource(1)
|
|
9
|
+
name 'crontab'
|
|
10
|
+
desc 'Use the crontab InSpec audit resource to test the contents of the crontab for a given user which contains information about scheduled tasks owned by that user.'
|
|
11
|
+
example "
|
|
12
|
+
describe crontab('root') do
|
|
13
|
+
its('commands') { should include '/path/to/some/script' }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe crontab('myuser').commands('/home/myuser/build.sh') do
|
|
17
|
+
its('hours') { should cmp '*' }
|
|
18
|
+
its('minutes') { should cmp '*' }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe crontab.where({'hour' => '*', 'minute' => '*'}) do
|
|
22
|
+
its('entries.length') { should cmp '0' }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe crontab.where { command =~ /a partial command string/ } do
|
|
26
|
+
its('entries.length') { should cmp 1 }
|
|
27
|
+
end
|
|
28
|
+
"
|
|
29
|
+
|
|
30
|
+
attr_reader :params
|
|
31
|
+
|
|
32
|
+
include CommentParser
|
|
33
|
+
|
|
34
|
+
def initialize(user = nil)
|
|
35
|
+
@user = user
|
|
36
|
+
@params = read_crontab
|
|
37
|
+
|
|
38
|
+
return skip_resource 'The `crontab` resource is not supported on your OS.' unless inspec.os.unix?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def read_crontab
|
|
42
|
+
inspec.command(crontab_cmd).stdout.lines.map { |l| parse_crontab_line(l) }.compact
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def parse_crontab_line(l)
|
|
46
|
+
data, = parse_comment_line(l, comment_char: '#', standalone_comments: false)
|
|
47
|
+
return nil if data.nil? || data.empty?
|
|
48
|
+
|
|
49
|
+
case data
|
|
50
|
+
when /@hourly .*/
|
|
51
|
+
{ 'minute' => '0', 'hour' => '*', 'day' => '*', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
52
|
+
when /@(midnight|daily) .*/
|
|
53
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
54
|
+
when /@weekly .*/
|
|
55
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '*', 'month' => '*', 'weekday' => '0', 'command' => data.split(/\s+/, 2).at(1) }
|
|
56
|
+
when /@monthly ./
|
|
57
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '*', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
58
|
+
when /@(annually|yearly) .*/
|
|
59
|
+
{ 'minute' => '0', 'hour' => '0', 'day' => '1', 'month' => '1', 'weekday' => '*', 'command' => data.split(/\s+/, 2).at(1) }
|
|
60
|
+
when /@reboot .*/
|
|
61
|
+
{ 'minute' => '-1', 'hour' => '-1', 'day' => '-1', 'month' => '-1', 'weekday' => '-1', 'command' => data.split(/\s+/, 2).at(1) }
|
|
62
|
+
else
|
|
63
|
+
elements = data.split(/\s+/, 6)
|
|
64
|
+
{
|
|
65
|
+
'minute' => elements.at(0),
|
|
66
|
+
'hour' => elements.at(1),
|
|
67
|
+
'day' => elements.at(2),
|
|
68
|
+
'month' => elements.at(3),
|
|
69
|
+
'weekday' => elements.at(4),
|
|
70
|
+
'command' => elements.at(5),
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def crontab_cmd
|
|
76
|
+
@user.nil? ? 'crontab -l' : "crontab -l -u #{@user}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
filter = FilterTable.create
|
|
80
|
+
filter.add_accessor(:where)
|
|
81
|
+
.add_accessor(:entries)
|
|
82
|
+
.add(:minutes, field: 'minute')
|
|
83
|
+
.add(:hours, field: 'hour')
|
|
84
|
+
.add(:days, field: 'day')
|
|
85
|
+
.add(:months, field: 'month')
|
|
86
|
+
.add(:weekdays, field: 'weekday')
|
|
87
|
+
.add(:commands, field: 'command')
|
|
88
|
+
|
|
89
|
+
# rebuild the crontab line from raw content
|
|
90
|
+
filter.add(:content) { |t, _|
|
|
91
|
+
t.entries.map do |e|
|
|
92
|
+
[e.minute, e.hour, e.day, e.month, e.weekday, e.command].join(' ')
|
|
93
|
+
end.join("\n")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
filter.connect(self, :params)
|
|
97
|
+
|
|
98
|
+
def to_s
|
|
99
|
+
@user.nil? ? 'crontab for current user' : "crontab for user #{@user}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/resources/csv.rb
CHANGED
|
@@ -15,19 +15,36 @@ module Inspec::Resources
|
|
|
15
15
|
end
|
|
16
16
|
"
|
|
17
17
|
|
|
18
|
-
# override
|
|
18
|
+
# override the parse method from JsonConfig
|
|
19
|
+
# Assuming a header row of name,col1,col2, it will output an array of hashes like so:
|
|
20
|
+
# [
|
|
21
|
+
# { 'name' => 'row1', 'col1' => 'value1', 'col2' => 'value2' },
|
|
22
|
+
# { 'name' => 'row2', 'col1' => 'value3', 'col2' => 'value4' }
|
|
23
|
+
# ]
|
|
19
24
|
def parse(content)
|
|
20
25
|
require 'csv'
|
|
26
|
+
|
|
21
27
|
# convert empty field to nil
|
|
22
28
|
CSV::Converters[:blank_to_nil] = lambda do |field|
|
|
23
29
|
field && field.empty? ? nil : field
|
|
24
30
|
end
|
|
31
|
+
|
|
25
32
|
# implicit conversion of values
|
|
26
33
|
csv = CSV.new(content, headers: true, converters: [:all, :blank_to_nil])
|
|
34
|
+
|
|
27
35
|
# convert to hash
|
|
28
36
|
csv.to_a.map(&:to_hash)
|
|
29
37
|
end
|
|
30
38
|
|
|
39
|
+
# override the value method from JsonConfig
|
|
40
|
+
# The format of the CSV hash as created by #parse is very different
|
|
41
|
+
# than what the YAML, JSON, and INI resources create, so using the
|
|
42
|
+
# #value method from JsonConfig (which uses ObjectTraverser.extract_value)
|
|
43
|
+
# doesn't make sense here.
|
|
44
|
+
def value(key)
|
|
45
|
+
@params.map { |x| x[key.first.to_s] }.compact
|
|
46
|
+
end
|
|
47
|
+
|
|
31
48
|
def to_s
|
|
32
49
|
"Csv #{@path}"
|
|
33
50
|
end
|