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,208 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Dominik Richter
|
3
|
+
# author: Christoph Hartmann
|
4
|
+
require 'inspec/log'
|
5
|
+
require 'inspec/rule'
|
6
|
+
require 'inspec/resource'
|
7
|
+
require 'inspec/library_eval_context'
|
8
|
+
require 'inspec/control_eval_context'
|
9
|
+
require 'inspec/require_loader'
|
10
|
+
require 'securerandom'
|
11
|
+
require 'inspec/objects/attribute'
|
12
|
+
|
13
|
+
module Inspec
|
14
|
+
class ProfileContext
|
15
|
+
def self.for_profile(profile, backend, attributes)
|
16
|
+
new(profile.name, backend, { 'profile' => profile,
|
17
|
+
'attributes' => attributes,
|
18
|
+
'check_mode' => profile.check_mode })
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :attributes, :profile_id, :resource_registry, :backend
|
22
|
+
attr_accessor :rules
|
23
|
+
def initialize(profile_id, backend, conf)
|
24
|
+
if backend.nil?
|
25
|
+
raise 'ProfileContext is initiated with a backend == nil. ' \
|
26
|
+
'This is a backend error which must be fixed upstream.'
|
27
|
+
end
|
28
|
+
@profile_id = profile_id
|
29
|
+
@backend = backend
|
30
|
+
@conf = conf.dup
|
31
|
+
@skip_only_if_eval = @conf['check_mode']
|
32
|
+
@rules = {}
|
33
|
+
@control_subcontexts = []
|
34
|
+
@lib_subcontexts = []
|
35
|
+
@require_loader = ::Inspec::RequireLoader.new
|
36
|
+
@attributes = []
|
37
|
+
# A local resource registry that only contains resources defined
|
38
|
+
# in the transitive dependency tree of the loaded profile.
|
39
|
+
@resource_registry = Inspec::Resource.new_registry
|
40
|
+
@library_eval_context = Inspec::LibraryEvalContext.create(@resource_registry, @require_loader)
|
41
|
+
@current_load = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def dependencies
|
45
|
+
if @conf['profile'].nil?
|
46
|
+
{}
|
47
|
+
else
|
48
|
+
@conf['profile'].locked_dependencies
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_resources_dsl
|
53
|
+
Inspec::Resource.create_dsl(self)
|
54
|
+
end
|
55
|
+
|
56
|
+
def control_eval_context
|
57
|
+
@control_eval_context ||= begin
|
58
|
+
ctx = Inspec::ControlEvalContext.create(self, to_resources_dsl)
|
59
|
+
ctx.new(@backend, @conf, dependencies, @require_loader, @skip_only_if_eval)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def reload_dsl
|
64
|
+
@control_eval_context = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def profile_supports_platform?
|
68
|
+
return true if @conf['profile'].nil?
|
69
|
+
|
70
|
+
@conf['profile'].supports_platform?
|
71
|
+
end
|
72
|
+
|
73
|
+
def profile_supports_inspec_version?
|
74
|
+
return true if @conf['profile'].nil?
|
75
|
+
|
76
|
+
@conf['profile'].supports_runtime?
|
77
|
+
end
|
78
|
+
|
79
|
+
def remove_rule(id)
|
80
|
+
@rules[id] = nil if @rules.key?(id)
|
81
|
+
@control_subcontexts.each do |c|
|
82
|
+
c.remove_rule(id)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def all_controls
|
87
|
+
ret = @rules.values
|
88
|
+
ret += @control_subcontexts.map(&:all_rules).flatten
|
89
|
+
ret
|
90
|
+
end
|
91
|
+
alias all_rules all_controls
|
92
|
+
|
93
|
+
def subcontext_by_name(name)
|
94
|
+
found = @lib_subcontexts.find { |c| c.profile_id == name }
|
95
|
+
if !found
|
96
|
+
@lib_subcontexts.each do |c|
|
97
|
+
found = c.subcontext_by_name(name)
|
98
|
+
break if found
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
found
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_resources(context)
|
106
|
+
@resource_registry.merge!(context.resource_registry)
|
107
|
+
control_eval_context.add_resources(context)
|
108
|
+
@lib_subcontexts << context
|
109
|
+
reload_dsl
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_subcontext(context)
|
113
|
+
@control_subcontexts << context
|
114
|
+
end
|
115
|
+
|
116
|
+
def load_libraries(libs)
|
117
|
+
lib_prefix = 'libraries' + File::SEPARATOR
|
118
|
+
autoloads = []
|
119
|
+
|
120
|
+
libs.sort_by! { |l| l[1] } # Sort on source path so load order is deterministic
|
121
|
+
libs.each do |content, source, line|
|
122
|
+
path = source
|
123
|
+
if source.start_with?(lib_prefix)
|
124
|
+
path = source.sub(lib_prefix, '')
|
125
|
+
autoloads.push(path) if File.dirname(path) == '.'
|
126
|
+
end
|
127
|
+
|
128
|
+
@require_loader.add(path, content, source, line)
|
129
|
+
end
|
130
|
+
|
131
|
+
# load all files directly that are flat inside the libraries folder
|
132
|
+
autoloads.each do |path|
|
133
|
+
next unless path.end_with?('.rb')
|
134
|
+
load_library_file(*@require_loader.load(path)) unless @require_loader.loaded?(path)
|
135
|
+
end
|
136
|
+
reload_dsl
|
137
|
+
end
|
138
|
+
|
139
|
+
def load_control_file(*args)
|
140
|
+
# Set `skip_file` to `false` between file loads to prevent skips from spanning multiple control files
|
141
|
+
control_eval_context.skip_file = false
|
142
|
+
load_with_context(control_eval_context, *args)
|
143
|
+
end
|
144
|
+
alias load load_control_file
|
145
|
+
|
146
|
+
def load_library_file(*args)
|
147
|
+
load_with_context(@library_eval_context, *args)
|
148
|
+
end
|
149
|
+
|
150
|
+
def load_with_context(context, content, source = nil, line = nil)
|
151
|
+
Inspec::Log.debug("Loading #{source || '<anonymous content>'} into #{self}")
|
152
|
+
@current_load = { file: source }
|
153
|
+
if content.is_a? Proc
|
154
|
+
context.instance_eval(&content)
|
155
|
+
elsif source.nil? && line.nil?
|
156
|
+
context.instance_eval(content)
|
157
|
+
else
|
158
|
+
context.instance_eval(content, source || 'unknown', line || 1)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def unregister_rule(id)
|
163
|
+
@rules.delete(full_id(@profile_id, id))
|
164
|
+
end
|
165
|
+
|
166
|
+
attr_reader :current_load
|
167
|
+
|
168
|
+
def register_rule(r)
|
169
|
+
# get the full ID
|
170
|
+
file = if @current_load.nil?
|
171
|
+
'unknown'
|
172
|
+
else
|
173
|
+
@current_load[:file] || 'unknown'
|
174
|
+
end
|
175
|
+
r.instance_variable_set(:@__file, file)
|
176
|
+
r.instance_variable_set(:@__group_title, current_load[:title])
|
177
|
+
|
178
|
+
# add the rule to the registry
|
179
|
+
fid = full_id(Inspec::Rule.profile_id(r), Inspec::Rule.rule_id(r))
|
180
|
+
existing = @rules[fid]
|
181
|
+
if existing.nil?
|
182
|
+
@rules[fid] = r
|
183
|
+
else
|
184
|
+
Inspec::Rule.merge(existing, r)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def register_attribute(name, options = {})
|
189
|
+
# we need to return an attribute object, to allow dermination of default values
|
190
|
+
attr = Attribute.new(name, options)
|
191
|
+
# read value from given gived values
|
192
|
+
attr.value = @conf['attributes'][attr.name] unless @conf['attributes'].nil?
|
193
|
+
@attributes.push(attr)
|
194
|
+
attr.value
|
195
|
+
end
|
196
|
+
|
197
|
+
def set_header(field, val)
|
198
|
+
@current_load[field] = val
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
def full_id(pid, rid)
|
204
|
+
return rid.to_s if pid.to_s.empty?
|
205
|
+
pid.to_s + '/' + rid.to_s
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# author: Adam Leff
|
3
|
+
|
4
|
+
require 'inspec/profile'
|
5
|
+
|
6
|
+
module Inspec
|
7
|
+
class ProfileVendor
|
8
|
+
attr_reader :profile_path
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
@profile_path = Pathname.new(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def vendor!
|
15
|
+
vendor_dependencies
|
16
|
+
end
|
17
|
+
|
18
|
+
# The URL fetcher uses a Tempfile to retrieve the vendored
|
19
|
+
# profile, which creates a file that is only readable by
|
20
|
+
# the current user. In most circumstances, this is likely OK.
|
21
|
+
# However, in environments like a Habitat package, these files
|
22
|
+
# need to be readable by all users or the Habitat Supervisor
|
23
|
+
# may not be able to start InSpec correctly.
|
24
|
+
#
|
25
|
+
# This method makes sure all vendored files are mode 644 for this
|
26
|
+
# use case. This method is not called by default - the caller
|
27
|
+
# vendoring the profile must make the decision as to whether this
|
28
|
+
# is necessary.
|
29
|
+
def make_readable
|
30
|
+
Dir.glob("#{cache_path}/**/*") do |e|
|
31
|
+
FileUtils.chmod(0644, e) if File.file?(e)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def cache_path
|
36
|
+
profile_path.join('vendor')
|
37
|
+
end
|
38
|
+
|
39
|
+
def lockfile
|
40
|
+
profile_path.join('inspec.lock')
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def profile
|
46
|
+
@profile ||= Inspec::Profile.for_target(profile_path.to_s, profile_opts)
|
47
|
+
end
|
48
|
+
|
49
|
+
def profile_opts
|
50
|
+
{
|
51
|
+
vendor_cache: Inspec::Cache.new(cache_path.to_s),
|
52
|
+
backend: Inspec::Backend.create(target: 'mock://'),
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def vendor_dependencies
|
57
|
+
delete_vendored_data
|
58
|
+
File.write(lockfile, profile.generate_lockfile.to_yaml)
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_vendored_data
|
62
|
+
FileUtils.rm_rf(cache_path) if cache_path.exist?
|
63
|
+
File.delete(lockfile) if lockfile.exist?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'inspec/reporters/base'
|
2
|
+
require 'inspec/reporters/cli'
|
3
|
+
require 'inspec/reporters/json'
|
4
|
+
require 'inspec/reporters/json_min'
|
5
|
+
require 'inspec/reporters/junit'
|
6
|
+
require 'inspec/reporters/automate'
|
7
|
+
|
8
|
+
module Inspec::Reporters
|
9
|
+
def self.render(reporter, run_data)
|
10
|
+
name, config = reporter.dup
|
11
|
+
config[:run_data] = run_data
|
12
|
+
case name
|
13
|
+
when 'cli'
|
14
|
+
reporter = Inspec::Reporters::CLI.new(config)
|
15
|
+
when 'json'
|
16
|
+
reporter = Inspec::Reporters::Json.new(config)
|
17
|
+
when 'json-min'
|
18
|
+
reporter = Inspec::Reporters::JsonMin.new(config)
|
19
|
+
when 'junit'
|
20
|
+
reporter = Inspec::Reporters::Junit.new(config)
|
21
|
+
when 'automate'
|
22
|
+
reporter = Inspec::Reporters::Automate.new(config)
|
23
|
+
else
|
24
|
+
raise NotImplementedError, "'#{name}' is not a valid reporter type."
|
25
|
+
end
|
26
|
+
|
27
|
+
# optional send_report method on reporter
|
28
|
+
return reporter.send_report if defined?(reporter.send_report)
|
29
|
+
|
30
|
+
reporter.render
|
31
|
+
output = reporter.rendered_output
|
32
|
+
|
33
|
+
if config['file']
|
34
|
+
# create destination directory if it does not exist
|
35
|
+
dirname = File.dirname(config['file'])
|
36
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
37
|
+
|
38
|
+
File.write(config['file'], output)
|
39
|
+
elsif config['stdout'] == true
|
40
|
+
print output
|
41
|
+
STDOUT.flush
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.report(reporter, run_data)
|
46
|
+
name, config = reporter.dup
|
47
|
+
config[:run_data] = run_data
|
48
|
+
case name
|
49
|
+
when 'json'
|
50
|
+
reporter = Inspec::Reporters::Json.new(config)
|
51
|
+
when 'json-min'
|
52
|
+
reporter = Inspec::Reporters::JsonMin.new(config)
|
53
|
+
else
|
54
|
+
# use base run_data hash for any other report
|
55
|
+
return run_data
|
56
|
+
end
|
57
|
+
|
58
|
+
reporter.report
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module Inspec::Reporters
|
7
|
+
class Automate < Json
|
8
|
+
def initialize(config)
|
9
|
+
super(config)
|
10
|
+
|
11
|
+
# default to not verifying ssl for sending reports
|
12
|
+
@config['verify_ssl'] = @config['verify_ssl'] || false
|
13
|
+
end
|
14
|
+
|
15
|
+
def enriched_report
|
16
|
+
# grab the report from the parent class
|
17
|
+
final_report = report
|
18
|
+
|
19
|
+
# Label this content as an inspec_report
|
20
|
+
final_report[:type] = 'inspec_report'
|
21
|
+
|
22
|
+
final_report[:end_time] = Time.now.utc.strftime('%FT%TZ')
|
23
|
+
final_report[:node_uuid] = @config['node_uuid'] || @run_data[:platform][:uuid]
|
24
|
+
raise Inspec::ReporterError, 'Cannot find a UUID for your node. Please specify one via json-config.' if final_report[:node_uuid].nil?
|
25
|
+
|
26
|
+
final_report[:report_uuid] = uuid_from_string(final_report[:end_time] + final_report[:node_uuid])
|
27
|
+
|
28
|
+
# optional json-config passthrough options
|
29
|
+
%w{node_name environment roles recipies}.each do |option|
|
30
|
+
final_report[option.to_sym] = @config[option] unless @config[option].nil?
|
31
|
+
end
|
32
|
+
final_report
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_report
|
36
|
+
headers = { 'Content-Type' => 'application/json' }
|
37
|
+
headers['x-data-collector-token'] = @config['token']
|
38
|
+
headers['x-data-collector-auth'] = 'version=1.0'
|
39
|
+
|
40
|
+
uri = URI(@config['url'])
|
41
|
+
req = Net::HTTP::Post.new(uri.path, headers)
|
42
|
+
req.body = enriched_report.to_json
|
43
|
+
begin
|
44
|
+
Inspec::Log.debug "Posting report to Chef Automate: #{uri.path}"
|
45
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
46
|
+
http.use_ssl = uri.scheme == 'https'
|
47
|
+
if @config['verify_ssl'] == true
|
48
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
49
|
+
else
|
50
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
51
|
+
end
|
52
|
+
|
53
|
+
http.request(req)
|
54
|
+
return true
|
55
|
+
rescue => e
|
56
|
+
Inspec::Log.error "send_report: POST to #{uri.path} returned: #{e.message}"
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# This hashes the passed string into SHA1.
|
64
|
+
# Then it downgrades the 160bit SHA1 to a 128bit
|
65
|
+
# then we format it as a valid UUIDv5.
|
66
|
+
def uuid_from_string(string)
|
67
|
+
hash = Digest::SHA1.new
|
68
|
+
hash.update(string)
|
69
|
+
ary = hash.digest.unpack('NnnnnN')
|
70
|
+
ary[2] = (ary[2] & 0x0FFF) | (5 << 12)
|
71
|
+
ary[3] = (ary[3] & 0x3FFF) | 0x8000
|
72
|
+
# rubocop:disable Style/FormatString
|
73
|
+
'%08x-%04x-%04x-%04x-%04x%08x' % ary
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Inspec::Reporters
|
2
|
+
class Base
|
3
|
+
attr_reader :run_data
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
@run_data = config[:run_data]
|
8
|
+
@output = ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def output(str, newline = true)
|
12
|
+
@output << str
|
13
|
+
@output << "\n" if newline
|
14
|
+
end
|
15
|
+
|
16
|
+
def rendered_output
|
17
|
+
@output
|
18
|
+
end
|
19
|
+
|
20
|
+
# each reporter must implement #render
|
21
|
+
def render
|
22
|
+
raise NotImplementedError, "#{self.class} must implement a `#render` method to format its output."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,356 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Inspec::Reporters
|
4
|
+
class CLI < Base
|
5
|
+
case RUBY_PLATFORM
|
6
|
+
when /windows|mswin|msys|mingw|cygwin/
|
7
|
+
# Most currently available Windows terminals have poor support
|
8
|
+
# for ANSI extended colors
|
9
|
+
COLORS = {
|
10
|
+
'failed' => "\033[0;1;31m",
|
11
|
+
'passed' => "\033[0;1;32m",
|
12
|
+
'skipped' => "\033[0;37m",
|
13
|
+
'reset' => "\033[0m",
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
# Most currently available Windows terminals have poor support
|
17
|
+
# for UTF-8 characters so use these boring indicators
|
18
|
+
INDICATORS = {
|
19
|
+
'failed' => '[FAIL]',
|
20
|
+
'skipped' => '[SKIP]',
|
21
|
+
'passed' => '[PASS]',
|
22
|
+
'unknown' => '[UNKN]',
|
23
|
+
}.freeze
|
24
|
+
else
|
25
|
+
# Extended colors for everyone else
|
26
|
+
COLORS = {
|
27
|
+
'failed' => "\033[38;5;9m",
|
28
|
+
'passed' => "\033[38;5;41m",
|
29
|
+
'skipped' => "\033[38;5;247m",
|
30
|
+
'reset' => "\033[0m",
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
# Groovy UTF-8 characters for everyone else...
|
34
|
+
# ...even though they probably only work on Mac
|
35
|
+
INDICATORS = {
|
36
|
+
'failed' => '×',
|
37
|
+
'skipped' => '↺',
|
38
|
+
'passed' => '✔',
|
39
|
+
'unknown' => '?',
|
40
|
+
}.freeze
|
41
|
+
end
|
42
|
+
|
43
|
+
MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60
|
44
|
+
|
45
|
+
def render
|
46
|
+
run_data[:profiles].each do |profile|
|
47
|
+
@control_count = 0
|
48
|
+
output('')
|
49
|
+
print_profile_header(profile)
|
50
|
+
print_standard_control_results(profile)
|
51
|
+
print_anonymous_control_results(profile)
|
52
|
+
output(format_message(
|
53
|
+
indentation: 5,
|
54
|
+
message: 'No tests executed.',
|
55
|
+
)) if @control_count == 0
|
56
|
+
end
|
57
|
+
|
58
|
+
output('')
|
59
|
+
print_profile_summary
|
60
|
+
print_tests_summary
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def print_profile_header(profile)
|
66
|
+
output("Profile: #{format_profile_name(profile)}")
|
67
|
+
output("Version: #{profile[:version] || '(not specified)'}")
|
68
|
+
output("Target: #{run_data[:platform][:target]}") unless run_data[:platform][:target].nil?
|
69
|
+
output('')
|
70
|
+
end
|
71
|
+
|
72
|
+
def print_standard_control_results(profile)
|
73
|
+
standard_controls_from_profile(profile).each do |control_from_profile|
|
74
|
+
control = Control.new(control_from_profile)
|
75
|
+
next if control.results.nil?
|
76
|
+
output(format_control_header(control))
|
77
|
+
control.results.each do |result|
|
78
|
+
output(format_result(control, result, :standard))
|
79
|
+
@control_count += 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
output('') if @control_count > 0
|
83
|
+
end
|
84
|
+
|
85
|
+
def print_anonymous_control_results(profile)
|
86
|
+
anonymous_controls_from_profile(profile).each do |control_from_profile|
|
87
|
+
control = Control.new(control_from_profile)
|
88
|
+
next if control.results.nil?
|
89
|
+
output(format_control_header(control))
|
90
|
+
control.results.each do |result|
|
91
|
+
output(format_result(control, result, :anonymous))
|
92
|
+
@control_count += 1
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def format_profile_name(profile)
|
98
|
+
if profile[:title].nil?
|
99
|
+
(profile[:name] || 'unknown').to_s
|
100
|
+
else
|
101
|
+
"#{profile[:title]} (#{profile[:name] || 'unknown'})"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def format_control_header(control)
|
106
|
+
impact = control.impact_string
|
107
|
+
format_message(
|
108
|
+
color: impact,
|
109
|
+
indicator: impact,
|
110
|
+
message: control.title_for_report,
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
def format_result(control, result, type)
|
115
|
+
impact = control.impact_string_for_result(result)
|
116
|
+
|
117
|
+
message = if result[:status] == 'skipped'
|
118
|
+
result[:skip_message]
|
119
|
+
elsif type == :anonymous
|
120
|
+
result[:expectation_message]
|
121
|
+
else
|
122
|
+
result[:code_desc]
|
123
|
+
end
|
124
|
+
|
125
|
+
# append any failure details to the message if they exist
|
126
|
+
message += "\n#{result[:message]}" if result[:message]
|
127
|
+
|
128
|
+
format_message(
|
129
|
+
color: impact,
|
130
|
+
indicator: impact,
|
131
|
+
indentation: 5,
|
132
|
+
message: message,
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
def format_message(message_info)
|
137
|
+
indicator = message_info[:indicator]
|
138
|
+
color = message_info[:color]
|
139
|
+
indentation = message_info.fetch(:indentation, 2)
|
140
|
+
message = message_info[:message]
|
141
|
+
|
142
|
+
message_to_format = ''
|
143
|
+
message_to_format += "#{INDICATORS[indicator]} " unless indicator.nil?
|
144
|
+
message_to_format += message.to_s.lstrip
|
145
|
+
|
146
|
+
format_with_color(color, indent_lines(message_to_format, indentation))
|
147
|
+
end
|
148
|
+
|
149
|
+
def format_with_color(color_name, text)
|
150
|
+
return text if defined?(RSpec.configuration) && !RSpec.configuration.color
|
151
|
+
return text unless COLORS.key?(color_name)
|
152
|
+
|
153
|
+
"#{COLORS[color_name]}#{text}#{COLORS['reset']}"
|
154
|
+
end
|
155
|
+
|
156
|
+
def all_unique_controls
|
157
|
+
return @unique_controls unless @unique_controls.nil?
|
158
|
+
|
159
|
+
@unique_controls = Set.new
|
160
|
+
run_data[:profiles].each do |profile|
|
161
|
+
profile[:controls].map { |control| @unique_controls.add(control) }
|
162
|
+
end
|
163
|
+
|
164
|
+
@unique_controls
|
165
|
+
end
|
166
|
+
|
167
|
+
def profile_summary
|
168
|
+
failed = 0
|
169
|
+
skipped = 0
|
170
|
+
passed = 0
|
171
|
+
|
172
|
+
all_unique_controls.each do |control|
|
173
|
+
next if control[:id].start_with? '(generated from '
|
174
|
+
next unless control[:results]
|
175
|
+
if control[:results].any? { |r| r[:status] == 'failed' }
|
176
|
+
failed += 1
|
177
|
+
elsif control[:results].any? { |r| r[:status] == 'skipped' }
|
178
|
+
skipped += 1
|
179
|
+
else
|
180
|
+
passed += 1
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
total = failed + passed + skipped
|
185
|
+
|
186
|
+
{
|
187
|
+
'total' => total,
|
188
|
+
'failed' => failed,
|
189
|
+
'skipped' => skipped,
|
190
|
+
'passed' => passed,
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
def tests_summary
|
195
|
+
total = 0
|
196
|
+
failed = 0
|
197
|
+
skipped = 0
|
198
|
+
passed = 0
|
199
|
+
|
200
|
+
all_unique_controls.each do |control|
|
201
|
+
next unless control[:results]
|
202
|
+
control[:results].each do |result|
|
203
|
+
if result[:status] == 'failed'
|
204
|
+
failed += 1
|
205
|
+
elsif result[:status] == 'skipped'
|
206
|
+
skipped += 1
|
207
|
+
else
|
208
|
+
passed += 1
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
{
|
214
|
+
'total' => total,
|
215
|
+
'failed' => failed,
|
216
|
+
'skipped' => skipped,
|
217
|
+
'passed' => passed,
|
218
|
+
}
|
219
|
+
end
|
220
|
+
|
221
|
+
def print_profile_summary
|
222
|
+
summary = profile_summary
|
223
|
+
return unless summary['total'] > 0
|
224
|
+
|
225
|
+
success_str = summary['passed'] == 1 ? '1 successful control' : "#{summary['passed']} successful controls"
|
226
|
+
failed_str = summary['failed'] == 1 ? '1 control failure' : "#{summary['failed']} control failures"
|
227
|
+
skipped_str = summary['skipped'] == 1 ? '1 control skipped' : "#{summary['skipped']} controls skipped"
|
228
|
+
|
229
|
+
success_color = summary['passed'] > 0 ? 'passed' : 'no_color'
|
230
|
+
failed_color = summary['failed'] > 0 ? 'failed' : 'no_color'
|
231
|
+
skipped_color = summary['skipped'] > 0 ? 'skipped' : 'no_color'
|
232
|
+
|
233
|
+
s = format(
|
234
|
+
'Profile Summary: %s, %s, %s',
|
235
|
+
format_with_color(success_color, success_str),
|
236
|
+
format_with_color(failed_color, failed_str),
|
237
|
+
format_with_color(skipped_color, skipped_str),
|
238
|
+
)
|
239
|
+
output(s) if summary['total'] > 0
|
240
|
+
end
|
241
|
+
|
242
|
+
def print_tests_summary
|
243
|
+
summary = tests_summary
|
244
|
+
|
245
|
+
failed_str = summary['failed'] == 1 ? '1 failure' : "#{summary['failed']} failures"
|
246
|
+
|
247
|
+
success_color = summary['passed'] > 0 ? 'passed' : 'no_color'
|
248
|
+
failed_color = summary['failed'] > 0 ? 'failed' : 'no_color'
|
249
|
+
skipped_color = summary['skipped'] > 0 ? 'skipped' : 'no_color'
|
250
|
+
|
251
|
+
s = format(
|
252
|
+
'Test Summary: %s, %s, %s',
|
253
|
+
format_with_color(success_color, "#{summary['passed']} successful"),
|
254
|
+
format_with_color(failed_color, failed_str),
|
255
|
+
format_with_color(skipped_color, "#{summary['skipped']} skipped"),
|
256
|
+
)
|
257
|
+
|
258
|
+
output(s)
|
259
|
+
end
|
260
|
+
|
261
|
+
def standard_controls_from_profile(profile)
|
262
|
+
profile[:controls].reject { |c| is_anonymous_control?(c) }
|
263
|
+
end
|
264
|
+
|
265
|
+
def anonymous_controls_from_profile(profile)
|
266
|
+
profile[:controls].select { |c| is_anonymous_control?(c) && !c[:results].nil? }
|
267
|
+
end
|
268
|
+
|
269
|
+
def is_anonymous_control?(control)
|
270
|
+
control[:id].start_with?('(generated from ')
|
271
|
+
end
|
272
|
+
|
273
|
+
def indent_lines(message, indentation)
|
274
|
+
message.lines.map { |line| ' ' * indentation + line }.join
|
275
|
+
end
|
276
|
+
|
277
|
+
class Control
|
278
|
+
attr_reader :data
|
279
|
+
|
280
|
+
def initialize(control_hash)
|
281
|
+
@data = control_hash
|
282
|
+
end
|
283
|
+
|
284
|
+
def id
|
285
|
+
data[:id]
|
286
|
+
end
|
287
|
+
|
288
|
+
def title
|
289
|
+
data[:title]
|
290
|
+
end
|
291
|
+
|
292
|
+
def results
|
293
|
+
data[:results]
|
294
|
+
end
|
295
|
+
|
296
|
+
def impact
|
297
|
+
data[:impact]
|
298
|
+
end
|
299
|
+
|
300
|
+
def anonymous?
|
301
|
+
id.start_with?('(generated from ')
|
302
|
+
end
|
303
|
+
|
304
|
+
def title_for_report
|
305
|
+
# if this is an anonymous control, just grab the resource title from any result entry
|
306
|
+
return results.first[:resource_title] if anonymous?
|
307
|
+
|
308
|
+
title_for_report = "#{id}: #{title || results.first[:resource_title]}"
|
309
|
+
|
310
|
+
# we will not add any additional data to the title if there's only
|
311
|
+
# zero or one test for this control.
|
312
|
+
return title_for_report if results.nil? || results.size <= 1
|
313
|
+
|
314
|
+
# append a failure summary if appropriate.
|
315
|
+
title_for_report += " (#{failure_count} failed)" if failure_count > 0
|
316
|
+
title_for_report += " (#{skipped_count} skipped)" if skipped_count > 0
|
317
|
+
|
318
|
+
title_for_report
|
319
|
+
end
|
320
|
+
|
321
|
+
def impact_string
|
322
|
+
if anonymous?
|
323
|
+
nil
|
324
|
+
elsif impact.nil?
|
325
|
+
'unknown'
|
326
|
+
elsif results&.find { |r| r[:status] == 'skipped' }
|
327
|
+
'skipped'
|
328
|
+
elsif results.nil? || results.empty? || results.all? { |r| r[:status] == 'passed' }
|
329
|
+
'passed'
|
330
|
+
else
|
331
|
+
'failed'
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def impact_string_for_result(result)
|
336
|
+
if result[:status] == 'skipped'
|
337
|
+
'skipped'
|
338
|
+
elsif result[:status] == 'passed'
|
339
|
+
'passed'
|
340
|
+
elsif impact.nil?
|
341
|
+
'unknown'
|
342
|
+
else
|
343
|
+
'failed'
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def failure_count
|
348
|
+
results.select { |r| r[:status] == 'failed' }.size
|
349
|
+
end
|
350
|
+
|
351
|
+
def skipped_count
|
352
|
+
results.select { |r| r[:status] == 'skipped' }.size
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|