inspec 2.1.81 → 2.1.83
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 +5 -5
- data/.rubocop.yml +101 -101
- data/CHANGELOG.md +3183 -3177
- data/Gemfile +56 -56
- data/LICENSE +14 -14
- data/MAINTAINERS.md +33 -33
- data/MAINTAINERS.toml +52 -52
- data/README.md +453 -453
- data/Rakefile +349 -349
- data/bin/inspec +12 -12
- data/docs/.gitignore +2 -2
- data/docs/README.md +41 -40
- data/docs/dev/control-eval.md +61 -61
- data/docs/dsl_inspec.md +258 -258
- data/docs/dsl_resource.md +100 -100
- data/docs/glossary.md +99 -99
- data/docs/habitat.md +191 -191
- data/docs/inspec_and_friends.md +114 -114
- data/docs/matchers.md +169 -169
- data/docs/migration.md +293 -293
- data/docs/platforms.md +118 -118
- data/docs/plugin_kitchen_inspec.md +50 -50
- data/docs/profiles.md +378 -378
- data/docs/reporters.md +105 -105
- data/docs/resources/aide_conf.md.erb +75 -75
- data/docs/resources/apache.md.erb +67 -67
- data/docs/resources/apache_conf.md.erb +68 -68
- data/docs/resources/apt.md.erb +71 -71
- data/docs/resources/audit_policy.md.erb +47 -47
- data/docs/resources/auditd.md.erb +79 -79
- data/docs/resources/auditd_conf.md.erb +68 -68
- data/docs/resources/aws_cloudtrail_trail.md.erb +155 -155
- data/docs/resources/aws_cloudtrail_trails.md.erb +86 -86
- data/docs/resources/aws_cloudwatch_alarm.md.erb +91 -91
- data/docs/resources/aws_cloudwatch_log_metric_filter.md.erb +154 -154
- data/docs/resources/aws_config_delivery_channel.md.erb +101 -101
- data/docs/resources/aws_config_recorder.md.erb +86 -86
- data/docs/resources/aws_ec2_instance.md.erb +112 -112
- data/docs/resources/aws_ec2_instances.md.erb +79 -79
- data/docs/resources/aws_iam_access_key.md.erb +129 -129
- data/docs/resources/aws_iam_access_keys.md.erb +204 -204
- data/docs/resources/aws_iam_group.md.erb +64 -64
- data/docs/resources/aws_iam_groups.md.erb +49 -49
- data/docs/resources/aws_iam_password_policy.md.erb +82 -82
- data/docs/resources/aws_iam_policies.md.erb +87 -87
- data/docs/resources/aws_iam_policy.md.erb +245 -245
- data/docs/resources/aws_iam_role.md.erb +69 -69
- data/docs/resources/aws_iam_root_user.md.erb +76 -76
- data/docs/resources/aws_iam_user.md.erb +120 -120
- data/docs/resources/aws_iam_users.md.erb +279 -279
- data/docs/resources/aws_kms_key.md.erb +177 -177
- data/docs/resources/aws_kms_keys.md.erb +89 -89
- data/docs/resources/aws_rds_instance.md.erb +66 -66
- data/docs/resources/aws_route_table.md.erb +53 -53
- data/docs/resources/aws_route_tables.md.erb +55 -55
- data/docs/resources/aws_s3_bucket.md.erb +146 -146
- data/docs/resources/aws_s3_bucket_object.md.erb +89 -89
- data/docs/resources/aws_s3_buckets.md.erb +59 -59
- data/docs/resources/aws_security_group.md.erb +296 -296
- data/docs/resources/aws_security_groups.md.erb +97 -97
- data/docs/resources/aws_sns_subscription.md.erb +130 -130
- data/docs/resources/aws_sns_topic.md.erb +69 -69
- data/docs/resources/aws_sns_topics.md.erb +58 -58
- data/docs/resources/aws_subnet.md.erb +140 -140
- data/docs/resources/aws_subnets.md.erb +132 -132
- data/docs/resources/aws_vpc.md.erb +125 -125
- data/docs/resources/aws_vpcs.md.erb +125 -125
- data/docs/resources/azure_generic_resource.md.erb +171 -171
- data/docs/resources/azure_resource_group.md.erb +284 -284
- data/docs/resources/azure_virtual_machine.md.erb +347 -347
- data/docs/resources/azure_virtual_machine_data_disk.md.erb +224 -224
- data/docs/resources/bash.md.erb +75 -75
- data/docs/resources/bond.md.erb +90 -90
- data/docs/resources/bridge.md.erb +57 -57
- data/docs/resources/bsd_service.md.erb +67 -67
- data/docs/resources/chocolatey_package.md.erb +58 -58
- data/docs/resources/command.md.erb +138 -138
- data/docs/resources/cpan.md.erb +79 -79
- data/docs/resources/cran.md.erb +64 -64
- data/docs/resources/crontab.md.erb +89 -89
- data/docs/resources/csv.md.erb +54 -54
- data/docs/resources/dh_params.md.erb +205 -205
- data/docs/resources/directory.md.erb +30 -30
- data/docs/resources/docker.md.erb +219 -219
- data/docs/resources/docker_container.md.erb +103 -103
- data/docs/resources/docker_image.md.erb +94 -94
- data/docs/resources/docker_service.md.erb +114 -114
- data/docs/resources/elasticsearch.md.erb +242 -242
- data/docs/resources/etc_fstab.md.erb +125 -125
- data/docs/resources/etc_group.md.erb +75 -75
- data/docs/resources/etc_hosts.md.erb +78 -78
- data/docs/resources/etc_hosts_allow.md.erb +74 -74
- data/docs/resources/etc_hosts_deny.md.erb +74 -74
- data/docs/resources/file.md.erb +526 -526
- data/docs/resources/filesystem.md.erb +41 -41
- data/docs/resources/firewalld.md.erb +107 -107
- data/docs/resources/gem.md.erb +79 -79
- data/docs/resources/group.md.erb +61 -61
- data/docs/resources/grub_conf.md.erb +101 -101
- data/docs/resources/host.md.erb +86 -86
- data/docs/resources/http.md.erb +197 -197
- data/docs/resources/iis_app.md.erb +122 -122
- data/docs/resources/iis_site.md.erb +135 -135
- data/docs/resources/inetd_conf.md.erb +94 -94
- data/docs/resources/ini.md.erb +76 -76
- data/docs/resources/interface.md.erb +58 -58
- data/docs/resources/iptables.md.erb +64 -64
- data/docs/resources/json.md.erb +63 -63
- data/docs/resources/kernel_module.md.erb +120 -120
- data/docs/resources/kernel_parameter.md.erb +53 -53
- data/docs/resources/key_rsa.md.erb +85 -85
- data/docs/resources/launchd_service.md.erb +57 -57
- data/docs/resources/limits_conf.md.erb +75 -75
- data/docs/resources/login_defs.md.erb +71 -71
- data/docs/resources/mount.md.erb +69 -69
- data/docs/resources/mssql_session.md.erb +60 -60
- data/docs/resources/mysql_conf.md.erb +99 -99
- data/docs/resources/mysql_session.md.erb +74 -74
- data/docs/resources/nginx.md.erb +79 -79
- data/docs/resources/nginx_conf.md.erb +138 -138
- data/docs/resources/npm.md.erb +60 -60
- data/docs/resources/ntp_conf.md.erb +60 -60
- data/docs/resources/oneget.md.erb +53 -53
- data/docs/resources/oracledb_session.md.erb +52 -52
- data/docs/resources/os.md.erb +141 -141
- data/docs/resources/os_env.md.erb +91 -91
- data/docs/resources/package.md.erb +120 -120
- data/docs/resources/packages.md.erb +67 -67
- data/docs/resources/parse_config.md.erb +103 -103
- data/docs/resources/parse_config_file.md.erb +138 -138
- data/docs/resources/passwd.md.erb +141 -141
- data/docs/resources/pip.md.erb +67 -67
- data/docs/resources/port.md.erb +137 -137
- data/docs/resources/postgres_conf.md.erb +79 -79
- data/docs/resources/postgres_hba_conf.md.erb +93 -93
- data/docs/resources/postgres_ident_conf.md.erb +76 -76
- data/docs/resources/postgres_session.md.erb +69 -69
- data/docs/resources/powershell.md.erb +102 -102
- data/docs/resources/processes.md.erb +109 -109
- data/docs/resources/rabbitmq_config.md.erb +41 -41
- data/docs/resources/registry_key.md.erb +158 -158
- data/docs/resources/runit_service.md.erb +57 -57
- data/docs/resources/security_policy.md.erb +47 -47
- data/docs/resources/service.md.erb +121 -121
- data/docs/resources/shadow.md.erb +146 -146
- data/docs/resources/ssh_config.md.erb +73 -73
- data/docs/resources/sshd_config.md.erb +83 -83
- data/docs/resources/ssl.md.erb +119 -119
- data/docs/resources/sys_info.md.erb +42 -42
- data/docs/resources/systemd_service.md.erb +57 -57
- data/docs/resources/sysv_service.md.erb +57 -57
- data/docs/resources/upstart_service.md.erb +57 -57
- data/docs/resources/user.md.erb +140 -140
- data/docs/resources/users.md.erb +127 -127
- data/docs/resources/vbscript.md.erb +55 -55
- data/docs/resources/virtualization.md.erb +57 -57
- data/docs/resources/windows_feature.md.erb +47 -47
- data/docs/resources/windows_hotfix.md.erb +53 -53
- data/docs/resources/windows_task.md.erb +95 -95
- data/docs/resources/wmi.md.erb +81 -81
- data/docs/resources/x509_certificate.md.erb +151 -151
- data/docs/resources/xinetd_conf.md.erb +156 -156
- data/docs/resources/xml.md.erb +85 -85
- data/docs/resources/yaml.md.erb +69 -69
- data/docs/resources/yum.md.erb +98 -98
- data/docs/resources/zfs_dataset.md.erb +53 -53
- data/docs/resources/zfs_pool.md.erb +47 -47
- data/docs/ruby_usage.md +203 -203
- data/docs/shared/matcher_be.md.erb +1 -1
- data/docs/shared/matcher_cmp.md.erb +43 -43
- data/docs/shared/matcher_eq.md.erb +3 -3
- data/docs/shared/matcher_include.md.erb +1 -1
- data/docs/shared/matcher_match.md.erb +1 -1
- data/docs/shell.md +217 -217
- data/examples/README.md +8 -8
- data/examples/inheritance/README.md +65 -65
- data/examples/inheritance/controls/example.rb +14 -14
- data/examples/inheritance/inspec.yml +15 -15
- data/examples/kitchen-ansible/.kitchen.yml +25 -25
- data/examples/kitchen-ansible/Gemfile +19 -19
- data/examples/kitchen-ansible/README.md +53 -53
- data/examples/kitchen-ansible/files/nginx.repo +6 -6
- data/examples/kitchen-ansible/tasks/main.yml +16 -16
- data/examples/kitchen-ansible/test/integration/default/default.yml +5 -5
- data/examples/kitchen-ansible/test/integration/default/web_spec.rb +28 -28
- data/examples/kitchen-chef/.kitchen.yml +20 -20
- data/examples/kitchen-chef/Berksfile +3 -3
- data/examples/kitchen-chef/Gemfile +19 -19
- data/examples/kitchen-chef/README.md +27 -27
- data/examples/kitchen-chef/metadata.rb +7 -7
- data/examples/kitchen-chef/recipes/default.rb +6 -6
- data/examples/kitchen-chef/recipes/nginx.rb +30 -30
- data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -28
- data/examples/kitchen-puppet/.kitchen.yml +23 -23
- data/examples/kitchen-puppet/Gemfile +20 -20
- data/examples/kitchen-puppet/Puppetfile +25 -25
- data/examples/kitchen-puppet/README.md +53 -53
- data/examples/kitchen-puppet/manifests/site.pp +33 -33
- data/examples/kitchen-puppet/metadata.json +11 -11
- data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -28
- data/examples/meta-profile/README.md +37 -37
- data/examples/meta-profile/controls/example.rb +13 -13
- data/examples/meta-profile/inspec.yml +13 -13
- data/examples/profile-attribute.yml +2 -2
- data/examples/profile-attribute/README.md +14 -14
- data/examples/profile-attribute/controls/example.rb +11 -11
- data/examples/profile-attribute/inspec.yml +8 -8
- data/examples/profile-aws/controls/iam_password_policy_expiration.rb +8 -8
- data/examples/profile-aws/controls/iam_password_policy_max_age.rb +8 -8
- data/examples/profile-aws/controls/iam_root_user_mfa.rb +8 -8
- data/examples/profile-aws/controls/iam_users_access_key_age.rb +8 -8
- data/examples/profile-aws/controls/iam_users_console_users_mfa.rb +8 -8
- data/examples/profile-aws/inspec.yml +11 -11
- data/examples/profile-azure/controls/azure_resource_group_example.rb +24 -24
- data/examples/profile-azure/controls/azure_vm_example.rb +29 -29
- data/examples/profile-azure/inspec.yml +11 -11
- data/examples/profile-sensitive/README.md +29 -29
- data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -9
- data/examples/profile-sensitive/controls/sensitive.rb +9 -9
- data/examples/profile-sensitive/inspec.yml +8 -8
- data/examples/profile/README.md +48 -48
- data/examples/profile/controls/example.rb +23 -23
- data/examples/profile/controls/gordon.rb +36 -36
- data/examples/profile/controls/meta.rb +34 -34
- data/examples/profile/inspec.yml +10 -10
- data/examples/profile/libraries/gordon_config.rb +59 -59
- data/inspec.gemspec +49 -49
- data/lib/bundles/README.md +3 -3
- data/lib/bundles/inspec-artifact.rb +7 -7
- data/lib/bundles/inspec-artifact/README.md +1 -1
- data/lib/bundles/inspec-artifact/cli.rb +277 -277
- data/lib/bundles/inspec-compliance.rb +16 -16
- data/lib/bundles/inspec-compliance/.kitchen.yml +20 -20
- data/lib/bundles/inspec-compliance/README.md +193 -193
- data/lib/bundles/inspec-compliance/api.rb +360 -360
- data/lib/bundles/inspec-compliance/api/login.rb +193 -193
- data/lib/bundles/inspec-compliance/bootstrap.sh +41 -41
- data/lib/bundles/inspec-compliance/cli.rb +260 -260
- data/lib/bundles/inspec-compliance/configuration.rb +103 -103
- data/lib/bundles/inspec-compliance/http.rb +125 -125
- data/lib/bundles/inspec-compliance/support.rb +36 -36
- data/lib/bundles/inspec-compliance/target.rb +112 -112
- data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +93 -93
- data/lib/bundles/inspec-habitat.rb +12 -12
- data/lib/bundles/inspec-habitat/cli.rb +36 -36
- data/lib/bundles/inspec-habitat/log.rb +10 -10
- data/lib/bundles/inspec-habitat/profile.rb +391 -391
- data/lib/bundles/inspec-init.rb +8 -8
- data/lib/bundles/inspec-init/README.md +31 -31
- data/lib/bundles/inspec-init/cli.rb +97 -97
- data/lib/bundles/inspec-init/templates/profile/README.md +3 -3
- data/lib/bundles/inspec-init/templates/profile/controls/example.rb +19 -19
- data/lib/bundles/inspec-init/templates/profile/inspec.yml +8 -8
- data/lib/bundles/inspec-supermarket.rb +13 -13
- data/lib/bundles/inspec-supermarket/README.md +45 -45
- data/lib/bundles/inspec-supermarket/api.rb +84 -84
- data/lib/bundles/inspec-supermarket/cli.rb +73 -73
- data/lib/bundles/inspec-supermarket/target.rb +34 -34
- data/lib/fetchers/git.rb +163 -163
- data/lib/fetchers/local.rb +74 -74
- data/lib/fetchers/mock.rb +35 -35
- data/lib/fetchers/url.rb +247 -247
- data/lib/inspec.rb +24 -24
- data/lib/inspec/archive/tar.rb +29 -29
- data/lib/inspec/archive/zip.rb +19 -19
- data/lib/inspec/backend.rb +93 -93
- data/lib/inspec/base_cli.rb +368 -368
- data/lib/inspec/cached_fetcher.rb +66 -66
- data/lib/inspec/cli.rb +292 -292
- data/lib/inspec/completions/bash.sh.erb +45 -45
- data/lib/inspec/completions/fish.sh.erb +34 -34
- data/lib/inspec/completions/zsh.sh.erb +61 -61
- data/lib/inspec/control_eval_context.rb +179 -179
- data/lib/inspec/dependencies/cache.rb +72 -72
- data/lib/inspec/dependencies/dependency_set.rb +92 -92
- data/lib/inspec/dependencies/lockfile.rb +115 -115
- data/lib/inspec/dependencies/requirement.rb +123 -123
- data/lib/inspec/dependencies/resolver.rb +86 -86
- data/lib/inspec/describe.rb +27 -27
- data/lib/inspec/dsl.rb +66 -66
- data/lib/inspec/dsl_shared.rb +33 -33
- data/lib/inspec/env_printer.rb +157 -157
- data/lib/inspec/errors.rb +14 -14
- data/lib/inspec/exceptions.rb +12 -12
- data/lib/inspec/expect.rb +45 -45
- data/lib/inspec/fetcher.rb +45 -45
- data/lib/inspec/file_provider.rb +275 -275
- data/lib/inspec/formatters.rb +3 -3
- data/lib/inspec/formatters/base.rb +259 -259
- data/lib/inspec/formatters/json_rspec.rb +20 -20
- data/lib/inspec/formatters/show_progress.rb +12 -12
- data/lib/inspec/library_eval_context.rb +58 -58
- data/lib/inspec/log.rb +11 -11
- data/lib/inspec/metadata.rb +247 -247
- data/lib/inspec/method_source.rb +24 -24
- data/lib/inspec/objects.rb +14 -14
- data/lib/inspec/objects/attribute.rb +75 -75
- data/lib/inspec/objects/control.rb +61 -61
- data/lib/inspec/objects/describe.rb +92 -92
- data/lib/inspec/objects/each_loop.rb +36 -36
- data/lib/inspec/objects/list.rb +15 -15
- data/lib/inspec/objects/or_test.rb +40 -40
- data/lib/inspec/objects/ruby_helper.rb +15 -15
- data/lib/inspec/objects/tag.rb +27 -27
- data/lib/inspec/objects/test.rb +87 -87
- data/lib/inspec/objects/value.rb +27 -27
- data/lib/inspec/plugins.rb +60 -60
- data/lib/inspec/plugins/cli.rb +24 -24
- data/lib/inspec/plugins/fetcher.rb +86 -86
- data/lib/inspec/plugins/resource.rb +135 -135
- data/lib/inspec/plugins/secret.rb +15 -15
- data/lib/inspec/plugins/source_reader.rb +40 -40
- data/lib/inspec/polyfill.rb +12 -12
- data/lib/inspec/profile.rb +513 -513
- data/lib/inspec/profile_context.rb +208 -208
- data/lib/inspec/profile_vendor.rb +66 -66
- data/lib/inspec/reporters.rb +60 -60
- data/lib/inspec/reporters/automate.rb +76 -76
- data/lib/inspec/reporters/base.rb +25 -25
- data/lib/inspec/reporters/cli.rb +356 -356
- data/lib/inspec/reporters/json.rb +117 -117
- data/lib/inspec/reporters/json_min.rb +48 -48
- data/lib/inspec/reporters/junit.rb +78 -78
- data/lib/inspec/require_loader.rb +33 -33
- data/lib/inspec/resource.rb +190 -190
- data/lib/inspec/rule.rb +280 -280
- data/lib/inspec/runner.rb +345 -345
- data/lib/inspec/runner_mock.rb +41 -41
- data/lib/inspec/runner_rspec.rb +175 -175
- data/lib/inspec/runtime_profile.rb +26 -26
- data/lib/inspec/schema.rb +213 -213
- data/lib/inspec/secrets.rb +19 -19
- data/lib/inspec/secrets/yaml.rb +30 -30
- data/lib/inspec/shell.rb +220 -220
- data/lib/inspec/shell_detector.rb +90 -90
- data/lib/inspec/source_reader.rb +29 -29
- data/lib/inspec/version.rb +8 -8
- data/lib/matchers/matchers.rb +339 -339
- data/lib/resource_support/aws.rb +50 -50
- data/lib/resource_support/aws/aws_backend_base.rb +12 -12
- data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -12
- data/lib/resource_support/aws/aws_plural_resource_mixin.rb +21 -21
- data/lib/resource_support/aws/aws_resource_mixin.rb +66 -66
- data/lib/resource_support/aws/aws_singular_resource_mixin.rb +24 -24
- data/lib/resources/aide_conf.rb +151 -151
- data/lib/resources/apache.rb +48 -48
- data/lib/resources/apache_conf.rb +149 -149
- data/lib/resources/apt.rb +149 -149
- data/lib/resources/audit_policy.rb +63 -63
- data/lib/resources/auditd.rb +231 -231
- data/lib/resources/auditd_conf.rb +46 -46
- data/lib/resources/aws/aws_cloudtrail_trail.rb +93 -93
- data/lib/resources/aws/aws_cloudtrail_trails.rb +47 -47
- data/lib/resources/aws/aws_cloudwatch_alarm.rb +62 -62
- data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +100 -100
- data/lib/resources/aws/aws_config_delivery_channel.rb +70 -70
- data/lib/resources/aws/aws_config_recorder.rb +93 -93
- data/lib/resources/aws/aws_ec2_instance.rb +157 -157
- data/lib/resources/aws/aws_ec2_instances.rb +64 -64
- data/lib/resources/aws/aws_iam_access_key.rb +106 -106
- data/lib/resources/aws/aws_iam_access_keys.rb +149 -149
- data/lib/resources/aws/aws_iam_group.rb +58 -58
- data/lib/resources/aws/aws_iam_groups.rb +52 -52
- data/lib/resources/aws/aws_iam_password_policy.rb +116 -116
- data/lib/resources/aws/aws_iam_policies.rb +53 -53
- data/lib/resources/aws/aws_iam_policy.rb +291 -291
- data/lib/resources/aws/aws_iam_role.rb +55 -55
- data/lib/resources/aws/aws_iam_root_user.rb +78 -78
- data/lib/resources/aws/aws_iam_user.rb +142 -142
- data/lib/resources/aws/aws_iam_users.rb +146 -146
- data/lib/resources/aws/aws_kms_key.rb +96 -96
- data/lib/resources/aws/aws_kms_keys.rb +53 -53
- data/lib/resources/aws/aws_rds_instance.rb +71 -71
- data/lib/resources/aws/aws_route_table.rb +63 -63
- data/lib/resources/aws/aws_route_tables.rb +60 -60
- data/lib/resources/aws/aws_s3_bucket.rb +137 -137
- data/lib/resources/aws/aws_s3_bucket_object.rb +82 -82
- data/lib/resources/aws/aws_s3_buckets.rb +51 -51
- data/lib/resources/aws/aws_security_group.rb +249 -249
- data/lib/resources/aws/aws_security_groups.rb +68 -68
- data/lib/resources/aws/aws_sns_subscription.rb +78 -78
- data/lib/resources/aws/aws_sns_topic.rb +53 -53
- data/lib/resources/aws/aws_sns_topics.rb +56 -56
- data/lib/resources/aws/aws_subnet.rb +88 -88
- data/lib/resources/aws/aws_subnets.rb +53 -53
- data/lib/resources/aws/aws_vpc.rb +73 -73
- data/lib/resources/aws/aws_vpcs.rb +52 -52
- data/lib/resources/azure/azure_backend.rb +377 -377
- data/lib/resources/azure/azure_generic_resource.rb +59 -59
- data/lib/resources/azure/azure_resource_group.rb +152 -152
- data/lib/resources/azure/azure_virtual_machine.rb +264 -264
- data/lib/resources/azure/azure_virtual_machine_data_disk.rb +134 -134
- data/lib/resources/bash.rb +35 -35
- data/lib/resources/bond.rb +69 -69
- data/lib/resources/bridge.rb +122 -122
- data/lib/resources/chocolatey_package.rb +78 -78
- data/lib/resources/command.rb +73 -73
- data/lib/resources/cpan.rb +58 -58
- data/lib/resources/cran.rb +64 -64
- data/lib/resources/crontab.rb +169 -169
- data/lib/resources/csv.rb +56 -56
- data/lib/resources/dh_params.rb +77 -77
- data/lib/resources/directory.rb +25 -25
- data/lib/resources/docker.rb +236 -236
- data/lib/resources/docker_container.rb +89 -89
- data/lib/resources/docker_image.rb +83 -83
- data/lib/resources/docker_object.rb +57 -57
- data/lib/resources/docker_service.rb +90 -90
- data/lib/resources/elasticsearch.rb +169 -169
- data/lib/resources/etc_fstab.rb +94 -94
- data/lib/resources/etc_group.rb +154 -154
- data/lib/resources/etc_hosts.rb +66 -66
- data/lib/resources/etc_hosts_allow_deny.rb +112 -112
- data/lib/resources/file.rb +298 -298
- data/lib/resources/filesystem.rb +31 -31
- data/lib/resources/firewalld.rb +143 -143
- data/lib/resources/gem.rb +70 -70
- data/lib/resources/groups.rb +215 -215
- data/lib/resources/grub_conf.rb +227 -227
- data/lib/resources/host.rb +306 -306
- data/lib/resources/http.rb +253 -253
- data/lib/resources/iis_app.rb +101 -101
- data/lib/resources/iis_site.rb +148 -148
- data/lib/resources/inetd_conf.rb +54 -54
- data/lib/resources/ini.rb +29 -29
- data/lib/resources/interface.rb +129 -129
- data/lib/resources/iptables.rb +80 -80
- data/lib/resources/json.rb +111 -111
- data/lib/resources/kernel_module.rb +107 -107
- data/lib/resources/kernel_parameter.rb +58 -58
- data/lib/resources/key_rsa.rb +63 -63
- data/lib/resources/limits_conf.rb +46 -46
- data/lib/resources/login_def.rb +57 -57
- data/lib/resources/mount.rb +88 -88
- data/lib/resources/mssql_session.rb +101 -101
- data/lib/resources/mysql.rb +82 -82
- data/lib/resources/mysql_conf.rb +127 -127
- data/lib/resources/mysql_session.rb +85 -85
- data/lib/resources/nginx.rb +96 -96
- data/lib/resources/nginx_conf.rb +226 -226
- data/lib/resources/npm.rb +48 -48
- data/lib/resources/ntp_conf.rb +51 -51
- data/lib/resources/oneget.rb +71 -71
- data/lib/resources/oracledb_session.rb +139 -139
- data/lib/resources/os.rb +36 -36
- data/lib/resources/os_env.rb +86 -86
- data/lib/resources/package.rb +370 -370
- data/lib/resources/packages.rb +111 -111
- data/lib/resources/parse_config.rb +112 -112
- data/lib/resources/passwd.rb +76 -76
- data/lib/resources/pip.rb +130 -130
- data/lib/resources/platform.rb +109 -109
- data/lib/resources/port.rb +771 -771
- data/lib/resources/postgres.rb +131 -131
- data/lib/resources/postgres_conf.rb +114 -114
- data/lib/resources/postgres_hba_conf.rb +90 -90
- data/lib/resources/postgres_ident_conf.rb +79 -79
- data/lib/resources/postgres_session.rb +71 -71
- data/lib/resources/powershell.rb +67 -67
- data/lib/resources/processes.rb +204 -204
- data/lib/resources/rabbitmq_conf.rb +51 -51
- data/lib/resources/registry_key.rb +297 -297
- data/lib/resources/security_policy.rb +180 -180
- data/lib/resources/service.rb +794 -794
- data/lib/resources/shadow.rb +159 -159
- data/lib/resources/ssh_conf.rb +97 -97
- data/lib/resources/ssl.rb +99 -99
- data/lib/resources/sys_info.rb +28 -28
- data/lib/resources/toml.rb +32 -32
- data/lib/resources/users.rb +654 -654
- data/lib/resources/vbscript.rb +68 -68
- data/lib/resources/virtualization.rb +247 -247
- data/lib/resources/windows_feature.rb +84 -84
- data/lib/resources/windows_hotfix.rb +35 -35
- data/lib/resources/windows_task.rb +102 -102
- data/lib/resources/wmi.rb +110 -110
- data/lib/resources/x509_certificate.rb +137 -137
- data/lib/resources/xinetd.rb +106 -106
- data/lib/resources/xml.rb +46 -46
- data/lib/resources/yaml.rb +43 -43
- data/lib/resources/yum.rb +180 -180
- data/lib/resources/zfs_dataset.rb +60 -60
- data/lib/resources/zfs_pool.rb +49 -49
- data/lib/source_readers/flat.rb +39 -39
- data/lib/source_readers/inspec.rb +75 -75
- data/lib/utils/command_wrapper.rb +27 -27
- data/lib/utils/convert.rb +12 -12
- data/lib/utils/database_helpers.rb +77 -77
- data/lib/utils/enumerable_delegation.rb +9 -9
- data/lib/utils/erlang_parser.rb +192 -192
- data/lib/utils/file_reader.rb +25 -25
- data/lib/utils/filter.rb +273 -273
- data/lib/utils/filter_array.rb +27 -27
- data/lib/utils/find_files.rb +47 -47
- data/lib/utils/hash.rb +41 -41
- data/lib/utils/json_log.rb +18 -18
- data/lib/utils/latest_version.rb +22 -22
- data/lib/utils/modulator.rb +12 -12
- data/lib/utils/nginx_parser.rb +105 -105
- data/lib/utils/object_traversal.rb +49 -49
- data/lib/utils/parser.rb +274 -274
- data/lib/utils/pkey_reader.rb +15 -15
- data/lib/utils/plugin_registry.rb +93 -93
- data/lib/utils/simpleconfig.rb +120 -120
- data/lib/utils/spdx.rb +13 -13
- data/lib/utils/spdx.txt +343 -343
- metadata +3 -3
data/lib/inspec/reporters.rb
CHANGED
|
@@ -1,60 +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
|
|
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
|
|
@@ -1,76 +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] = @config['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 job_uuid}.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
|
|
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] = @config['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 job_uuid}.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
|
|
@@ -1,25 +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
|
|
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
|
data/lib/inspec/reporters/cli.rb
CHANGED
|
@@ -1,356 +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
|
|
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
|