inspec-core 2.1.67

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