inspec-core 2.1.67
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/CHANGELOG.md +3136 -0
- data/Gemfile +56 -0
- data/LICENSE +14 -0
- data/MAINTAINERS.md +33 -0
- data/MAINTAINERS.toml +52 -0
- data/README.md +453 -0
- data/bin/inspec +12 -0
- data/docs/.gitignore +2 -0
- data/docs/README.md +40 -0
- data/docs/dev/control-eval.md +62 -0
- data/docs/dsl_inspec.md +258 -0
- data/docs/dsl_resource.md +100 -0
- data/docs/glossary.md +99 -0
- data/docs/habitat.md +192 -0
- data/docs/inspec_and_friends.md +114 -0
- data/docs/matchers.md +169 -0
- data/docs/migration.md +293 -0
- data/docs/platforms.md +119 -0
- data/docs/plugin_kitchen_inspec.md +50 -0
- data/docs/profiles.md +378 -0
- data/docs/reporters.md +105 -0
- data/docs/resources/aide_conf.md.erb +76 -0
- data/docs/resources/apache.md.erb +67 -0
- data/docs/resources/apache_conf.md.erb +68 -0
- data/docs/resources/apt.md.erb +71 -0
- data/docs/resources/audit_policy.md.erb +47 -0
- data/docs/resources/auditd.md.erb +79 -0
- data/docs/resources/auditd_conf.md.erb +68 -0
- data/docs/resources/bash.md.erb +75 -0
- data/docs/resources/bond.md.erb +90 -0
- data/docs/resources/bridge.md.erb +57 -0
- data/docs/resources/bsd_service.md.erb +67 -0
- data/docs/resources/chocolatey_package.md.erb +58 -0
- data/docs/resources/command.md.erb +138 -0
- data/docs/resources/cpan.md.erb +79 -0
- data/docs/resources/cran.md.erb +64 -0
- data/docs/resources/crontab.md.erb +89 -0
- data/docs/resources/csv.md.erb +54 -0
- data/docs/resources/dh_params.md.erb +205 -0
- data/docs/resources/directory.md.erb +30 -0
- data/docs/resources/docker.md.erb +219 -0
- data/docs/resources/docker_container.md.erb +103 -0
- data/docs/resources/docker_image.md.erb +94 -0
- data/docs/resources/docker_service.md.erb +114 -0
- data/docs/resources/elasticsearch.md.erb +242 -0
- data/docs/resources/etc_fstab.md.erb +125 -0
- data/docs/resources/etc_group.md.erb +75 -0
- data/docs/resources/etc_hosts.md.erb +78 -0
- data/docs/resources/etc_hosts_allow.md.erb +74 -0
- data/docs/resources/etc_hosts_deny.md.erb +74 -0
- data/docs/resources/file.md.erb +526 -0
- data/docs/resources/filesystem.md.erb +41 -0
- data/docs/resources/firewalld.md.erb +107 -0
- data/docs/resources/gem.md.erb +79 -0
- data/docs/resources/group.md.erb +61 -0
- data/docs/resources/grub_conf.md.erb +101 -0
- data/docs/resources/host.md.erb +86 -0
- data/docs/resources/http.md.erb +197 -0
- data/docs/resources/iis_app.md.erb +122 -0
- data/docs/resources/iis_site.md.erb +135 -0
- data/docs/resources/inetd_conf.md.erb +94 -0
- data/docs/resources/ini.md.erb +76 -0
- data/docs/resources/interface.md.erb +58 -0
- data/docs/resources/iptables.md.erb +64 -0
- data/docs/resources/json.md.erb +63 -0
- data/docs/resources/kernel_module.md.erb +120 -0
- data/docs/resources/kernel_parameter.md.erb +53 -0
- data/docs/resources/key_rsa.md.erb +85 -0
- data/docs/resources/launchd_service.md.erb +57 -0
- data/docs/resources/limits_conf.md.erb +75 -0
- data/docs/resources/login_defs.md.erb +71 -0
- data/docs/resources/mount.md.erb +69 -0
- data/docs/resources/mssql_session.md.erb +60 -0
- data/docs/resources/mysql_conf.md.erb +99 -0
- data/docs/resources/mysql_session.md.erb +74 -0
- data/docs/resources/nginx.md.erb +79 -0
- data/docs/resources/nginx_conf.md.erb +138 -0
- data/docs/resources/npm.md.erb +60 -0
- data/docs/resources/ntp_conf.md.erb +60 -0
- data/docs/resources/oneget.md.erb +53 -0
- data/docs/resources/oracledb_session.md.erb +52 -0
- data/docs/resources/os.md.erb +141 -0
- data/docs/resources/os_env.md.erb +91 -0
- data/docs/resources/package.md.erb +120 -0
- data/docs/resources/packages.md.erb +67 -0
- data/docs/resources/parse_config.md.erb +103 -0
- data/docs/resources/parse_config_file.md.erb +138 -0
- data/docs/resources/passwd.md.erb +141 -0
- data/docs/resources/pip.md.erb +67 -0
- data/docs/resources/port.md.erb +137 -0
- data/docs/resources/postgres_conf.md.erb +79 -0
- data/docs/resources/postgres_hba_conf.md.erb +93 -0
- data/docs/resources/postgres_ident_conf.md.erb +76 -0
- data/docs/resources/postgres_session.md.erb +69 -0
- data/docs/resources/powershell.md.erb +102 -0
- data/docs/resources/processes.md.erb +109 -0
- data/docs/resources/rabbitmq_config.md.erb +41 -0
- data/docs/resources/registry_key.md.erb +158 -0
- data/docs/resources/runit_service.md.erb +57 -0
- data/docs/resources/security_policy.md.erb +47 -0
- data/docs/resources/service.md.erb +121 -0
- data/docs/resources/shadow.md.erb +146 -0
- data/docs/resources/ssh_config.md.erb +73 -0
- data/docs/resources/sshd_config.md.erb +83 -0
- data/docs/resources/ssl.md.erb +119 -0
- data/docs/resources/sys_info.md.erb +42 -0
- data/docs/resources/systemd_service.md.erb +57 -0
- data/docs/resources/sysv_service.md.erb +57 -0
- data/docs/resources/upstart_service.md.erb +57 -0
- data/docs/resources/user.md.erb +140 -0
- data/docs/resources/users.md.erb +127 -0
- data/docs/resources/vbscript.md.erb +55 -0
- data/docs/resources/virtualization.md.erb +57 -0
- data/docs/resources/windows_feature.md.erb +47 -0
- data/docs/resources/windows_hotfix.md.erb +53 -0
- data/docs/resources/windows_task.md.erb +95 -0
- data/docs/resources/wmi.md.erb +81 -0
- data/docs/resources/x509_certificate.md.erb +151 -0
- data/docs/resources/xinetd_conf.md.erb +156 -0
- data/docs/resources/xml.md.erb +85 -0
- data/docs/resources/yaml.md.erb +69 -0
- data/docs/resources/yum.md.erb +98 -0
- data/docs/resources/zfs_dataset.md.erb +53 -0
- data/docs/resources/zfs_pool.md.erb +47 -0
- data/docs/ruby_usage.md +203 -0
- data/docs/shared/matcher_be.md.erb +1 -0
- data/docs/shared/matcher_cmp.md.erb +43 -0
- data/docs/shared/matcher_eq.md.erb +3 -0
- data/docs/shared/matcher_include.md.erb +1 -0
- data/docs/shared/matcher_match.md.erb +1 -0
- data/docs/shell.md +217 -0
- data/examples/README.md +8 -0
- data/examples/inheritance/README.md +65 -0
- data/examples/inheritance/controls/example.rb +14 -0
- data/examples/inheritance/inspec.yml +15 -0
- data/examples/kitchen-ansible/.kitchen.yml +25 -0
- data/examples/kitchen-ansible/Gemfile +19 -0
- data/examples/kitchen-ansible/README.md +53 -0
- data/examples/kitchen-ansible/files/nginx.repo +6 -0
- data/examples/kitchen-ansible/tasks/main.yml +16 -0
- data/examples/kitchen-ansible/test/integration/default/default.yml +5 -0
- data/examples/kitchen-ansible/test/integration/default/web_spec.rb +28 -0
- data/examples/kitchen-chef/.kitchen.yml +20 -0
- data/examples/kitchen-chef/Berksfile +3 -0
- data/examples/kitchen-chef/Gemfile +19 -0
- data/examples/kitchen-chef/README.md +27 -0
- data/examples/kitchen-chef/metadata.rb +7 -0
- data/examples/kitchen-chef/recipes/default.rb +6 -0
- data/examples/kitchen-chef/recipes/nginx.rb +30 -0
- data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -0
- data/examples/kitchen-puppet/.kitchen.yml +23 -0
- data/examples/kitchen-puppet/Gemfile +20 -0
- data/examples/kitchen-puppet/Puppetfile +25 -0
- data/examples/kitchen-puppet/README.md +53 -0
- data/examples/kitchen-puppet/manifests/site.pp +33 -0
- data/examples/kitchen-puppet/metadata.json +11 -0
- data/examples/kitchen-puppet/modules/.gitkeep +0 -0
- data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -0
- data/examples/meta-profile/README.md +37 -0
- data/examples/meta-profile/controls/example.rb +13 -0
- data/examples/meta-profile/inspec.yml +13 -0
- data/examples/profile-attribute.yml +2 -0
- data/examples/profile-attribute/README.md +14 -0
- data/examples/profile-attribute/controls/example.rb +11 -0
- data/examples/profile-attribute/inspec.yml +8 -0
- 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/examples/profile/README.md +48 -0
- data/examples/profile/controls/example.rb +23 -0
- data/examples/profile/controls/gordon.rb +36 -0
- data/examples/profile/controls/meta.rb +34 -0
- data/examples/profile/inspec.yml +10 -0
- data/examples/profile/libraries/gordon_config.rb +59 -0
- data/inspec-core.gemspec +43 -0
- data/lib/bundles/README.md +3 -0
- data/lib/bundles/inspec-artifact.rb +7 -0
- data/lib/bundles/inspec-artifact/README.md +1 -0
- data/lib/bundles/inspec-artifact/cli.rb +277 -0
- data/lib/bundles/inspec-compliance.rb +16 -0
- data/lib/bundles/inspec-compliance/.kitchen.yml +20 -0
- data/lib/bundles/inspec-compliance/README.md +193 -0
- data/lib/bundles/inspec-compliance/api.rb +360 -0
- data/lib/bundles/inspec-compliance/api/login.rb +193 -0
- data/lib/bundles/inspec-compliance/bootstrap.sh +41 -0
- data/lib/bundles/inspec-compliance/cli.rb +260 -0
- data/lib/bundles/inspec-compliance/configuration.rb +103 -0
- data/lib/bundles/inspec-compliance/http.rb +125 -0
- data/lib/bundles/inspec-compliance/images/cc-token.png +0 -0
- data/lib/bundles/inspec-compliance/support.rb +36 -0
- data/lib/bundles/inspec-compliance/target.rb +106 -0
- data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +93 -0
- data/lib/bundles/inspec-habitat.rb +12 -0
- data/lib/bundles/inspec-habitat/cli.rb +36 -0
- data/lib/bundles/inspec-habitat/log.rb +10 -0
- data/lib/bundles/inspec-habitat/profile.rb +391 -0
- data/lib/bundles/inspec-init.rb +8 -0
- data/lib/bundles/inspec-init/README.md +31 -0
- data/lib/bundles/inspec-init/cli.rb +97 -0
- data/lib/bundles/inspec-init/templates/profile/README.md +3 -0
- data/lib/bundles/inspec-init/templates/profile/controls/example.rb +19 -0
- data/lib/bundles/inspec-init/templates/profile/inspec.yml +8 -0
- data/lib/bundles/inspec-init/templates/profile/libraries/.gitkeep +0 -0
- data/lib/bundles/inspec-supermarket.rb +13 -0
- data/lib/bundles/inspec-supermarket/README.md +45 -0
- data/lib/bundles/inspec-supermarket/api.rb +84 -0
- data/lib/bundles/inspec-supermarket/cli.rb +73 -0
- data/lib/bundles/inspec-supermarket/target.rb +34 -0
- data/lib/fetchers/git.rb +163 -0
- data/lib/fetchers/local.rb +74 -0
- data/lib/fetchers/mock.rb +35 -0
- data/lib/fetchers/url.rb +247 -0
- data/lib/inspec.rb +24 -0
- data/lib/inspec/archive/tar.rb +29 -0
- data/lib/inspec/archive/zip.rb +19 -0
- data/lib/inspec/backend.rb +93 -0
- data/lib/inspec/base_cli.rb +368 -0
- data/lib/inspec/cached_fetcher.rb +66 -0
- data/lib/inspec/cli.rb +292 -0
- data/lib/inspec/completions/bash.sh.erb +45 -0
- data/lib/inspec/completions/fish.sh.erb +34 -0
- data/lib/inspec/completions/zsh.sh.erb +61 -0
- data/lib/inspec/control_eval_context.rb +179 -0
- data/lib/inspec/dependencies/cache.rb +72 -0
- data/lib/inspec/dependencies/dependency_set.rb +92 -0
- data/lib/inspec/dependencies/lockfile.rb +115 -0
- data/lib/inspec/dependencies/requirement.rb +123 -0
- data/lib/inspec/dependencies/resolver.rb +86 -0
- data/lib/inspec/describe.rb +27 -0
- data/lib/inspec/dsl.rb +66 -0
- data/lib/inspec/dsl_shared.rb +33 -0
- data/lib/inspec/env_printer.rb +157 -0
- data/lib/inspec/errors.rb +14 -0
- data/lib/inspec/exceptions.rb +12 -0
- data/lib/inspec/expect.rb +45 -0
- data/lib/inspec/fetcher.rb +45 -0
- data/lib/inspec/file_provider.rb +275 -0
- data/lib/inspec/formatters.rb +3 -0
- data/lib/inspec/formatters/base.rb +259 -0
- data/lib/inspec/formatters/json_rspec.rb +20 -0
- data/lib/inspec/formatters/show_progress.rb +12 -0
- data/lib/inspec/library_eval_context.rb +58 -0
- data/lib/inspec/log.rb +11 -0
- data/lib/inspec/metadata.rb +247 -0
- data/lib/inspec/method_source.rb +24 -0
- data/lib/inspec/objects.rb +14 -0
- data/lib/inspec/objects/attribute.rb +75 -0
- data/lib/inspec/objects/control.rb +61 -0
- data/lib/inspec/objects/describe.rb +92 -0
- data/lib/inspec/objects/each_loop.rb +36 -0
- data/lib/inspec/objects/list.rb +15 -0
- data/lib/inspec/objects/or_test.rb +40 -0
- data/lib/inspec/objects/ruby_helper.rb +15 -0
- data/lib/inspec/objects/tag.rb +27 -0
- data/lib/inspec/objects/test.rb +87 -0
- data/lib/inspec/objects/value.rb +27 -0
- data/lib/inspec/plugins.rb +60 -0
- data/lib/inspec/plugins/cli.rb +24 -0
- data/lib/inspec/plugins/fetcher.rb +86 -0
- data/lib/inspec/plugins/resource.rb +135 -0
- data/lib/inspec/plugins/secret.rb +15 -0
- data/lib/inspec/plugins/source_reader.rb +40 -0
- data/lib/inspec/polyfill.rb +12 -0
- data/lib/inspec/profile.rb +513 -0
- data/lib/inspec/profile_context.rb +208 -0
- data/lib/inspec/profile_vendor.rb +66 -0
- data/lib/inspec/reporters.rb +60 -0
- data/lib/inspec/reporters/automate.rb +76 -0
- data/lib/inspec/reporters/base.rb +25 -0
- data/lib/inspec/reporters/cli.rb +356 -0
- data/lib/inspec/reporters/json.rb +116 -0
- data/lib/inspec/reporters/json_min.rb +48 -0
- data/lib/inspec/reporters/junit.rb +78 -0
- data/lib/inspec/require_loader.rb +33 -0
- data/lib/inspec/resource.rb +190 -0
- data/lib/inspec/rule.rb +280 -0
- data/lib/inspec/runner.rb +345 -0
- data/lib/inspec/runner_mock.rb +41 -0
- data/lib/inspec/runner_rspec.rb +175 -0
- data/lib/inspec/runtime_profile.rb +26 -0
- data/lib/inspec/schema.rb +213 -0
- data/lib/inspec/secrets.rb +19 -0
- data/lib/inspec/secrets/yaml.rb +30 -0
- data/lib/inspec/shell.rb +220 -0
- data/lib/inspec/shell_detector.rb +90 -0
- data/lib/inspec/source_reader.rb +29 -0
- data/lib/inspec/version.rb +8 -0
- data/lib/matchers/matchers.rb +339 -0
- data/lib/resources/aide_conf.rb +151 -0
- data/lib/resources/apache.rb +48 -0
- data/lib/resources/apache_conf.rb +149 -0
- data/lib/resources/apt.rb +149 -0
- data/lib/resources/audit_policy.rb +63 -0
- data/lib/resources/auditd.rb +231 -0
- data/lib/resources/auditd_conf.rb +46 -0
- data/lib/resources/bash.rb +35 -0
- data/lib/resources/bond.rb +69 -0
- data/lib/resources/bridge.rb +122 -0
- data/lib/resources/chocolatey_package.rb +78 -0
- data/lib/resources/command.rb +73 -0
- data/lib/resources/cpan.rb +58 -0
- data/lib/resources/cran.rb +64 -0
- data/lib/resources/crontab.rb +169 -0
- data/lib/resources/csv.rb +56 -0
- data/lib/resources/dh_params.rb +77 -0
- data/lib/resources/directory.rb +25 -0
- data/lib/resources/docker.rb +236 -0
- data/lib/resources/docker_container.rb +89 -0
- data/lib/resources/docker_image.rb +83 -0
- data/lib/resources/docker_object.rb +57 -0
- data/lib/resources/docker_service.rb +90 -0
- data/lib/resources/elasticsearch.rb +169 -0
- data/lib/resources/etc_fstab.rb +94 -0
- data/lib/resources/etc_group.rb +154 -0
- data/lib/resources/etc_hosts.rb +66 -0
- data/lib/resources/etc_hosts_allow_deny.rb +112 -0
- data/lib/resources/file.rb +298 -0
- data/lib/resources/filesystem.rb +31 -0
- data/lib/resources/firewalld.rb +143 -0
- data/lib/resources/gem.rb +70 -0
- data/lib/resources/groups.rb +215 -0
- data/lib/resources/grub_conf.rb +227 -0
- data/lib/resources/host.rb +306 -0
- data/lib/resources/http.rb +253 -0
- data/lib/resources/iis_app.rb +101 -0
- data/lib/resources/iis_site.rb +148 -0
- data/lib/resources/inetd_conf.rb +54 -0
- data/lib/resources/ini.rb +29 -0
- data/lib/resources/interface.rb +129 -0
- data/lib/resources/iptables.rb +80 -0
- data/lib/resources/json.rb +111 -0
- data/lib/resources/kernel_module.rb +107 -0
- data/lib/resources/kernel_parameter.rb +58 -0
- data/lib/resources/key_rsa.rb +63 -0
- data/lib/resources/limits_conf.rb +46 -0
- data/lib/resources/login_def.rb +57 -0
- data/lib/resources/mount.rb +88 -0
- data/lib/resources/mssql_session.rb +101 -0
- data/lib/resources/mysql.rb +82 -0
- data/lib/resources/mysql_conf.rb +127 -0
- data/lib/resources/mysql_session.rb +85 -0
- data/lib/resources/nginx.rb +96 -0
- data/lib/resources/nginx_conf.rb +226 -0
- data/lib/resources/npm.rb +48 -0
- data/lib/resources/ntp_conf.rb +51 -0
- data/lib/resources/oneget.rb +71 -0
- data/lib/resources/oracledb_session.rb +139 -0
- data/lib/resources/os.rb +36 -0
- data/lib/resources/os_env.rb +86 -0
- data/lib/resources/package.rb +370 -0
- data/lib/resources/packages.rb +111 -0
- data/lib/resources/parse_config.rb +112 -0
- data/lib/resources/passwd.rb +76 -0
- data/lib/resources/pip.rb +130 -0
- data/lib/resources/platform.rb +109 -0
- data/lib/resources/port.rb +771 -0
- data/lib/resources/postgres.rb +131 -0
- data/lib/resources/postgres_conf.rb +114 -0
- data/lib/resources/postgres_hba_conf.rb +90 -0
- data/lib/resources/postgres_ident_conf.rb +79 -0
- data/lib/resources/postgres_session.rb +71 -0
- data/lib/resources/powershell.rb +67 -0
- data/lib/resources/processes.rb +204 -0
- data/lib/resources/rabbitmq_conf.rb +51 -0
- data/lib/resources/registry_key.rb +297 -0
- data/lib/resources/security_policy.rb +180 -0
- data/lib/resources/service.rb +794 -0
- data/lib/resources/shadow.rb +159 -0
- data/lib/resources/ssh_conf.rb +97 -0
- data/lib/resources/ssl.rb +99 -0
- data/lib/resources/sys_info.rb +28 -0
- data/lib/resources/toml.rb +32 -0
- data/lib/resources/users.rb +654 -0
- data/lib/resources/vbscript.rb +68 -0
- data/lib/resources/virtualization.rb +247 -0
- data/lib/resources/windows_feature.rb +84 -0
- data/lib/resources/windows_hotfix.rb +35 -0
- data/lib/resources/windows_task.rb +102 -0
- data/lib/resources/wmi.rb +110 -0
- data/lib/resources/x509_certificate.rb +137 -0
- data/lib/resources/xinetd.rb +106 -0
- data/lib/resources/xml.rb +46 -0
- data/lib/resources/yaml.rb +43 -0
- data/lib/resources/yum.rb +180 -0
- data/lib/resources/zfs_dataset.rb +60 -0
- data/lib/resources/zfs_pool.rb +49 -0
- data/lib/source_readers/flat.rb +39 -0
- data/lib/source_readers/inspec.rb +75 -0
- data/lib/utils/command_wrapper.rb +27 -0
- data/lib/utils/convert.rb +12 -0
- data/lib/utils/database_helpers.rb +77 -0
- data/lib/utils/enumerable_delegation.rb +9 -0
- data/lib/utils/erlang_parser.rb +192 -0
- data/lib/utils/file_reader.rb +25 -0
- data/lib/utils/filter.rb +273 -0
- data/lib/utils/filter_array.rb +27 -0
- data/lib/utils/find_files.rb +47 -0
- data/lib/utils/hash.rb +41 -0
- data/lib/utils/json_log.rb +18 -0
- data/lib/utils/latest_version.rb +22 -0
- data/lib/utils/modulator.rb +12 -0
- data/lib/utils/nginx_parser.rb +105 -0
- data/lib/utils/object_traversal.rb +49 -0
- data/lib/utils/parser.rb +274 -0
- data/lib/utils/pkey_reader.rb +15 -0
- data/lib/utils/plugin_registry.rb +93 -0
- data/lib/utils/simpleconfig.rb +120 -0
- data/lib/utils/spdx.rb +13 -0
- data/lib/utils/spdx.txt +344 -0
- metadata +713 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
3
|
+
module Inspec
|
4
|
+
class Value
|
5
|
+
include ::Inspec::RubyHelper
|
6
|
+
|
7
|
+
attr_accessor :qualifier
|
8
|
+
attr_accessor :skip
|
9
|
+
attr_accessor :variable
|
10
|
+
|
11
|
+
def initialize(qualifiers = [])
|
12
|
+
@qualifier = qualifiers
|
13
|
+
@variable = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_ruby
|
17
|
+
res = @variable.nil? ? '' : "#{@variable} = "
|
18
|
+
res + @qualifier.map { |x| ruby_qualifier(x) }.join('.')
|
19
|
+
end
|
20
|
+
|
21
|
+
def name_variable(cache = [])
|
22
|
+
@variable = Array('a'..'z').find { |x| !cache.include?(x) }
|
23
|
+
cache.push(@variable)
|
24
|
+
@variable
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'forwardable'
|
6
|
+
|
7
|
+
module Inspec
|
8
|
+
# Resource Plugins
|
9
|
+
module Plugins
|
10
|
+
autoload :Resource, 'inspec/plugins/resource'
|
11
|
+
autoload :CLI, 'inspec/plugins/cli'
|
12
|
+
autoload :Fetcher, 'inspec/plugins/fetcher'
|
13
|
+
autoload :SourceReader, 'inspec/plugins/source_reader'
|
14
|
+
autoload :Secret, 'inspec/plugins/secret'
|
15
|
+
end
|
16
|
+
|
17
|
+
# PLEASE NOTE: The Plugin system is an internal mechanism for connecting
|
18
|
+
# inspec components. Its API is currently considered in an alpha state
|
19
|
+
# and may change between minor version revisions. A stable plugin API will be
|
20
|
+
# released in the future.
|
21
|
+
class PluginCtl
|
22
|
+
extend Forwardable
|
23
|
+
|
24
|
+
attr_reader :registry
|
25
|
+
def_delegator :registry, :keys, :list
|
26
|
+
|
27
|
+
def initialize(home = nil)
|
28
|
+
@paths = []
|
29
|
+
|
30
|
+
# load plugins in the same gem installation
|
31
|
+
lib_home = File.expand_path(File.join(__FILE__, '..', '..', '..', '..'))
|
32
|
+
@paths += Dir[lib_home+'/inspec-*-*/lib/inspec-*rb']
|
33
|
+
|
34
|
+
# traverse out of inspec-vX.Y.Z/lib/inspec/plugins.rb
|
35
|
+
@home = home || File.join(Dir.home, '.inspec', 'plugins')
|
36
|
+
@paths += Dir[File.join(@home, '**{,/*/**}', '*.gemspec')]
|
37
|
+
.map { |x| File.dirname(x) }
|
38
|
+
.map { |x| Dir[File.join(x, 'lib', 'inspec-*.rb')] }
|
39
|
+
.flatten
|
40
|
+
|
41
|
+
# load bundled plugins
|
42
|
+
bundled_dir = File.expand_path(File.dirname(__FILE__))
|
43
|
+
@paths += Dir[File.join(bundled_dir, '..', 'bundles', 'inspec-*.rb')].flatten
|
44
|
+
|
45
|
+
# map paths to names
|
46
|
+
@registry = Hash[@paths.map { |x|
|
47
|
+
[File.basename(x, '.rb'), x]
|
48
|
+
}]
|
49
|
+
end
|
50
|
+
|
51
|
+
def load(name)
|
52
|
+
path = @registry[name]
|
53
|
+
if path.nil?
|
54
|
+
raise "Couldn't find plugin #{name}. Searching in #{@home}"
|
55
|
+
end
|
56
|
+
# puts "Loading plugin #{name} from #{path}"
|
57
|
+
require path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Christoph Hartmann
|
3
|
+
# author: Dominik Richter
|
4
|
+
|
5
|
+
module Inspec
|
6
|
+
module Plugins
|
7
|
+
# stores all CLI plugin, we expect those to the `Thor` subclasses
|
8
|
+
class CLI
|
9
|
+
def self.subcommands
|
10
|
+
@subcommands ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.add_subcommand(klass, subcommand_name, usage, description, options = {})
|
14
|
+
subcommands[subcommand_name] = {
|
15
|
+
klass: klass,
|
16
|
+
subcommand_name: subcommand_name,
|
17
|
+
usage: usage,
|
18
|
+
description: description,
|
19
|
+
options: options,
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
require 'utils/plugin_registry'
|
5
|
+
require 'inspec/file_provider'
|
6
|
+
|
7
|
+
module Inspec
|
8
|
+
module Plugins
|
9
|
+
#
|
10
|
+
# An Inspec::Plugins::Fetcher is responsible for fetching a remote
|
11
|
+
# source to a local directory or file provided by the user.
|
12
|
+
#
|
13
|
+
# In general, there are two kinds of fetchers. (1) Fetchers that
|
14
|
+
# implement this entire API (see the Git or Url fetchers for
|
15
|
+
# examples), and (2) fetchers that only implement self.resolve and
|
16
|
+
# then call the resolve_next method with a modified target hash.
|
17
|
+
# Fetchers in (2) do not need to implement the functions in this
|
18
|
+
# class because the caller will never actually get an instance of
|
19
|
+
# those fetchers.
|
20
|
+
#
|
21
|
+
class Fetcher < PluginRegistry::Plugin
|
22
|
+
def self.plugin_registry
|
23
|
+
Inspec::Fetcher
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :target
|
27
|
+
|
28
|
+
def writable?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# The path to the archive on disk. This can be passed to a
|
34
|
+
# FileProvider to get access to the files in the fetched
|
35
|
+
# profile.
|
36
|
+
#
|
37
|
+
def archive_path
|
38
|
+
raise "Fetcher #{self} does not implement `archive_path()`. This is required."
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Fetches the remote source to a local source, using the
|
43
|
+
# provided path as a partial filename. That is, if you pass
|
44
|
+
# /foo/bar/baz, the fetcher can create:
|
45
|
+
#
|
46
|
+
# /foo/bar/baz/: A profile directory, or
|
47
|
+
# /foo/bar/baz.tar.gz: A profile tarball, or
|
48
|
+
# /foo/bar/baz.zip
|
49
|
+
#
|
50
|
+
def fetch(_path)
|
51
|
+
raise "Fetcher #{self} does not implement `fetch()`. This is required."
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# The full specification of the remote source, with any
|
56
|
+
# ambigious references provided by the user resolved to an exact
|
57
|
+
# reference where possible. For example, in the Git provide, a
|
58
|
+
# tag will be resolved to an exact revision.
|
59
|
+
#
|
60
|
+
def resolved_source
|
61
|
+
raise "Fetcher #{self} does not implement `resolved_source()`. This is required for terminal fetchers."
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# The unique key based on the content of the remote archive.
|
66
|
+
#
|
67
|
+
def cache_key
|
68
|
+
raise "Fetcher #{self} does not implement `cache_key()`. This is required for terminal fetchers."
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# relative_target is provided to keep compatibility with 3rd
|
73
|
+
# party plugins.
|
74
|
+
#
|
75
|
+
# Deprecated: This function may be removed in future versions of
|
76
|
+
# Inspec, don't depend on it in new plugins.
|
77
|
+
#
|
78
|
+
# @returns [Inspec::RelativeFileProvider]
|
79
|
+
#
|
80
|
+
def relative_target
|
81
|
+
file_provider = Inspec::FileProvider.for_path(archive_path)
|
82
|
+
file_provider.relative_provider
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
module Inspec
|
6
|
+
module ResourceBehaviors
|
7
|
+
def to_s
|
8
|
+
@__resource_name__
|
9
|
+
end
|
10
|
+
|
11
|
+
# Overwrite inspect to provide better output to RSpec results.
|
12
|
+
#
|
13
|
+
# @return [String] full name of the resource
|
14
|
+
def inspect
|
15
|
+
to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module ResourceDSL
|
20
|
+
def name(name = nil)
|
21
|
+
return if name.nil?
|
22
|
+
@name = name
|
23
|
+
__register(name, self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def desc(description = nil)
|
27
|
+
return if description.nil?
|
28
|
+
__resource_registry[@name].desc(description)
|
29
|
+
end
|
30
|
+
|
31
|
+
def supports(criteria = nil)
|
32
|
+
return if criteria.nil?
|
33
|
+
Inspec::Resource.supports[@name] ||= []
|
34
|
+
Inspec::Resource.supports[@name].push(criteria)
|
35
|
+
end
|
36
|
+
|
37
|
+
def example(example = nil)
|
38
|
+
return if example.nil?
|
39
|
+
__resource_registry[@name].example(example)
|
40
|
+
end
|
41
|
+
|
42
|
+
def __resource_registry
|
43
|
+
Inspec::Resource.registry
|
44
|
+
end
|
45
|
+
|
46
|
+
def __register(name, obj) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
47
|
+
cl = Class.new(obj) do # rubocop:disable Metrics/BlockLength
|
48
|
+
attr_reader :resource_exception_message
|
49
|
+
|
50
|
+
def initialize(backend, name, *args)
|
51
|
+
@resource_skipped = false
|
52
|
+
@resource_failed = false
|
53
|
+
@supports = Inspec::Resource.supports[name]
|
54
|
+
|
55
|
+
# attach the backend to this instance
|
56
|
+
@__backend_runner__ = backend
|
57
|
+
@__resource_name__ = name
|
58
|
+
|
59
|
+
# check resource supports
|
60
|
+
supported = true
|
61
|
+
supported = check_supports unless @supports.nil?
|
62
|
+
test_backend = defined?(Train::Transports::Mock::Connection) && backend.backend.class == Train::Transports::Mock::Connection
|
63
|
+
# do not return if we are supported, or for tests
|
64
|
+
return unless supported || test_backend
|
65
|
+
|
66
|
+
# call the resource initializer
|
67
|
+
begin
|
68
|
+
super(*args)
|
69
|
+
rescue Inspec::Exceptions::ResourceSkipped => e
|
70
|
+
skip_resource(e.message)
|
71
|
+
rescue Inspec::Exceptions::ResourceFailed => e
|
72
|
+
fail_resource(e.message)
|
73
|
+
rescue NoMethodError => e
|
74
|
+
# The new platform resources have methods generated on the fly
|
75
|
+
# for inspec check to work we need to skip these train errors
|
76
|
+
raise unless test_backend && e.receiver.class == Train::Transports::Mock::Connection
|
77
|
+
skip_resource(e.message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.desc(description = nil)
|
82
|
+
return @description if description.nil?
|
83
|
+
@description = description
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.example(example = nil)
|
87
|
+
return @example if example.nil?
|
88
|
+
@example = example
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_supports
|
92
|
+
status = inspec.platform.supported?(@supports)
|
93
|
+
skip_msg = "Resource #{@__resource_name__.capitalize} is not supported on platform #{inspec.platform.name}/#{inspec.platform.release}."
|
94
|
+
skip_resource(skip_msg) unless status
|
95
|
+
status
|
96
|
+
end
|
97
|
+
|
98
|
+
def skip_resource(message)
|
99
|
+
@resource_skipped = true
|
100
|
+
@resource_exception_message = message
|
101
|
+
end
|
102
|
+
|
103
|
+
def resource_skipped?
|
104
|
+
@resource_skipped
|
105
|
+
end
|
106
|
+
|
107
|
+
def fail_resource(message)
|
108
|
+
@resource_failed = true
|
109
|
+
@resource_exception_message = message
|
110
|
+
end
|
111
|
+
|
112
|
+
def resource_failed?
|
113
|
+
@resource_failed
|
114
|
+
end
|
115
|
+
|
116
|
+
def inspec
|
117
|
+
@__backend_runner__
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# rubocop:enable Lint/NestedMethodDefinition
|
122
|
+
if __resource_registry.key?(name)
|
123
|
+
Inspec::Log.warn("Overwriting resource #{name}. To reference a specific version of #{name} use the resource() method")
|
124
|
+
end
|
125
|
+
__resource_registry[name] = cl
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
module Plugins
|
130
|
+
class Resource
|
131
|
+
extend Inspec::ResourceDSL
|
132
|
+
include Inspec::ResourceBehaviors
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'utils/plugin_registry'
|
6
|
+
|
7
|
+
module Inspec
|
8
|
+
module Plugins
|
9
|
+
class Secret < PluginRegistry::Plugin
|
10
|
+
def self.plugin_registry
|
11
|
+
Inspec::SecretsBackend
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
|
5
|
+
require 'utils/plugin_registry'
|
6
|
+
|
7
|
+
module Inspec
|
8
|
+
module Plugins
|
9
|
+
class SourceReader < PluginRegistry::Plugin
|
10
|
+
def self.plugin_registry
|
11
|
+
Inspec::SourceReader
|
12
|
+
end
|
13
|
+
|
14
|
+
# Retrieve this profile's metadata.
|
15
|
+
#
|
16
|
+
# @return [Inspec::Metadata] profile metadata
|
17
|
+
def metadata
|
18
|
+
raise "SourceReader #{self} does not implement `metadata()`. This method is required"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Retrieve this profile's tests
|
22
|
+
#
|
23
|
+
# "tests" here refers to a test file. Individual controls and anonymous
|
24
|
+
# tests are later extracted from the raw contents of a test file. The map
|
25
|
+
# her simply maps from a test file name to the file contents.
|
26
|
+
#
|
27
|
+
# @return [Hash] Collection with references pointing to test contents
|
28
|
+
def tests
|
29
|
+
raise "SourceReader #{self} does not implement `tests()`. This method is required"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Retrieve this profile's libraries
|
33
|
+
#
|
34
|
+
# @return [Hash] Collection with references pointing to library contents
|
35
|
+
def libraries
|
36
|
+
raise "SourceReader #{self} does not implement `libraries()`. This method is required"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,513 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2015 Dominik Richter
|
3
|
+
# author: Dominik Richter
|
4
|
+
# author: Christoph Hartmann
|
5
|
+
|
6
|
+
require 'forwardable'
|
7
|
+
require 'openssl'
|
8
|
+
require 'inspec/polyfill'
|
9
|
+
require 'inspec/cached_fetcher'
|
10
|
+
require 'inspec/file_provider'
|
11
|
+
require 'inspec/source_reader'
|
12
|
+
require 'inspec/metadata'
|
13
|
+
require 'inspec/backend'
|
14
|
+
require 'inspec/rule'
|
15
|
+
require 'inspec/log'
|
16
|
+
require 'inspec/profile_context'
|
17
|
+
require 'inspec/runtime_profile'
|
18
|
+
require 'inspec/method_source'
|
19
|
+
require 'inspec/dependencies/cache'
|
20
|
+
require 'inspec/dependencies/lockfile'
|
21
|
+
require 'inspec/dependencies/dependency_set'
|
22
|
+
|
23
|
+
module Inspec
|
24
|
+
class Profile
|
25
|
+
extend Forwardable
|
26
|
+
|
27
|
+
def self.resolve_target(target, cache)
|
28
|
+
Inspec::Log.debug "Resolve #{target} into cache #{cache.path}"
|
29
|
+
Inspec::CachedFetcher.new(target, cache)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check if the profile contains a vendored cache, move content into global cache
|
33
|
+
# TODO: use relative file provider
|
34
|
+
# TODO: use source reader for Cache as well
|
35
|
+
def self.copy_deps_into_cache(file_provider, opts)
|
36
|
+
# filter content
|
37
|
+
cache = file_provider.files.find_all do |entry|
|
38
|
+
entry.start_with?('vendor')
|
39
|
+
end
|
40
|
+
content = Hash[cache.map { |x| [x, file_provider.binread(x)] }]
|
41
|
+
keys = content.keys
|
42
|
+
keys.each do |key|
|
43
|
+
next if content[key].nil?
|
44
|
+
# remove prefix
|
45
|
+
rel = Pathname.new(key).relative_path_from(Pathname.new('vendor')).to_s
|
46
|
+
tar = Pathname.new(opts[:vendor_cache].path).join(rel)
|
47
|
+
|
48
|
+
FileUtils.mkdir_p tar.dirname.to_s
|
49
|
+
Inspec::Log.debug "Copy #{tar} to cache directory"
|
50
|
+
File.binwrite(tar.to_s, content[key])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.for_path(path, opts)
|
55
|
+
file_provider = FileProvider.for_path(path)
|
56
|
+
rp = file_provider.relative_provider
|
57
|
+
|
58
|
+
# copy embedded dependecies into global cache
|
59
|
+
copy_deps_into_cache(rp, opts) unless opts[:vendor_cache].nil?
|
60
|
+
|
61
|
+
reader = Inspec::SourceReader.resolve(rp)
|
62
|
+
if reader.nil?
|
63
|
+
raise("Don't understand inspec profile in #{path}, it " \
|
64
|
+
"doesn't look like a supported profile structure.")
|
65
|
+
end
|
66
|
+
new(reader, opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.for_fetcher(fetcher, opts)
|
70
|
+
opts[:vendor_cache] = opts[:vendor_cache] || Cache.new
|
71
|
+
path, writable = fetcher.fetch
|
72
|
+
for_path(path, opts.merge(target: fetcher.target, writable: writable))
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.for_target(target, opts = {})
|
76
|
+
opts[:vendor_cache] = opts[:vendor_cache] || Cache.new
|
77
|
+
fetcher = resolve_target(target, opts[:vendor_cache])
|
78
|
+
for_fetcher(fetcher, opts)
|
79
|
+
end
|
80
|
+
|
81
|
+
attr_reader :source_reader, :backend, :runner_context, :check_mode
|
82
|
+
def_delegator :@source_reader, :tests
|
83
|
+
def_delegator :@source_reader, :libraries
|
84
|
+
def_delegator :@source_reader, :metadata
|
85
|
+
|
86
|
+
# rubocop:disable Metrics/AbcSize
|
87
|
+
def initialize(source_reader, options = {})
|
88
|
+
@source_reader = source_reader
|
89
|
+
@target = options[:target]
|
90
|
+
@logger = options[:logger] || Logger.new(nil)
|
91
|
+
@locked_dependencies = options[:dependencies]
|
92
|
+
@controls = options[:controls] || []
|
93
|
+
@writable = options[:writable] || false
|
94
|
+
@profile_id = options[:id]
|
95
|
+
@cache = options[:vendor_cache] || Cache.new
|
96
|
+
@attr_values = options[:attributes]
|
97
|
+
@tests_collected = false
|
98
|
+
@libraries_loaded = false
|
99
|
+
@check_mode = options[:check_mode] || false
|
100
|
+
Metadata.finalize(@source_reader.metadata, @profile_id, options)
|
101
|
+
|
102
|
+
# if a backend has already been created, clone it so each profile has its own unique backend object
|
103
|
+
# otherwise, create a new backend object
|
104
|
+
#
|
105
|
+
# This is necessary since we store the RuntimeProfile on the backend object. If a user runs `inspec exec`
|
106
|
+
# with multiple profiles, only the RuntimeProfile for the last-loaded profile will be available if
|
107
|
+
# we share the backend between profiles.
|
108
|
+
#
|
109
|
+
# This will cause issues if a profile attempts to load a file via `inspec.profile.file`
|
110
|
+
train_options = options.reject { |k, _| k == 'target' } # See https://github.com/chef/inspec/pull/1646
|
111
|
+
@backend = options[:backend].nil? ? Inspec::Backend.create(train_options) : options[:backend].dup
|
112
|
+
@runtime_profile = RuntimeProfile.new(self)
|
113
|
+
@backend.profile = @runtime_profile
|
114
|
+
|
115
|
+
@runner_context =
|
116
|
+
options[:profile_context] ||
|
117
|
+
Inspec::ProfileContext.for_profile(self, @backend, @attr_values)
|
118
|
+
|
119
|
+
@supports_platform = metadata.supports_platform?(@backend)
|
120
|
+
@supports_runtime = metadata.supports_runtime?
|
121
|
+
end
|
122
|
+
|
123
|
+
def name
|
124
|
+
metadata.params[:name]
|
125
|
+
end
|
126
|
+
|
127
|
+
def version
|
128
|
+
metadata.params[:version]
|
129
|
+
end
|
130
|
+
|
131
|
+
def writable?
|
132
|
+
@writable
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Is this profile is supported on the current platform of the
|
137
|
+
# backend machine and the current inspec version.
|
138
|
+
#
|
139
|
+
# @returns [TrueClass, FalseClass]
|
140
|
+
#
|
141
|
+
def supported?
|
142
|
+
supports_platform? && supports_runtime?
|
143
|
+
end
|
144
|
+
|
145
|
+
def supports_platform?
|
146
|
+
if @supports_platform.nil?
|
147
|
+
@supports_platform = metadata.supports_platform?(@backend)
|
148
|
+
end
|
149
|
+
@supports_platform
|
150
|
+
end
|
151
|
+
|
152
|
+
def supports_runtime?
|
153
|
+
if @supports_runtime.nil?
|
154
|
+
@supports_runtime = metadata.supports_runtime?
|
155
|
+
end
|
156
|
+
@supports_runtime
|
157
|
+
end
|
158
|
+
|
159
|
+
def params
|
160
|
+
@params ||= load_params
|
161
|
+
end
|
162
|
+
|
163
|
+
def collect_tests(include_list = @controls)
|
164
|
+
if !@tests_collected
|
165
|
+
locked_dependencies.each(&:collect_tests)
|
166
|
+
|
167
|
+
tests.each do |path, content|
|
168
|
+
next if content.nil? || content.empty?
|
169
|
+
abs_path = source_reader.target.abs_path(path)
|
170
|
+
@runner_context.load_control_file(content, abs_path, nil)
|
171
|
+
end
|
172
|
+
@tests_collected = true
|
173
|
+
end
|
174
|
+
filter_controls(@runner_context.all_rules, include_list)
|
175
|
+
end
|
176
|
+
|
177
|
+
def filter_controls(controls_array, include_list)
|
178
|
+
return controls_array if include_list.nil? || include_list.empty?
|
179
|
+
controls_array.select do |c|
|
180
|
+
id = ::Inspec::Rule.rule_id(c)
|
181
|
+
include_list.include?(id)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def load_libraries
|
186
|
+
return @runner_context if @libraries_loaded
|
187
|
+
|
188
|
+
locked_dependencies.each do |d|
|
189
|
+
c = d.load_libraries
|
190
|
+
@runner_context.add_resources(c)
|
191
|
+
end
|
192
|
+
|
193
|
+
libs = libraries.map do |path, content|
|
194
|
+
[content, path]
|
195
|
+
end
|
196
|
+
|
197
|
+
@runner_context.load_libraries(libs)
|
198
|
+
@libraries_loaded = true
|
199
|
+
@runner_context
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_s
|
203
|
+
"Inspec::Profile<#{name}>"
|
204
|
+
end
|
205
|
+
|
206
|
+
# return info using uncached params
|
207
|
+
def info!
|
208
|
+
info(load_params.dup)
|
209
|
+
end
|
210
|
+
|
211
|
+
def info(res = params.dup)
|
212
|
+
# add information about the controls
|
213
|
+
res[:controls] = res[:controls].map do |id, rule|
|
214
|
+
next if id.to_s.empty?
|
215
|
+
data = rule.dup
|
216
|
+
data.delete(:checks)
|
217
|
+
data[:impact] ||= 0.5
|
218
|
+
data[:impact] = 1.0 if data[:impact] > 1.0
|
219
|
+
data[:impact] = 0.0 if data[:impact] < 0.0
|
220
|
+
data[:id] = id
|
221
|
+
data
|
222
|
+
end.compact
|
223
|
+
|
224
|
+
# resolve hash structure in groups
|
225
|
+
res[:groups] = res[:groups].map do |id, group|
|
226
|
+
group[:id] = id
|
227
|
+
group
|
228
|
+
end
|
229
|
+
|
230
|
+
# add information about the required attributes
|
231
|
+
res[:attributes] = res[:attributes].map(&:to_hash) unless res[:attributes].nil? || res[:attributes].empty?
|
232
|
+
res[:sha256] = sha256
|
233
|
+
res
|
234
|
+
end
|
235
|
+
|
236
|
+
# Check if the profile is internally well-structured. The logger will be
|
237
|
+
# used to print information on errors and warnings which are found.
|
238
|
+
#
|
239
|
+
# @return [Boolean] true if no errors were found, false otherwise
|
240
|
+
def check # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
|
241
|
+
# initial values for response object
|
242
|
+
result = {
|
243
|
+
summary: {
|
244
|
+
valid: false,
|
245
|
+
timestamp: Time.now.iso8601,
|
246
|
+
location: @target,
|
247
|
+
profile: nil,
|
248
|
+
controls: 0,
|
249
|
+
},
|
250
|
+
errors: [],
|
251
|
+
warnings: [],
|
252
|
+
}
|
253
|
+
|
254
|
+
entry = lambda { |file, line, column, control, msg|
|
255
|
+
{
|
256
|
+
file: file,
|
257
|
+
line: line,
|
258
|
+
column: column,
|
259
|
+
control_id: control,
|
260
|
+
msg: msg,
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
warn = lambda { |file, line, column, control, msg|
|
265
|
+
@logger.warn(msg)
|
266
|
+
result[:warnings].push(entry.call(file, line, column, control, msg))
|
267
|
+
}
|
268
|
+
|
269
|
+
error = lambda { |file, line, column, control, msg|
|
270
|
+
@logger.error(msg)
|
271
|
+
result[:errors].push(entry.call(file, line, column, control, msg))
|
272
|
+
}
|
273
|
+
|
274
|
+
@logger.info "Checking profile in #{@target}"
|
275
|
+
meta_path = @source_reader.target.abs_path(@source_reader.metadata.ref)
|
276
|
+
if meta_path =~ /metadata\.rb$/
|
277
|
+
warn.call(@target, 0, 0, nil, 'The use of `metadata.rb` is deprecated. Use `inspec.yml`.')
|
278
|
+
end
|
279
|
+
|
280
|
+
# verify metadata
|
281
|
+
m_errors, m_warnings = metadata.valid
|
282
|
+
m_errors.each { |msg| error.call(meta_path, 0, 0, nil, msg) }
|
283
|
+
m_warnings.each { |msg| warn.call(meta_path, 0, 0, nil, msg) }
|
284
|
+
m_unsupported = metadata.unsupported
|
285
|
+
m_unsupported.each { |u| warn.call(meta_path, 0, 0, nil, "doesn't support: #{u}") }
|
286
|
+
@logger.info 'Metadata OK.' if m_errors.empty? && m_unsupported.empty?
|
287
|
+
|
288
|
+
# extract profile name
|
289
|
+
result[:summary][:profile] = metadata.params[:name]
|
290
|
+
|
291
|
+
# check if the profile is using the old test directory instead of the
|
292
|
+
# new controls directory
|
293
|
+
if @source_reader.tests.keys.any? { |x| x =~ %r{^test/$} }
|
294
|
+
warn.call(@target, 0, 0, nil, 'Profile uses deprecated `test` directory, rename it to `controls`.')
|
295
|
+
end
|
296
|
+
|
297
|
+
count = controls_count
|
298
|
+
result[:summary][:controls] = count
|
299
|
+
if count == 0
|
300
|
+
warn.call(nil, nil, nil, nil, 'No controls or tests were defined.')
|
301
|
+
else
|
302
|
+
@logger.info("Found #{count} controls.")
|
303
|
+
end
|
304
|
+
|
305
|
+
# iterate over hash of groups
|
306
|
+
params[:controls].each { |id, control|
|
307
|
+
sfile = control[:source_location][:ref]
|
308
|
+
sline = control[:source_location][:line]
|
309
|
+
error.call(sfile, sline, nil, id, 'Avoid controls with empty IDs') if id.nil? or id.empty?
|
310
|
+
next if id.start_with? '(generated '
|
311
|
+
warn.call(sfile, sline, nil, id, "Control #{id} has no title") if control[:title].to_s.empty?
|
312
|
+
warn.call(sfile, sline, nil, id, "Control #{id} has no description") if control[:desc].to_s.empty?
|
313
|
+
warn.call(sfile, sline, nil, id, "Control #{id} has impact > 1.0") if control[:impact].to_f > 1.0
|
314
|
+
warn.call(sfile, sline, nil, id, "Control #{id} has impact < 0.0") if control[:impact].to_f < 0.0
|
315
|
+
warn.call(sfile, sline, nil, id, "Control #{id} has no tests defined") if control[:checks].nil? or control[:checks].empty?
|
316
|
+
}
|
317
|
+
|
318
|
+
# profile is valid if we could not find any error
|
319
|
+
result[:summary][:valid] = result[:errors].empty?
|
320
|
+
|
321
|
+
@logger.info 'Control definitions OK.' if result[:warnings].empty?
|
322
|
+
result
|
323
|
+
end
|
324
|
+
|
325
|
+
def controls_count
|
326
|
+
params[:controls].values.length
|
327
|
+
end
|
328
|
+
|
329
|
+
# generates a archive of a folder profile
|
330
|
+
# assumes that the profile was checked before
|
331
|
+
def archive(opts)
|
332
|
+
# check if file exists otherwise overwrite the archive
|
333
|
+
dst = archive_name(opts)
|
334
|
+
if dst.exist? && !opts[:overwrite]
|
335
|
+
@logger.info "Archive #{dst} exists already. Use --overwrite."
|
336
|
+
return false
|
337
|
+
end
|
338
|
+
|
339
|
+
# remove existing archive
|
340
|
+
File.delete(dst) if dst.exist?
|
341
|
+
@logger.info "Generate archive #{dst}."
|
342
|
+
|
343
|
+
# filter files that should not be part of the profile
|
344
|
+
# TODO ignore all .files, but add the files to debug output
|
345
|
+
|
346
|
+
# display all files that will be part of the archive
|
347
|
+
@logger.debug 'Add the following files to archive:'
|
348
|
+
files.each { |f| @logger.debug ' ' + f }
|
349
|
+
|
350
|
+
if opts[:zip]
|
351
|
+
# generate zip archive
|
352
|
+
require 'inspec/archive/zip'
|
353
|
+
zag = Inspec::Archive::ZipArchiveGenerator.new
|
354
|
+
zag.archive(root_path, files, dst)
|
355
|
+
else
|
356
|
+
# generate tar archive
|
357
|
+
require 'inspec/archive/tar'
|
358
|
+
tag = Inspec::Archive::TarArchiveGenerator.new
|
359
|
+
tag.archive(root_path, files, dst)
|
360
|
+
end
|
361
|
+
|
362
|
+
@logger.info 'Finished archive generation.'
|
363
|
+
true
|
364
|
+
end
|
365
|
+
|
366
|
+
def locked_dependencies
|
367
|
+
@locked_dependencies ||= load_dependencies
|
368
|
+
end
|
369
|
+
|
370
|
+
def lockfile_exists?
|
371
|
+
@source_reader.target.files.include?('inspec.lock')
|
372
|
+
end
|
373
|
+
|
374
|
+
def lockfile_path
|
375
|
+
File.join(cwd, 'inspec.lock')
|
376
|
+
end
|
377
|
+
|
378
|
+
def root_path
|
379
|
+
@source_reader.target.prefix
|
380
|
+
end
|
381
|
+
|
382
|
+
def files
|
383
|
+
@source_reader.target.files
|
384
|
+
end
|
385
|
+
|
386
|
+
#
|
387
|
+
# TODO(ssd): Relative path handling really needs to be carefully
|
388
|
+
# thought through, especially with respect to relative paths in
|
389
|
+
# tarballs.
|
390
|
+
#
|
391
|
+
def cwd
|
392
|
+
@target.is_a?(String) && File.directory?(@target) ? @target : './'
|
393
|
+
end
|
394
|
+
|
395
|
+
def lockfile
|
396
|
+
@lockfile ||= if lockfile_exists?
|
397
|
+
Inspec::Lockfile.from_content(@source_reader.target.read('inspec.lock'))
|
398
|
+
else
|
399
|
+
generate_lockfile
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
#
|
404
|
+
# Generate an in-memory lockfile. This won't render the lock file
|
405
|
+
# to disk, it must be explicitly written to disk by the caller.
|
406
|
+
#
|
407
|
+
# @param vendor_path [String] Path to the on-disk vendor dir
|
408
|
+
# @return [Inspec::Lockfile]
|
409
|
+
#
|
410
|
+
def generate_lockfile
|
411
|
+
res = Inspec::DependencySet.new(cwd, @cache, nil, @backend)
|
412
|
+
res.vendor(metadata.dependencies)
|
413
|
+
Inspec::Lockfile.from_dependency_set(res)
|
414
|
+
end
|
415
|
+
|
416
|
+
def load_dependencies
|
417
|
+
Inspec::DependencySet.from_lockfile(lockfile, cwd, @cache, @backend, { attributes: @attr_values })
|
418
|
+
end
|
419
|
+
|
420
|
+
# Calculate this profile's SHA256 checksum. Includes metadata, dependencies,
|
421
|
+
# libraries, data files, and controls.
|
422
|
+
#
|
423
|
+
# @return [Type] description of returned object
|
424
|
+
def sha256
|
425
|
+
# get all dependency checksums
|
426
|
+
deps = Hash[locked_dependencies.list.map { |k, v| [k, v.profile.sha256] }]
|
427
|
+
|
428
|
+
res = OpenSSL::Digest::SHA256.new
|
429
|
+
files = source_reader.tests.to_a + source_reader.libraries.to_a +
|
430
|
+
source_reader.data_files.to_a +
|
431
|
+
[['inspec.yml', source_reader.metadata.content]] +
|
432
|
+
[['inspec.lock.deps', YAML.dump(deps)]]
|
433
|
+
|
434
|
+
files.sort_by { |a| a[0] }
|
435
|
+
.map { |f| res << f[0] << "\0" << f[1] << "\0" }
|
436
|
+
|
437
|
+
res.digest.unpack('H*')[0]
|
438
|
+
end
|
439
|
+
|
440
|
+
private
|
441
|
+
|
442
|
+
# Create an archive name for this profile and an additional options
|
443
|
+
# configuration. Either use :output or generate the name from metadata.
|
444
|
+
#
|
445
|
+
# @param [Hash] configuration options
|
446
|
+
# @return [Pathname] path for the archive
|
447
|
+
def archive_name(opts)
|
448
|
+
if (name = opts[:output])
|
449
|
+
return Pathname.new(name)
|
450
|
+
end
|
451
|
+
|
452
|
+
name = params[:name] ||
|
453
|
+
raise('Cannot create an archive without a profile name! Please '\
|
454
|
+
'specify the name in metadata or use --output to create the archive.')
|
455
|
+
version = params[:version] ||
|
456
|
+
raise('Cannot create an archive without a profile version! Please '\
|
457
|
+
'specify the version in metadata or use --output to create the archive.')
|
458
|
+
ext = opts[:zip] ? 'zip' : 'tar.gz'
|
459
|
+
slug = name.downcase.strip.tr(' ', '-').gsub(/[^\w-]/, '_')
|
460
|
+
Pathname.new(Dir.pwd).join("#{slug}-#{version}.#{ext}")
|
461
|
+
end
|
462
|
+
|
463
|
+
def load_params
|
464
|
+
params = @source_reader.metadata.params
|
465
|
+
params[:name] = @profile_id unless @profile_id.nil?
|
466
|
+
load_checks_params(params)
|
467
|
+
@profile_id ||= params[:name]
|
468
|
+
params
|
469
|
+
end
|
470
|
+
|
471
|
+
def load_checks_params(params)
|
472
|
+
load_libraries
|
473
|
+
tests = collect_tests
|
474
|
+
params[:controls] = controls = {}
|
475
|
+
params[:groups] = groups = {}
|
476
|
+
prefix = @source_reader.target.prefix || ''
|
477
|
+
tests.each do |rule|
|
478
|
+
next if rule.nil?
|
479
|
+
f = load_rule_filepath(prefix, rule)
|
480
|
+
load_rule(rule, f, controls, groups)
|
481
|
+
end
|
482
|
+
params[:attributes] = @runner_context.attributes
|
483
|
+
params
|
484
|
+
end
|
485
|
+
|
486
|
+
def load_rule_filepath(prefix, rule)
|
487
|
+
file = rule.instance_variable_get(:@__file)
|
488
|
+
file = file[prefix.length..-1] if file.start_with?(prefix)
|
489
|
+
file
|
490
|
+
end
|
491
|
+
|
492
|
+
def load_rule(rule, file, controls, groups)
|
493
|
+
id = Inspec::Rule.rule_id(rule)
|
494
|
+
location = rule.instance_variable_get(:@__source_location)
|
495
|
+
controls[id] = {
|
496
|
+
title: rule.title,
|
497
|
+
desc: rule.desc,
|
498
|
+
impact: rule.impact,
|
499
|
+
refs: rule.ref,
|
500
|
+
tags: rule.tag,
|
501
|
+
checks: Inspec::Rule.checks(rule),
|
502
|
+
code: Inspec::MethodSource.code_at(location, source_reader),
|
503
|
+
source_location: location,
|
504
|
+
}
|
505
|
+
|
506
|
+
groups[file] ||= {
|
507
|
+
title: rule.instance_variable_get(:@__group_title),
|
508
|
+
controls: [],
|
509
|
+
}
|
510
|
+
groups[file][:controls].push(id)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|