inspec 2.0.32 → 2.0.45

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 (482) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +101 -101
  3. data/CHANGELOG.md +2991 -2970
  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 +446 -437
  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 +93 -93
  15. data/docs/glossary.md +99 -99
  16. data/docs/habitat.md +191 -191
  17. data/docs/inspec_and_friends.md +107 -107
  18. data/docs/matchers.md +169 -168
  19. data/docs/migration.md +293 -293
  20. data/docs/platforms.md +118 -118
  21. data/docs/plugin_kitchen_inspec.md +49 -49
  22. data/docs/profiles.md +370 -370
  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_security_group.md.erb +151 -151
  52. data/docs/resources/aws_security_groups.md.erb +91 -91
  53. data/docs/resources/aws_sns_topic.md.erb +63 -63
  54. data/docs/resources/aws_subnet.md.erb +133 -133
  55. data/docs/resources/aws_subnets.md.erb +126 -126
  56. data/docs/resources/aws_vpc.md.erb +120 -120
  57. data/docs/resources/aws_vpcs.md.erb +48 -48
  58. data/docs/resources/azure_generic_resource.md.erb +170 -170
  59. data/docs/resources/azure_resource_group.md.erb +284 -284
  60. data/docs/resources/azure_virtual_machine.md.erb +347 -347
  61. data/docs/resources/azure_virtual_machine_data_disk.md.erb +224 -224
  62. data/docs/resources/bash.md.erb +75 -75
  63. data/docs/resources/bond.md.erb +90 -90
  64. data/docs/resources/bridge.md.erb +57 -57
  65. data/docs/resources/bsd_service.md.erb +67 -67
  66. data/docs/resources/command.md.erb +138 -138
  67. data/docs/resources/cpan.md.erb +79 -79
  68. data/docs/resources/cran.md.erb +64 -64
  69. data/docs/resources/crontab.md.erb +89 -89
  70. data/docs/resources/csv.md.erb +54 -54
  71. data/docs/resources/dh_params.md.erb +205 -205
  72. data/docs/resources/directory.md.erb +30 -30
  73. data/docs/resources/docker.md.erb +219 -219
  74. data/docs/resources/docker_container.md.erb +104 -104
  75. data/docs/resources/docker_image.md.erb +94 -94
  76. data/docs/resources/docker_service.md.erb +114 -114
  77. data/docs/resources/elasticsearch.md.erb +242 -242
  78. data/docs/resources/etc_fstab.md.erb +125 -125
  79. data/docs/resources/etc_group.md.erb +75 -75
  80. data/docs/resources/etc_hosts.md.erb +78 -78
  81. data/docs/resources/etc_hosts_allow.md.erb +74 -74
  82. data/docs/resources/etc_hosts_deny.md.erb +74 -74
  83. data/docs/resources/file.md.erb +526 -515
  84. data/docs/resources/filesystem.md.erb +41 -41
  85. data/docs/resources/firewalld.md.erb +107 -107
  86. data/docs/resources/gem.md.erb +79 -79
  87. data/docs/resources/group.md.erb +61 -61
  88. data/docs/resources/grub_conf.md.erb +101 -101
  89. data/docs/resources/host.md.erb +86 -86
  90. data/docs/resources/http.md.erb +196 -196
  91. data/docs/resources/iis_app.md.erb +122 -122
  92. data/docs/resources/iis_site.md.erb +135 -135
  93. data/docs/resources/inetd_conf.md.erb +94 -94
  94. data/docs/resources/ini.md.erb +76 -76
  95. data/docs/resources/interface.md.erb +58 -58
  96. data/docs/resources/iptables.md.erb +64 -64
  97. data/docs/resources/json.md.erb +63 -63
  98. data/docs/resources/kernel_module.md.erb +120 -120
  99. data/docs/resources/kernel_parameter.md.erb +53 -53
  100. data/docs/resources/key_rsa.md.erb +85 -85
  101. data/docs/resources/launchd_service.md.erb +57 -57
  102. data/docs/resources/limits_conf.md.erb +75 -75
  103. data/docs/resources/login_def.md.erb +71 -71
  104. data/docs/resources/mount.md.erb +69 -69
  105. data/docs/resources/mssql_session.md.erb +60 -60
  106. data/docs/resources/mysql_conf.md.erb +99 -99
  107. data/docs/resources/mysql_session.md.erb +74 -74
  108. data/docs/resources/nginx.md.erb +79 -79
  109. data/docs/resources/nginx_conf.md.erb +128 -128
  110. data/docs/resources/npm.md.erb +60 -60
  111. data/docs/resources/ntp_conf.md.erb +60 -60
  112. data/docs/resources/oneget.md.erb +53 -53
  113. data/docs/resources/oracledb_session.md.erb +52 -52
  114. data/docs/resources/os.md.erb +141 -141
  115. data/docs/resources/os_env.md.erb +78 -78
  116. data/docs/resources/package.md.erb +120 -120
  117. data/docs/resources/packages.md.erb +67 -67
  118. data/docs/resources/parse_config.md.erb +103 -103
  119. data/docs/resources/parse_config_file.md.erb +138 -138
  120. data/docs/resources/passwd.md.erb +141 -141
  121. data/docs/resources/pip.md.erb +67 -67
  122. data/docs/resources/port.md.erb +137 -137
  123. data/docs/resources/postgres_conf.md.erb +79 -79
  124. data/docs/resources/postgres_hba_conf.md.erb +93 -93
  125. data/docs/resources/postgres_ident_conf.md.erb +76 -76
  126. data/docs/resources/postgres_session.md.erb +69 -69
  127. data/docs/resources/powershell.md.erb +102 -102
  128. data/docs/resources/processes.md.erb +109 -109
  129. data/docs/resources/rabbitmq_config.md.erb +41 -41
  130. data/docs/resources/registry_key.md.erb +158 -158
  131. data/docs/resources/runit_service.md.erb +57 -57
  132. data/docs/resources/security_policy.md.erb +47 -47
  133. data/docs/resources/service.md.erb +121 -121
  134. data/docs/resources/shadow.md.erb +146 -144
  135. data/docs/resources/ssh_config.md.erb +80 -80
  136. data/docs/resources/sshd_config.md.erb +83 -83
  137. data/docs/resources/ssl.md.erb +119 -119
  138. data/docs/resources/sys_info.md.erb +42 -42
  139. data/docs/resources/systemd_service.md.erb +57 -57
  140. data/docs/resources/sysv_service.md.erb +57 -57
  141. data/docs/resources/upstart_service.md.erb +57 -57
  142. data/docs/resources/user.md.erb +140 -140
  143. data/docs/resources/users.md.erb +127 -127
  144. data/docs/resources/vbscript.md.erb +55 -55
  145. data/docs/resources/virtualization.md.erb +57 -57
  146. data/docs/resources/windows_feature.md.erb +47 -47
  147. data/docs/resources/windows_hotfix.md.erb +53 -53
  148. data/docs/resources/windows_task.md.erb +95 -95
  149. data/docs/resources/wmi.md.erb +81 -81
  150. data/docs/resources/x509_certificate.md.erb +151 -151
  151. data/docs/resources/xinetd_conf.md.erb +156 -156
  152. data/docs/resources/xml.md.erb +85 -85
  153. data/docs/resources/yaml.md.erb +69 -69
  154. data/docs/resources/yum.md.erb +98 -98
  155. data/docs/resources/zfs_dataset.md.erb +53 -53
  156. data/docs/resources/zfs_pool.md.erb +47 -47
  157. data/docs/ruby_usage.md +203 -203
  158. data/docs/shared/matcher_be.md.erb +1 -1
  159. data/docs/shared/matcher_cmp.md.erb +43 -43
  160. data/docs/shared/matcher_eq.md.erb +3 -3
  161. data/docs/shared/matcher_include.md.erb +1 -1
  162. data/docs/shared/matcher_match.md.erb +1 -1
  163. data/docs/shell.md +215 -215
  164. data/examples/README.md +8 -8
  165. data/examples/inheritance/README.md +65 -65
  166. data/examples/inheritance/controls/example.rb +14 -14
  167. data/examples/inheritance/inspec.yml +15 -15
  168. data/examples/kitchen-ansible/.kitchen.yml +25 -25
  169. data/examples/kitchen-ansible/Gemfile +19 -19
  170. data/examples/kitchen-ansible/README.md +53 -53
  171. data/examples/kitchen-ansible/files/nginx.repo +6 -6
  172. data/examples/kitchen-ansible/tasks/main.yml +16 -16
  173. data/examples/kitchen-ansible/test/integration/default/default.yml +5 -5
  174. data/examples/kitchen-ansible/test/integration/default/web_spec.rb +28 -28
  175. data/examples/kitchen-chef/.kitchen.yml +20 -20
  176. data/examples/kitchen-chef/Berksfile +3 -3
  177. data/examples/kitchen-chef/Gemfile +19 -19
  178. data/examples/kitchen-chef/README.md +27 -27
  179. data/examples/kitchen-chef/metadata.rb +7 -7
  180. data/examples/kitchen-chef/recipes/default.rb +6 -6
  181. data/examples/kitchen-chef/recipes/nginx.rb +30 -30
  182. data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -28
  183. data/examples/kitchen-puppet/.kitchen.yml +22 -22
  184. data/examples/kitchen-puppet/Gemfile +20 -20
  185. data/examples/kitchen-puppet/Puppetfile +25 -25
  186. data/examples/kitchen-puppet/README.md +53 -53
  187. data/examples/kitchen-puppet/manifests/site.pp +33 -33
  188. data/examples/kitchen-puppet/metadata.json +11 -11
  189. data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -28
  190. data/examples/meta-profile/README.md +37 -37
  191. data/examples/meta-profile/controls/example.rb +13 -13
  192. data/examples/meta-profile/inspec.yml +13 -13
  193. data/examples/profile-attribute.yml +2 -2
  194. data/examples/profile-attribute/README.md +14 -14
  195. data/examples/profile-attribute/controls/example.rb +11 -11
  196. data/examples/profile-attribute/inspec.yml +8 -8
  197. data/examples/profile-aws/controls/iam_password_policy_expiration.rb +8 -8
  198. data/examples/profile-aws/controls/iam_password_policy_max_age.rb +8 -8
  199. data/examples/profile-aws/controls/iam_root_user_mfa.rb +8 -8
  200. data/examples/profile-aws/controls/iam_users_access_key_age.rb +8 -8
  201. data/examples/profile-aws/controls/iam_users_console_users_mfa.rb +8 -8
  202. data/examples/profile-aws/inspec.yml +11 -11
  203. data/examples/profile-azure/controls/azure_resource_group_example.rb +24 -24
  204. data/examples/profile-azure/controls/azure_vm_example.rb +29 -29
  205. data/examples/profile-azure/inspec.yml +11 -11
  206. data/examples/profile-sensitive/README.md +29 -29
  207. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -9
  208. data/examples/profile-sensitive/controls/sensitive.rb +9 -9
  209. data/examples/profile-sensitive/inspec.yml +8 -8
  210. data/examples/profile/README.md +48 -48
  211. data/examples/profile/controls/example.rb +23 -23
  212. data/examples/profile/controls/gordon.rb +36 -36
  213. data/examples/profile/controls/meta.rb +34 -34
  214. data/examples/profile/inspec.yml +10 -10
  215. data/examples/profile/libraries/gordon_config.rb +53 -53
  216. data/inspec.gemspec +47 -47
  217. data/lib/bundles/README.md +3 -3
  218. data/lib/bundles/inspec-artifact.rb +7 -7
  219. data/lib/bundles/inspec-artifact/README.md +1 -1
  220. data/lib/bundles/inspec-artifact/cli.rb +277 -277
  221. data/lib/bundles/inspec-compliance.rb +16 -16
  222. data/lib/bundles/inspec-compliance/.kitchen.yml +20 -20
  223. data/lib/bundles/inspec-compliance/README.md +185 -185
  224. data/lib/bundles/inspec-compliance/api.rb +316 -316
  225. data/lib/bundles/inspec-compliance/api/login.rb +152 -152
  226. data/lib/bundles/inspec-compliance/bootstrap.sh +41 -41
  227. data/lib/bundles/inspec-compliance/cli.rb +254 -254
  228. data/lib/bundles/inspec-compliance/configuration.rb +103 -103
  229. data/lib/bundles/inspec-compliance/http.rb +86 -86
  230. data/lib/bundles/inspec-compliance/support.rb +36 -36
  231. data/lib/bundles/inspec-compliance/target.rb +98 -98
  232. data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +93 -93
  233. data/lib/bundles/inspec-habitat.rb +12 -12
  234. data/lib/bundles/inspec-habitat/cli.rb +36 -36
  235. data/lib/bundles/inspec-habitat/log.rb +10 -10
  236. data/lib/bundles/inspec-habitat/profile.rb +390 -390
  237. data/lib/bundles/inspec-init.rb +8 -8
  238. data/lib/bundles/inspec-init/README.md +31 -31
  239. data/lib/bundles/inspec-init/cli.rb +97 -97
  240. data/lib/bundles/inspec-init/templates/profile/README.md +3 -3
  241. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +19 -19
  242. data/lib/bundles/inspec-init/templates/profile/inspec.yml +8 -8
  243. data/lib/bundles/inspec-supermarket.rb +13 -13
  244. data/lib/bundles/inspec-supermarket/README.md +45 -45
  245. data/lib/bundles/inspec-supermarket/api.rb +84 -84
  246. data/lib/bundles/inspec-supermarket/cli.rb +73 -73
  247. data/lib/bundles/inspec-supermarket/target.rb +34 -34
  248. data/lib/fetchers/git.rb +163 -163
  249. data/lib/fetchers/local.rb +74 -74
  250. data/lib/fetchers/mock.rb +35 -35
  251. data/lib/fetchers/url.rb +204 -204
  252. data/lib/inspec.rb +24 -24
  253. data/lib/inspec/archive/tar.rb +29 -29
  254. data/lib/inspec/archive/zip.rb +19 -19
  255. data/lib/inspec/backend.rb +92 -92
  256. data/lib/inspec/base_cli.rb +355 -350
  257. data/lib/inspec/cached_fetcher.rb +66 -66
  258. data/lib/inspec/cli.rb +292 -292
  259. data/lib/inspec/completions/bash.sh.erb +45 -45
  260. data/lib/inspec/completions/fish.sh.erb +34 -34
  261. data/lib/inspec/completions/zsh.sh.erb +61 -61
  262. data/lib/inspec/control_eval_context.rb +179 -179
  263. data/lib/inspec/dependencies/cache.rb +72 -72
  264. data/lib/inspec/dependencies/dependency_set.rb +92 -92
  265. data/lib/inspec/dependencies/lockfile.rb +115 -115
  266. data/lib/inspec/dependencies/requirement.rb +123 -123
  267. data/lib/inspec/dependencies/resolver.rb +86 -86
  268. data/lib/inspec/describe.rb +27 -27
  269. data/lib/inspec/dsl.rb +66 -66
  270. data/lib/inspec/dsl_shared.rb +33 -33
  271. data/lib/inspec/env_printer.rb +157 -157
  272. data/lib/inspec/errors.rb +13 -13
  273. data/lib/inspec/exceptions.rb +12 -12
  274. data/lib/inspec/expect.rb +45 -45
  275. data/lib/inspec/fetcher.rb +45 -45
  276. data/lib/inspec/file_provider.rb +275 -275
  277. data/lib/inspec/formatters.rb +3 -3
  278. data/lib/inspec/formatters/base.rb +250 -250
  279. data/lib/inspec/formatters/json_rspec.rb +20 -20
  280. data/lib/inspec/formatters/show_progress.rb +12 -12
  281. data/lib/inspec/library_eval_context.rb +58 -58
  282. data/lib/inspec/log.rb +11 -11
  283. data/lib/inspec/metadata.rb +247 -247
  284. data/lib/inspec/method_source.rb +24 -24
  285. data/lib/inspec/objects.rb +14 -14
  286. data/lib/inspec/objects/attribute.rb +65 -65
  287. data/lib/inspec/objects/control.rb +61 -61
  288. data/lib/inspec/objects/describe.rb +92 -92
  289. data/lib/inspec/objects/each_loop.rb +36 -36
  290. data/lib/inspec/objects/list.rb +15 -15
  291. data/lib/inspec/objects/or_test.rb +40 -40
  292. data/lib/inspec/objects/ruby_helper.rb +15 -15
  293. data/lib/inspec/objects/tag.rb +27 -27
  294. data/lib/inspec/objects/test.rb +87 -87
  295. data/lib/inspec/objects/value.rb +27 -27
  296. data/lib/inspec/plugins.rb +60 -60
  297. data/lib/inspec/plugins/cli.rb +24 -24
  298. data/lib/inspec/plugins/fetcher.rb +86 -86
  299. data/lib/inspec/plugins/resource.rb +135 -135
  300. data/lib/inspec/plugins/secret.rb +15 -15
  301. data/lib/inspec/plugins/source_reader.rb +40 -40
  302. data/lib/inspec/polyfill.rb +12 -12
  303. data/lib/inspec/profile.rb +510 -510
  304. data/lib/inspec/profile_context.rb +207 -207
  305. data/lib/inspec/profile_vendor.rb +66 -66
  306. data/lib/inspec/reporters.rb +54 -50
  307. data/lib/inspec/reporters/base.rb +24 -24
  308. data/lib/inspec/reporters/cli.rb +356 -356
  309. data/lib/inspec/reporters/json.rb +116 -116
  310. data/lib/inspec/reporters/json_min.rb +48 -48
  311. data/lib/inspec/reporters/junit.rb +77 -77
  312. data/lib/inspec/require_loader.rb +33 -33
  313. data/lib/inspec/resource.rb +186 -186
  314. data/lib/inspec/rule.rb +266 -266
  315. data/lib/inspec/runner.rb +345 -345
  316. data/lib/inspec/runner_mock.rb +41 -41
  317. data/lib/inspec/runner_rspec.rb +175 -175
  318. data/lib/inspec/runtime_profile.rb +26 -26
  319. data/lib/inspec/schema.rb +213 -213
  320. data/lib/inspec/secrets.rb +19 -19
  321. data/lib/inspec/secrets/yaml.rb +30 -30
  322. data/lib/inspec/shell.rb +220 -220
  323. data/lib/inspec/shell_detector.rb +90 -90
  324. data/lib/inspec/source_reader.rb +29 -29
  325. data/lib/inspec/version.rb +8 -8
  326. data/lib/matchers/matchers.rb +339 -339
  327. data/lib/resource_support/aws.rb +41 -41
  328. data/lib/resource_support/aws/aws_backend_base.rb +12 -12
  329. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -12
  330. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +21 -21
  331. data/lib/resource_support/aws/aws_resource_mixin.rb +66 -66
  332. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +24 -24
  333. data/lib/resources/aide_conf.rb +159 -160
  334. data/lib/resources/apache.rb +48 -48
  335. data/lib/resources/apache_conf.rb +156 -156
  336. data/lib/resources/apt.rb +149 -149
  337. data/lib/resources/audit_policy.rb +63 -63
  338. data/lib/resources/auditd.rb +231 -231
  339. data/lib/resources/auditd_conf.rb +55 -55
  340. data/lib/resources/aws/aws_cloudtrail_trail.rb +77 -77
  341. data/lib/resources/aws/aws_cloudtrail_trails.rb +47 -47
  342. data/lib/resources/aws/aws_cloudwatch_alarm.rb +62 -62
  343. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +100 -100
  344. data/lib/resources/aws/aws_config_recorder.rb +98 -98
  345. data/lib/resources/aws/aws_ec2_instance.rb +157 -157
  346. data/lib/resources/aws/aws_iam_access_key.rb +106 -106
  347. data/lib/resources/aws/aws_iam_access_keys.rb +149 -144
  348. data/lib/resources/aws/aws_iam_group.rb +56 -56
  349. data/lib/resources/aws/aws_iam_groups.rb +52 -45
  350. data/lib/resources/aws/aws_iam_password_policy.rb +116 -116
  351. data/lib/resources/aws/aws_iam_policies.rb +53 -46
  352. data/lib/resources/aws/aws_iam_policy.rb +125 -119
  353. data/lib/resources/aws/aws_iam_role.rb +51 -51
  354. data/lib/resources/aws/aws_iam_root_user.rb +60 -60
  355. data/lib/resources/aws/aws_iam_user.rb +111 -111
  356. data/lib/resources/aws/aws_iam_users.rb +108 -96
  357. data/lib/resources/aws/aws_kms_keys.rb +53 -46
  358. data/lib/resources/aws/aws_route_table.rb +61 -61
  359. data/lib/resources/aws/aws_s3_bucket.rb +115 -115
  360. data/lib/resources/aws/aws_security_group.rb +93 -93
  361. data/lib/resources/aws/aws_security_groups.rb +68 -68
  362. data/lib/resources/aws/aws_sns_topic.rb +53 -53
  363. data/lib/resources/aws/aws_subnet.rb +88 -88
  364. data/lib/resources/aws/aws_subnets.rb +53 -53
  365. data/lib/resources/aws/aws_vpc.rb +69 -69
  366. data/lib/resources/aws/aws_vpcs.rb +45 -45
  367. data/lib/resources/azure/azure_backend.rb +377 -377
  368. data/lib/resources/azure/azure_generic_resource.rb +59 -59
  369. data/lib/resources/azure/azure_resource_group.rb +152 -152
  370. data/lib/resources/azure/azure_virtual_machine.rb +264 -264
  371. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +136 -136
  372. data/lib/resources/bash.rb +35 -35
  373. data/lib/resources/bond.rb +68 -68
  374. data/lib/resources/bridge.rb +122 -122
  375. data/lib/resources/command.rb +73 -69
  376. data/lib/resources/cpan.rb +58 -58
  377. data/lib/resources/cran.rb +64 -64
  378. data/lib/resources/crontab.rb +169 -170
  379. data/lib/resources/csv.rb +60 -60
  380. data/lib/resources/dh_params.rb +82 -82
  381. data/lib/resources/directory.rb +25 -25
  382. data/lib/resources/docker.rb +236 -236
  383. data/lib/resources/docker_container.rb +89 -89
  384. data/lib/resources/docker_image.rb +83 -83
  385. data/lib/resources/docker_object.rb +57 -57
  386. data/lib/resources/docker_service.rb +90 -90
  387. data/lib/resources/elasticsearch.rb +169 -169
  388. data/lib/resources/etc_fstab.rb +101 -102
  389. data/lib/resources/etc_group.rb +152 -156
  390. data/lib/resources/etc_hosts.rb +82 -81
  391. data/lib/resources/etc_hosts_allow_deny.rb +122 -123
  392. data/lib/resources/file.rb +298 -298
  393. data/lib/resources/filesystem.rb +31 -31
  394. data/lib/resources/firewalld.rb +143 -144
  395. data/lib/resources/gem.rb +70 -70
  396. data/lib/resources/groups.rb +215 -215
  397. data/lib/resources/grub_conf.rb +237 -237
  398. data/lib/resources/host.rb +306 -300
  399. data/lib/resources/http.rb +251 -250
  400. data/lib/resources/iis_app.rb +101 -104
  401. data/lib/resources/iis_site.rb +148 -148
  402. data/lib/resources/inetd_conf.rb +62 -62
  403. data/lib/resources/ini.rb +29 -29
  404. data/lib/resources/interface.rb +129 -129
  405. data/lib/resources/iptables.rb +80 -69
  406. data/lib/resources/json.rb +117 -117
  407. data/lib/resources/kernel_module.rb +107 -107
  408. data/lib/resources/kernel_parameter.rb +58 -58
  409. data/lib/resources/key_rsa.rb +67 -67
  410. data/lib/resources/limits_conf.rb +55 -55
  411. data/lib/resources/login_def.rb +66 -66
  412. data/lib/resources/mount.rb +88 -88
  413. data/lib/resources/mssql_session.rb +101 -101
  414. data/lib/resources/mysql.rb +81 -81
  415. data/lib/resources/mysql_conf.rb +134 -134
  416. data/lib/resources/mysql_session.rb +71 -71
  417. data/lib/resources/nginx.rb +96 -96
  418. data/lib/resources/nginx_conf.rb +227 -227
  419. data/lib/resources/npm.rb +48 -48
  420. data/lib/resources/ntp_conf.rb +58 -58
  421. data/lib/resources/oneget.rb +71 -71
  422. data/lib/resources/oracledb_session.rb +139 -139
  423. data/lib/resources/os.rb +36 -36
  424. data/lib/resources/os_env.rb +76 -76
  425. data/lib/resources/package.rb +370 -370
  426. data/lib/resources/packages.rb +111 -111
  427. data/lib/resources/parse_config.rb +116 -116
  428. data/lib/resources/passwd.rb +74 -74
  429. data/lib/resources/pip.rb +89 -89
  430. data/lib/resources/platform.rb +109 -109
  431. data/lib/resources/port.rb +771 -771
  432. data/lib/resources/postgres.rb +130 -130
  433. data/lib/resources/postgres_conf.rb +121 -121
  434. data/lib/resources/postgres_hba_conf.rb +99 -100
  435. data/lib/resources/postgres_ident_conf.rb +76 -78
  436. data/lib/resources/postgres_session.rb +71 -71
  437. data/lib/resources/powershell.rb +53 -57
  438. data/lib/resources/processes.rb +204 -204
  439. data/lib/resources/rabbitmq_conf.rb +52 -52
  440. data/lib/resources/registry_key.rb +296 -296
  441. data/lib/resources/security_policy.rb +180 -180
  442. data/lib/resources/service.rb +789 -789
  443. data/lib/resources/shadow.rb +146 -140
  444. data/lib/resources/ssh_conf.rb +102 -102
  445. data/lib/resources/ssl.rb +99 -99
  446. data/lib/resources/sys_info.rb +28 -28
  447. data/lib/resources/toml.rb +32 -32
  448. data/lib/resources/users.rb +654 -654
  449. data/lib/resources/vbscript.rb +68 -69
  450. data/lib/resources/virtualization.rb +247 -247
  451. data/lib/resources/windows_feature.rb +84 -84
  452. data/lib/resources/windows_hotfix.rb +35 -35
  453. data/lib/resources/windows_task.rb +102 -105
  454. data/lib/resources/wmi.rb +110 -113
  455. data/lib/resources/x509_certificate.rb +143 -143
  456. data/lib/resources/xinetd.rb +111 -111
  457. data/lib/resources/xml.rb +46 -46
  458. data/lib/resources/yaml.rb +47 -47
  459. data/lib/resources/yum.rb +180 -180
  460. data/lib/resources/zfs_dataset.rb +60 -60
  461. data/lib/resources/zfs_pool.rb +49 -49
  462. data/lib/source_readers/flat.rb +39 -39
  463. data/lib/source_readers/inspec.rb +75 -75
  464. data/lib/utils/command_wrapper.rb +27 -27
  465. data/lib/utils/convert.rb +12 -12
  466. data/lib/utils/database_helpers.rb +77 -77
  467. data/lib/utils/erlang_parser.rb +192 -192
  468. data/lib/utils/filter.rb +272 -272
  469. data/lib/utils/filter_array.rb +27 -27
  470. data/lib/utils/find_files.rb +44 -44
  471. data/lib/utils/hash.rb +41 -41
  472. data/lib/utils/json_log.rb +18 -18
  473. data/lib/utils/latest_version.rb +22 -22
  474. data/lib/utils/modulator.rb +12 -12
  475. data/lib/utils/nginx_parser.rb +85 -85
  476. data/lib/utils/object_traversal.rb +49 -49
  477. data/lib/utils/parser.rb +274 -274
  478. data/lib/utils/plugin_registry.rb +93 -93
  479. data/lib/utils/simpleconfig.rb +120 -120
  480. data/lib/utils/spdx.rb +13 -13
  481. data/lib/utils/spdx.txt +343 -343
  482. metadata +2 -2
@@ -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