inspec 2.1.0 → 2.1.10

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