inspec 2.1.80 → 2.1.81

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 (510) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +101 -101
  3. data/CHANGELOG.md +3177 -3172
  4. data/Gemfile +56 -56
  5. data/LICENSE +14 -14
  6. data/MAINTAINERS.md +33 -33
  7. data/MAINTAINERS.toml +52 -52
  8. data/README.md +453 -453
  9. data/Rakefile +349 -349
  10. data/bin/inspec +12 -12
  11. data/docs/.gitignore +2 -2
  12. data/docs/README.md +40 -40
  13. data/docs/dev/control-eval.md +61 -61
  14. data/docs/dsl_inspec.md +258 -258
  15. data/docs/dsl_resource.md +100 -100
  16. data/docs/glossary.md +99 -99
  17. data/docs/habitat.md +191 -191
  18. data/docs/inspec_and_friends.md +114 -114
  19. data/docs/matchers.md +169 -169
  20. data/docs/migration.md +293 -293
  21. data/docs/platforms.md +118 -118
  22. data/docs/plugin_kitchen_inspec.md +50 -50
  23. data/docs/profiles.md +378 -378
  24. data/docs/reporters.md +105 -105
  25. data/docs/resources/aide_conf.md.erb +75 -75
  26. data/docs/resources/apache.md.erb +67 -67
  27. data/docs/resources/apache_conf.md.erb +68 -68
  28. data/docs/resources/apt.md.erb +71 -71
  29. data/docs/resources/audit_policy.md.erb +47 -47
  30. data/docs/resources/auditd.md.erb +79 -79
  31. data/docs/resources/auditd_conf.md.erb +68 -68
  32. data/docs/resources/aws_cloudtrail_trail.md.erb +155 -155
  33. data/docs/resources/aws_cloudtrail_trails.md.erb +86 -86
  34. data/docs/resources/aws_cloudwatch_alarm.md.erb +91 -91
  35. data/docs/resources/aws_cloudwatch_log_metric_filter.md.erb +154 -154
  36. data/docs/resources/aws_config_delivery_channel.md.erb +101 -101
  37. data/docs/resources/aws_config_recorder.md.erb +86 -86
  38. data/docs/resources/aws_ec2_instance.md.erb +112 -112
  39. data/docs/resources/aws_ec2_instances.md.erb +79 -79
  40. data/docs/resources/aws_iam_access_key.md.erb +129 -129
  41. data/docs/resources/aws_iam_access_keys.md.erb +204 -204
  42. data/docs/resources/aws_iam_group.md.erb +64 -64
  43. data/docs/resources/aws_iam_groups.md.erb +49 -49
  44. data/docs/resources/aws_iam_password_policy.md.erb +82 -82
  45. data/docs/resources/aws_iam_policies.md.erb +87 -87
  46. data/docs/resources/aws_iam_policy.md.erb +245 -245
  47. data/docs/resources/aws_iam_role.md.erb +69 -69
  48. data/docs/resources/aws_iam_root_user.md.erb +76 -76
  49. data/docs/resources/aws_iam_user.md.erb +120 -120
  50. data/docs/resources/aws_iam_users.md.erb +279 -279
  51. data/docs/resources/aws_kms_key.md.erb +177 -177
  52. data/docs/resources/aws_kms_keys.md.erb +89 -89
  53. data/docs/resources/aws_rds_instance.md.erb +66 -66
  54. data/docs/resources/aws_route_table.md.erb +53 -53
  55. data/docs/resources/aws_route_tables.md.erb +55 -55
  56. data/docs/resources/aws_s3_bucket.md.erb +146 -146
  57. data/docs/resources/aws_s3_bucket_object.md.erb +89 -89
  58. data/docs/resources/aws_s3_buckets.md.erb +59 -59
  59. data/docs/resources/aws_security_group.md.erb +296 -296
  60. data/docs/resources/aws_security_groups.md.erb +97 -97
  61. data/docs/resources/aws_sns_subscription.md.erb +130 -130
  62. data/docs/resources/aws_sns_topic.md.erb +69 -69
  63. data/docs/resources/aws_sns_topics.md.erb +58 -58
  64. data/docs/resources/aws_subnet.md.erb +140 -140
  65. data/docs/resources/aws_subnets.md.erb +132 -132
  66. data/docs/resources/aws_vpc.md.erb +125 -125
  67. data/docs/resources/aws_vpcs.md.erb +125 -125
  68. data/docs/resources/azure_generic_resource.md.erb +171 -171
  69. data/docs/resources/azure_resource_group.md.erb +284 -284
  70. data/docs/resources/azure_virtual_machine.md.erb +347 -347
  71. data/docs/resources/azure_virtual_machine_data_disk.md.erb +224 -224
  72. data/docs/resources/bash.md.erb +75 -75
  73. data/docs/resources/bond.md.erb +90 -90
  74. data/docs/resources/bridge.md.erb +57 -57
  75. data/docs/resources/bsd_service.md.erb +67 -67
  76. data/docs/resources/chocolatey_package.md.erb +58 -58
  77. data/docs/resources/command.md.erb +138 -138
  78. data/docs/resources/cpan.md.erb +79 -79
  79. data/docs/resources/cran.md.erb +64 -64
  80. data/docs/resources/crontab.md.erb +89 -89
  81. data/docs/resources/csv.md.erb +54 -54
  82. data/docs/resources/dh_params.md.erb +205 -205
  83. data/docs/resources/directory.md.erb +30 -30
  84. data/docs/resources/docker.md.erb +219 -219
  85. data/docs/resources/docker_container.md.erb +103 -103
  86. data/docs/resources/docker_image.md.erb +94 -94
  87. data/docs/resources/docker_service.md.erb +114 -114
  88. data/docs/resources/elasticsearch.md.erb +242 -242
  89. data/docs/resources/etc_fstab.md.erb +125 -125
  90. data/docs/resources/etc_group.md.erb +75 -75
  91. data/docs/resources/etc_hosts.md.erb +78 -78
  92. data/docs/resources/etc_hosts_allow.md.erb +74 -74
  93. data/docs/resources/etc_hosts_deny.md.erb +74 -74
  94. data/docs/resources/file.md.erb +526 -526
  95. data/docs/resources/filesystem.md.erb +41 -41
  96. data/docs/resources/firewalld.md.erb +107 -107
  97. data/docs/resources/gem.md.erb +79 -79
  98. data/docs/resources/group.md.erb +61 -61
  99. data/docs/resources/grub_conf.md.erb +101 -101
  100. data/docs/resources/host.md.erb +86 -86
  101. data/docs/resources/http.md.erb +197 -197
  102. data/docs/resources/iis_app.md.erb +122 -122
  103. data/docs/resources/iis_site.md.erb +135 -135
  104. data/docs/resources/inetd_conf.md.erb +94 -94
  105. data/docs/resources/ini.md.erb +76 -76
  106. data/docs/resources/interface.md.erb +58 -58
  107. data/docs/resources/iptables.md.erb +64 -64
  108. data/docs/resources/json.md.erb +63 -63
  109. data/docs/resources/kernel_module.md.erb +120 -120
  110. data/docs/resources/kernel_parameter.md.erb +53 -53
  111. data/docs/resources/key_rsa.md.erb +85 -85
  112. data/docs/resources/launchd_service.md.erb +57 -57
  113. data/docs/resources/limits_conf.md.erb +75 -75
  114. data/docs/resources/login_defs.md.erb +71 -71
  115. data/docs/resources/mount.md.erb +69 -69
  116. data/docs/resources/mssql_session.md.erb +60 -60
  117. data/docs/resources/mysql_conf.md.erb +99 -99
  118. data/docs/resources/mysql_session.md.erb +74 -74
  119. data/docs/resources/nginx.md.erb +79 -79
  120. data/docs/resources/nginx_conf.md.erb +138 -138
  121. data/docs/resources/npm.md.erb +60 -60
  122. data/docs/resources/ntp_conf.md.erb +60 -60
  123. data/docs/resources/oneget.md.erb +53 -53
  124. data/docs/resources/oracledb_session.md.erb +52 -52
  125. data/docs/resources/os.md.erb +141 -141
  126. data/docs/resources/os_env.md.erb +91 -91
  127. data/docs/resources/package.md.erb +120 -120
  128. data/docs/resources/packages.md.erb +67 -67
  129. data/docs/resources/parse_config.md.erb +103 -103
  130. data/docs/resources/parse_config_file.md.erb +138 -138
  131. data/docs/resources/passwd.md.erb +141 -141
  132. data/docs/resources/pip.md.erb +67 -67
  133. data/docs/resources/port.md.erb +137 -137
  134. data/docs/resources/postgres_conf.md.erb +79 -79
  135. data/docs/resources/postgres_hba_conf.md.erb +93 -93
  136. data/docs/resources/postgres_ident_conf.md.erb +76 -76
  137. data/docs/resources/postgres_session.md.erb +69 -69
  138. data/docs/resources/powershell.md.erb +102 -102
  139. data/docs/resources/processes.md.erb +109 -109
  140. data/docs/resources/rabbitmq_config.md.erb +41 -41
  141. data/docs/resources/registry_key.md.erb +158 -158
  142. data/docs/resources/runit_service.md.erb +57 -57
  143. data/docs/resources/security_policy.md.erb +47 -47
  144. data/docs/resources/service.md.erb +121 -121
  145. data/docs/resources/shadow.md.erb +146 -146
  146. data/docs/resources/ssh_config.md.erb +73 -73
  147. data/docs/resources/sshd_config.md.erb +83 -83
  148. data/docs/resources/ssl.md.erb +119 -119
  149. data/docs/resources/sys_info.md.erb +42 -42
  150. data/docs/resources/systemd_service.md.erb +57 -57
  151. data/docs/resources/sysv_service.md.erb +57 -57
  152. data/docs/resources/upstart_service.md.erb +57 -57
  153. data/docs/resources/user.md.erb +140 -140
  154. data/docs/resources/users.md.erb +127 -127
  155. data/docs/resources/vbscript.md.erb +55 -55
  156. data/docs/resources/virtualization.md.erb +57 -57
  157. data/docs/resources/windows_feature.md.erb +47 -47
  158. data/docs/resources/windows_hotfix.md.erb +53 -53
  159. data/docs/resources/windows_task.md.erb +95 -95
  160. data/docs/resources/wmi.md.erb +81 -81
  161. data/docs/resources/x509_certificate.md.erb +151 -151
  162. data/docs/resources/xinetd_conf.md.erb +156 -156
  163. data/docs/resources/xml.md.erb +85 -85
  164. data/docs/resources/yaml.md.erb +69 -69
  165. data/docs/resources/yum.md.erb +98 -98
  166. data/docs/resources/zfs_dataset.md.erb +53 -53
  167. data/docs/resources/zfs_pool.md.erb +47 -47
  168. data/docs/ruby_usage.md +203 -203
  169. data/docs/shared/matcher_be.md.erb +1 -1
  170. data/docs/shared/matcher_cmp.md.erb +43 -43
  171. data/docs/shared/matcher_eq.md.erb +3 -3
  172. data/docs/shared/matcher_include.md.erb +1 -1
  173. data/docs/shared/matcher_match.md.erb +1 -1
  174. data/docs/shell.md +217 -217
  175. data/examples/README.md +8 -8
  176. data/examples/inheritance/README.md +65 -65
  177. data/examples/inheritance/controls/example.rb +14 -14
  178. data/examples/inheritance/inspec.yml +15 -15
  179. data/examples/kitchen-ansible/.kitchen.yml +25 -25
  180. data/examples/kitchen-ansible/Gemfile +19 -19
  181. data/examples/kitchen-ansible/README.md +53 -53
  182. data/examples/kitchen-ansible/files/nginx.repo +6 -6
  183. data/examples/kitchen-ansible/tasks/main.yml +16 -16
  184. data/examples/kitchen-ansible/test/integration/default/default.yml +5 -5
  185. data/examples/kitchen-ansible/test/integration/default/web_spec.rb +28 -28
  186. data/examples/kitchen-chef/.kitchen.yml +20 -20
  187. data/examples/kitchen-chef/Berksfile +3 -3
  188. data/examples/kitchen-chef/Gemfile +19 -19
  189. data/examples/kitchen-chef/README.md +27 -27
  190. data/examples/kitchen-chef/metadata.rb +7 -7
  191. data/examples/kitchen-chef/recipes/default.rb +6 -6
  192. data/examples/kitchen-chef/recipes/nginx.rb +30 -30
  193. data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -28
  194. data/examples/kitchen-puppet/.kitchen.yml +23 -23
  195. data/examples/kitchen-puppet/Gemfile +20 -20
  196. data/examples/kitchen-puppet/Puppetfile +25 -25
  197. data/examples/kitchen-puppet/README.md +53 -53
  198. data/examples/kitchen-puppet/manifests/site.pp +33 -33
  199. data/examples/kitchen-puppet/metadata.json +11 -11
  200. data/examples/kitchen-puppet/modules/.gitkeep +0 -0
  201. data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -28
  202. data/examples/meta-profile/README.md +37 -37
  203. data/examples/meta-profile/controls/example.rb +13 -13
  204. data/examples/meta-profile/inspec.yml +13 -13
  205. data/examples/profile-attribute.yml +2 -2
  206. data/examples/profile-attribute/README.md +14 -14
  207. data/examples/profile-attribute/controls/example.rb +11 -11
  208. data/examples/profile-attribute/inspec.yml +8 -8
  209. data/examples/profile-aws/controls/iam_password_policy_expiration.rb +8 -8
  210. data/examples/profile-aws/controls/iam_password_policy_max_age.rb +8 -8
  211. data/examples/profile-aws/controls/iam_root_user_mfa.rb +8 -8
  212. data/examples/profile-aws/controls/iam_users_access_key_age.rb +8 -8
  213. data/examples/profile-aws/controls/iam_users_console_users_mfa.rb +8 -8
  214. data/examples/profile-aws/inspec.yml +11 -11
  215. data/examples/profile-azure/controls/azure_resource_group_example.rb +24 -24
  216. data/examples/profile-azure/controls/azure_vm_example.rb +29 -29
  217. data/examples/profile-azure/inspec.yml +11 -11
  218. data/examples/profile-sensitive/README.md +29 -29
  219. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -9
  220. data/examples/profile-sensitive/controls/sensitive.rb +9 -9
  221. data/examples/profile-sensitive/inspec.yml +8 -8
  222. data/examples/profile/README.md +48 -48
  223. data/examples/profile/controls/example.rb +23 -23
  224. data/examples/profile/controls/gordon.rb +36 -36
  225. data/examples/profile/controls/meta.rb +34 -34
  226. data/examples/profile/inspec.yml +10 -10
  227. data/examples/profile/libraries/gordon_config.rb +59 -59
  228. data/inspec.gemspec +49 -49
  229. data/lib/bundles/README.md +3 -3
  230. data/lib/bundles/inspec-artifact.rb +7 -7
  231. data/lib/bundles/inspec-artifact/README.md +1 -1
  232. data/lib/bundles/inspec-artifact/cli.rb +277 -277
  233. data/lib/bundles/inspec-compliance.rb +16 -16
  234. data/lib/bundles/inspec-compliance/.kitchen.yml +20 -20
  235. data/lib/bundles/inspec-compliance/README.md +193 -193
  236. data/lib/bundles/inspec-compliance/api.rb +360 -360
  237. data/lib/bundles/inspec-compliance/api/login.rb +193 -193
  238. data/lib/bundles/inspec-compliance/bootstrap.sh +41 -41
  239. data/lib/bundles/inspec-compliance/cli.rb +260 -260
  240. data/lib/bundles/inspec-compliance/configuration.rb +103 -103
  241. data/lib/bundles/inspec-compliance/http.rb +125 -125
  242. data/lib/bundles/inspec-compliance/images/cc-token.png +0 -0
  243. data/lib/bundles/inspec-compliance/support.rb +36 -36
  244. data/lib/bundles/inspec-compliance/target.rb +112 -112
  245. data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +93 -93
  246. data/lib/bundles/inspec-habitat.rb +12 -12
  247. data/lib/bundles/inspec-habitat/cli.rb +36 -36
  248. data/lib/bundles/inspec-habitat/log.rb +10 -10
  249. data/lib/bundles/inspec-habitat/profile.rb +391 -391
  250. data/lib/bundles/inspec-init.rb +8 -8
  251. data/lib/bundles/inspec-init/README.md +31 -31
  252. data/lib/bundles/inspec-init/cli.rb +97 -97
  253. data/lib/bundles/inspec-init/templates/profile/README.md +3 -3
  254. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +19 -19
  255. data/lib/bundles/inspec-init/templates/profile/inspec.yml +8 -8
  256. data/lib/bundles/inspec-init/templates/profile/libraries/.gitkeep +0 -0
  257. data/lib/bundles/inspec-supermarket.rb +13 -13
  258. data/lib/bundles/inspec-supermarket/README.md +45 -45
  259. data/lib/bundles/inspec-supermarket/api.rb +84 -84
  260. data/lib/bundles/inspec-supermarket/cli.rb +73 -73
  261. data/lib/bundles/inspec-supermarket/target.rb +34 -34
  262. data/lib/fetchers/git.rb +163 -163
  263. data/lib/fetchers/local.rb +74 -74
  264. data/lib/fetchers/mock.rb +35 -35
  265. data/lib/fetchers/url.rb +247 -247
  266. data/lib/inspec.rb +24 -24
  267. data/lib/inspec/archive/tar.rb +29 -29
  268. data/lib/inspec/archive/zip.rb +19 -19
  269. data/lib/inspec/backend.rb +93 -93
  270. data/lib/inspec/base_cli.rb +368 -368
  271. data/lib/inspec/cached_fetcher.rb +66 -66
  272. data/lib/inspec/cli.rb +292 -292
  273. data/lib/inspec/completions/bash.sh.erb +45 -45
  274. data/lib/inspec/completions/fish.sh.erb +34 -34
  275. data/lib/inspec/completions/zsh.sh.erb +61 -61
  276. data/lib/inspec/control_eval_context.rb +179 -179
  277. data/lib/inspec/dependencies/cache.rb +72 -72
  278. data/lib/inspec/dependencies/dependency_set.rb +92 -92
  279. data/lib/inspec/dependencies/lockfile.rb +115 -115
  280. data/lib/inspec/dependencies/requirement.rb +123 -123
  281. data/lib/inspec/dependencies/resolver.rb +86 -86
  282. data/lib/inspec/describe.rb +27 -27
  283. data/lib/inspec/dsl.rb +66 -66
  284. data/lib/inspec/dsl_shared.rb +33 -33
  285. data/lib/inspec/env_printer.rb +157 -157
  286. data/lib/inspec/errors.rb +14 -14
  287. data/lib/inspec/exceptions.rb +12 -12
  288. data/lib/inspec/expect.rb +45 -45
  289. data/lib/inspec/fetcher.rb +45 -45
  290. data/lib/inspec/file_provider.rb +275 -275
  291. data/lib/inspec/formatters.rb +3 -3
  292. data/lib/inspec/formatters/base.rb +259 -259
  293. data/lib/inspec/formatters/json_rspec.rb +20 -20
  294. data/lib/inspec/formatters/show_progress.rb +12 -12
  295. data/lib/inspec/library_eval_context.rb +58 -58
  296. data/lib/inspec/log.rb +11 -11
  297. data/lib/inspec/metadata.rb +247 -247
  298. data/lib/inspec/method_source.rb +24 -24
  299. data/lib/inspec/objects.rb +14 -14
  300. data/lib/inspec/objects/attribute.rb +75 -75
  301. data/lib/inspec/objects/control.rb +61 -61
  302. data/lib/inspec/objects/describe.rb +92 -92
  303. data/lib/inspec/objects/each_loop.rb +36 -36
  304. data/lib/inspec/objects/list.rb +15 -15
  305. data/lib/inspec/objects/or_test.rb +40 -40
  306. data/lib/inspec/objects/ruby_helper.rb +15 -15
  307. data/lib/inspec/objects/tag.rb +27 -27
  308. data/lib/inspec/objects/test.rb +87 -87
  309. data/lib/inspec/objects/value.rb +27 -27
  310. data/lib/inspec/plugins.rb +60 -60
  311. data/lib/inspec/plugins/cli.rb +24 -24
  312. data/lib/inspec/plugins/fetcher.rb +86 -86
  313. data/lib/inspec/plugins/resource.rb +135 -135
  314. data/lib/inspec/plugins/secret.rb +15 -15
  315. data/lib/inspec/plugins/source_reader.rb +40 -40
  316. data/lib/inspec/polyfill.rb +12 -12
  317. data/lib/inspec/profile.rb +513 -513
  318. data/lib/inspec/profile_context.rb +208 -208
  319. data/lib/inspec/profile_vendor.rb +66 -66
  320. data/lib/inspec/reporters.rb +60 -60
  321. data/lib/inspec/reporters/automate.rb +76 -76
  322. data/lib/inspec/reporters/base.rb +25 -25
  323. data/lib/inspec/reporters/cli.rb +356 -356
  324. data/lib/inspec/reporters/json.rb +117 -117
  325. data/lib/inspec/reporters/json_min.rb +48 -48
  326. data/lib/inspec/reporters/junit.rb +78 -78
  327. data/lib/inspec/require_loader.rb +33 -33
  328. data/lib/inspec/resource.rb +190 -190
  329. data/lib/inspec/rule.rb +280 -280
  330. data/lib/inspec/runner.rb +345 -345
  331. data/lib/inspec/runner_mock.rb +41 -41
  332. data/lib/inspec/runner_rspec.rb +175 -175
  333. data/lib/inspec/runtime_profile.rb +26 -26
  334. data/lib/inspec/schema.rb +213 -213
  335. data/lib/inspec/secrets.rb +19 -19
  336. data/lib/inspec/secrets/yaml.rb +30 -30
  337. data/lib/inspec/shell.rb +220 -220
  338. data/lib/inspec/shell_detector.rb +90 -90
  339. data/lib/inspec/source_reader.rb +29 -29
  340. data/lib/inspec/version.rb +8 -8
  341. data/lib/matchers/matchers.rb +339 -339
  342. data/lib/resource_support/aws.rb +50 -50
  343. data/lib/resource_support/aws/aws_backend_base.rb +12 -12
  344. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -12
  345. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +21 -21
  346. data/lib/resource_support/aws/aws_resource_mixin.rb +66 -66
  347. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +24 -24
  348. data/lib/resources/aide_conf.rb +151 -151
  349. data/lib/resources/apache.rb +48 -48
  350. data/lib/resources/apache_conf.rb +149 -149
  351. data/lib/resources/apt.rb +149 -149
  352. data/lib/resources/audit_policy.rb +63 -63
  353. data/lib/resources/auditd.rb +231 -231
  354. data/lib/resources/auditd_conf.rb +46 -46
  355. data/lib/resources/aws/aws_cloudtrail_trail.rb +93 -93
  356. data/lib/resources/aws/aws_cloudtrail_trails.rb +47 -47
  357. data/lib/resources/aws/aws_cloudwatch_alarm.rb +62 -62
  358. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +100 -100
  359. data/lib/resources/aws/aws_config_delivery_channel.rb +70 -70
  360. data/lib/resources/aws/aws_config_recorder.rb +93 -93
  361. data/lib/resources/aws/aws_ec2_instance.rb +157 -157
  362. data/lib/resources/aws/aws_ec2_instances.rb +64 -64
  363. data/lib/resources/aws/aws_iam_access_key.rb +106 -106
  364. data/lib/resources/aws/aws_iam_access_keys.rb +149 -149
  365. data/lib/resources/aws/aws_iam_group.rb +58 -58
  366. data/lib/resources/aws/aws_iam_groups.rb +52 -52
  367. data/lib/resources/aws/aws_iam_password_policy.rb +116 -116
  368. data/lib/resources/aws/aws_iam_policies.rb +53 -53
  369. data/lib/resources/aws/aws_iam_policy.rb +291 -291
  370. data/lib/resources/aws/aws_iam_role.rb +55 -55
  371. data/lib/resources/aws/aws_iam_root_user.rb +78 -78
  372. data/lib/resources/aws/aws_iam_user.rb +142 -142
  373. data/lib/resources/aws/aws_iam_users.rb +146 -146
  374. data/lib/resources/aws/aws_kms_key.rb +96 -96
  375. data/lib/resources/aws/aws_kms_keys.rb +53 -53
  376. data/lib/resources/aws/aws_rds_instance.rb +71 -71
  377. data/lib/resources/aws/aws_route_table.rb +63 -63
  378. data/lib/resources/aws/aws_route_tables.rb +60 -60
  379. data/lib/resources/aws/aws_s3_bucket.rb +137 -137
  380. data/lib/resources/aws/aws_s3_bucket_object.rb +82 -82
  381. data/lib/resources/aws/aws_s3_buckets.rb +51 -51
  382. data/lib/resources/aws/aws_security_group.rb +249 -249
  383. data/lib/resources/aws/aws_security_groups.rb +68 -68
  384. data/lib/resources/aws/aws_sns_subscription.rb +78 -78
  385. data/lib/resources/aws/aws_sns_topic.rb +53 -53
  386. data/lib/resources/aws/aws_sns_topics.rb +56 -56
  387. data/lib/resources/aws/aws_subnet.rb +88 -88
  388. data/lib/resources/aws/aws_subnets.rb +53 -53
  389. data/lib/resources/aws/aws_vpc.rb +73 -73
  390. data/lib/resources/aws/aws_vpcs.rb +52 -52
  391. data/lib/resources/azure/azure_backend.rb +377 -377
  392. data/lib/resources/azure/azure_generic_resource.rb +59 -59
  393. data/lib/resources/azure/azure_resource_group.rb +152 -152
  394. data/lib/resources/azure/azure_virtual_machine.rb +264 -264
  395. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +134 -134
  396. data/lib/resources/bash.rb +35 -35
  397. data/lib/resources/bond.rb +69 -69
  398. data/lib/resources/bridge.rb +122 -122
  399. data/lib/resources/chocolatey_package.rb +78 -78
  400. data/lib/resources/command.rb +73 -73
  401. data/lib/resources/cpan.rb +58 -58
  402. data/lib/resources/cran.rb +64 -64
  403. data/lib/resources/crontab.rb +169 -169
  404. data/lib/resources/csv.rb +56 -56
  405. data/lib/resources/dh_params.rb +77 -77
  406. data/lib/resources/directory.rb +25 -25
  407. data/lib/resources/docker.rb +236 -236
  408. data/lib/resources/docker_container.rb +89 -89
  409. data/lib/resources/docker_image.rb +83 -83
  410. data/lib/resources/docker_object.rb +57 -57
  411. data/lib/resources/docker_service.rb +90 -90
  412. data/lib/resources/elasticsearch.rb +169 -169
  413. data/lib/resources/etc_fstab.rb +94 -94
  414. data/lib/resources/etc_group.rb +154 -154
  415. data/lib/resources/etc_hosts.rb +66 -66
  416. data/lib/resources/etc_hosts_allow_deny.rb +112 -112
  417. data/lib/resources/file.rb +298 -298
  418. data/lib/resources/filesystem.rb +31 -31
  419. data/lib/resources/firewalld.rb +143 -143
  420. data/lib/resources/gem.rb +70 -70
  421. data/lib/resources/groups.rb +215 -215
  422. data/lib/resources/grub_conf.rb +227 -227
  423. data/lib/resources/host.rb +306 -306
  424. data/lib/resources/http.rb +253 -253
  425. data/lib/resources/iis_app.rb +101 -101
  426. data/lib/resources/iis_site.rb +148 -148
  427. data/lib/resources/inetd_conf.rb +54 -54
  428. data/lib/resources/ini.rb +29 -29
  429. data/lib/resources/interface.rb +129 -129
  430. data/lib/resources/iptables.rb +80 -80
  431. data/lib/resources/json.rb +111 -111
  432. data/lib/resources/kernel_module.rb +107 -107
  433. data/lib/resources/kernel_parameter.rb +58 -58
  434. data/lib/resources/key_rsa.rb +63 -63
  435. data/lib/resources/limits_conf.rb +46 -46
  436. data/lib/resources/login_def.rb +57 -57
  437. data/lib/resources/mount.rb +88 -88
  438. data/lib/resources/mssql_session.rb +101 -101
  439. data/lib/resources/mysql.rb +82 -82
  440. data/lib/resources/mysql_conf.rb +127 -127
  441. data/lib/resources/mysql_session.rb +85 -85
  442. data/lib/resources/nginx.rb +96 -96
  443. data/lib/resources/nginx_conf.rb +226 -226
  444. data/lib/resources/npm.rb +48 -48
  445. data/lib/resources/ntp_conf.rb +51 -51
  446. data/lib/resources/oneget.rb +71 -71
  447. data/lib/resources/oracledb_session.rb +139 -139
  448. data/lib/resources/os.rb +36 -36
  449. data/lib/resources/os_env.rb +86 -86
  450. data/lib/resources/package.rb +370 -370
  451. data/lib/resources/packages.rb +111 -111
  452. data/lib/resources/parse_config.rb +112 -112
  453. data/lib/resources/passwd.rb +76 -76
  454. data/lib/resources/pip.rb +130 -130
  455. data/lib/resources/platform.rb +109 -109
  456. data/lib/resources/port.rb +771 -771
  457. data/lib/resources/postgres.rb +131 -131
  458. data/lib/resources/postgres_conf.rb +114 -114
  459. data/lib/resources/postgres_hba_conf.rb +90 -90
  460. data/lib/resources/postgres_ident_conf.rb +79 -79
  461. data/lib/resources/postgres_session.rb +71 -71
  462. data/lib/resources/powershell.rb +67 -67
  463. data/lib/resources/processes.rb +204 -204
  464. data/lib/resources/rabbitmq_conf.rb +51 -51
  465. data/lib/resources/registry_key.rb +297 -297
  466. data/lib/resources/security_policy.rb +180 -180
  467. data/lib/resources/service.rb +794 -794
  468. data/lib/resources/shadow.rb +159 -159
  469. data/lib/resources/ssh_conf.rb +97 -97
  470. data/lib/resources/ssl.rb +99 -99
  471. data/lib/resources/sys_info.rb +28 -28
  472. data/lib/resources/toml.rb +32 -32
  473. data/lib/resources/users.rb +654 -654
  474. data/lib/resources/vbscript.rb +68 -68
  475. data/lib/resources/virtualization.rb +247 -247
  476. data/lib/resources/windows_feature.rb +84 -84
  477. data/lib/resources/windows_hotfix.rb +35 -35
  478. data/lib/resources/windows_task.rb +102 -102
  479. data/lib/resources/wmi.rb +110 -110
  480. data/lib/resources/x509_certificate.rb +137 -137
  481. data/lib/resources/xinetd.rb +106 -106
  482. data/lib/resources/xml.rb +46 -46
  483. data/lib/resources/yaml.rb +43 -43
  484. data/lib/resources/yum.rb +180 -180
  485. data/lib/resources/zfs_dataset.rb +60 -60
  486. data/lib/resources/zfs_pool.rb +49 -49
  487. data/lib/source_readers/flat.rb +39 -39
  488. data/lib/source_readers/inspec.rb +75 -75
  489. data/lib/utils/command_wrapper.rb +27 -27
  490. data/lib/utils/convert.rb +12 -12
  491. data/lib/utils/database_helpers.rb +77 -77
  492. data/lib/utils/enumerable_delegation.rb +9 -9
  493. data/lib/utils/erlang_parser.rb +192 -192
  494. data/lib/utils/file_reader.rb +25 -25
  495. data/lib/utils/filter.rb +273 -273
  496. data/lib/utils/filter_array.rb +27 -27
  497. data/lib/utils/find_files.rb +47 -47
  498. data/lib/utils/hash.rb +41 -41
  499. data/lib/utils/json_log.rb +18 -18
  500. data/lib/utils/latest_version.rb +22 -22
  501. data/lib/utils/modulator.rb +12 -12
  502. data/lib/utils/nginx_parser.rb +105 -105
  503. data/lib/utils/object_traversal.rb +49 -49
  504. data/lib/utils/parser.rb +274 -274
  505. data/lib/utils/pkey_reader.rb +15 -15
  506. data/lib/utils/plugin_registry.rb +93 -93
  507. data/lib/utils/simpleconfig.rb +120 -120
  508. data/lib/utils/spdx.rb +13 -13
  509. data/lib/utils/spdx.txt +343 -343
  510. metadata +3 -3
@@ -1,377 +1,377 @@
1
- # Base class for Azure Resources. This allows the generic class to work
2
- # as well as the specific target resources for Azure Resources
3
- #
4
- # @author Russell Seymour
5
- module Inspec::Resources
6
- class AzureResourceBase < Inspec.resource(1)
7
- attr_reader :opts, :client, :azure
8
-
9
- # Constructor that retreives the specified resource
10
- #
11
- # The opts hash should contain the following
12
- # :group_name - name of the resource group in which to look for items
13
- # :type - the type of Azure resource to look for
14
- # :apiversion - API version to use when looking for a specific resource
15
- # :name - name of the resource to find
16
- #
17
- # @author Russell Seymour
18
- #
19
- # @param [Hash] opts Hashtable of options as highlighted above
20
- # rubocop:disable Metrics/AbcSize
21
- def initialize(opts)
22
- # declare the hashtable of counts
23
- @counts = {}
24
- @total = 0
25
- @opts = opts
26
-
27
- # Determine if the environment variables for the options have been set
28
- option_var_names = {
29
- group_name: 'AZURE_RESOURCE_GROUP_NAME',
30
- name: 'AZURE_RESOURCE_NAME',
31
- type: 'AZURE_RESOURCE_TYPE',
32
- apiversion: 'AZURE_RESOURCE_API_VERSION',
33
- }
34
- option_var_names.each do |option_name, env_var_name|
35
- opts[option_name] = ENV[env_var_name] unless ENV[env_var_name].nil?
36
- end
37
-
38
- @azure = inspec.backend
39
- @client = azure.azure_client
40
- @failed_resource = false
41
- end
42
-
43
- def failed_resource?
44
- @failed_resource
45
- end
46
-
47
- def catch_azure_errors
48
- yield
49
- rescue MsRestAzure::AzureOperationError => e
50
- # e.message is actually a massive stringified JSON, which might be useful in the future.
51
- # You want error_message here.
52
- fail_resource e.error_message
53
- @failed_resource = true
54
- nil
55
- end
56
-
57
- # Return information about the resource group
58
- def resource_group
59
- catch_azure_errors do
60
- resource_group = client.resource_groups.get(opts[:group_name])
61
-
62
- # create the methods for the resource group object
63
- dm = AzureResourceDynamicMethods.new
64
- dm.create_methods(self, resource_group)
65
- end
66
- end
67
-
68
- def resources
69
- resources = nil
70
- catch_azure_errors do
71
- resources = client.resources.list_by_resource_group(opts[:group_name])
72
- end
73
- return if failed_resource?
74
-
75
- # filter the resources based on the type, and the name if they been specified
76
- resources = filter_resources(resources, opts)
77
-
78
- # if there is one resource then define methods on this class
79
- if resources.count == 1
80
- @total = 1
81
-
82
- resource = nil
83
- catch_azure_errors do
84
- # get the apiversion for the resource, if one has not been specified
85
- apiversion = azure.get_api_version(resources[0].type, opts)
86
-
87
- # get the resource by id so it can be interrogated
88
- resource = client.resources.get_by_id(resources[0].id, apiversion)
89
- end
90
- return if failed_resource?
91
-
92
- dm = AzureResourceDynamicMethods.new
93
-
94
- dm.create_methods(self, resource)
95
- else
96
-
97
- # As there are many resources, parse each one so that it can be
98
- # interrogated by the FilterTable
99
- # @probes = parse_resources(resources, azure)
100
- @probes = resources.each.map do |item|
101
- # update the total
102
- @total += 1
103
-
104
- # determine the counts for each type
105
- namespace, type_name = item.type.split(/\./)
106
- counts.key?(namespace) ? false : counts[namespace] = {}
107
- counts[namespace].key?(type_name) ? counts[namespace][type_name] += 1 : counts[namespace][type_name] = 1
108
-
109
- # get the detail about the resource
110
- apiversion = azure.get_api_version(item.type, opts)
111
- resource = client.resources.get_by_id(item.id, apiversion)
112
-
113
- # parse the resource
114
- parse_resource(resource)
115
- end.compact
116
-
117
- # Iterate around the counts and create the necessary classes
118
- counts.each do |namespace, ns_counts|
119
- define_singleton_method namespace do
120
- AzureResourceTypeCounts.new(ns_counts)
121
- end
122
- end
123
- end
124
- end
125
-
126
- # Does the resource have any tags?
127
- #
128
- # If it is a Hashtable then it does not, because there was nothing to parse so there is not
129
- # a nested object to work with
130
- #
131
- # @author Russell Seymour
132
- def has_tags?
133
- tags.is_a?(Hash) ? false : true
134
- end
135
-
136
- # Returns how many tags have been set on the resource
137
- #
138
- # @author Russell Seymour
139
- def tag_count
140
- tags.count
141
- end
142
-
143
- # It is necessary to be able to test the tags of a resource. It is possible to say of the
144
- # resource has tags or not, and it is possible to check that the tags include a specific tag
145
- # However the value is not accessible, this function creates methods for all the tags that
146
- # are available.
147
- #
148
- # The format of the method name is '<TAG_NAME>_tag' and will return the value of that tag
149
- #
150
- # Disabling rubopcop check. If this is set as a normal if..then..end statement there is a
151
- # violation stating it should use a guard. When using a guard it throws this error
152
- #
153
- # @author Russell Seymour
154
- def create_tag_methods
155
- # Iterate around the items of the tags and create the necessary access methods
156
- tags.item.each do |name, value|
157
- method_name = format('%s_tag', name)
158
- define_singleton_method method_name do
159
- value
160
- end
161
- end if defined?(tags.item)
162
- end
163
-
164
- private
165
-
166
- # Filter the resources that are returned by the options that have been specified
167
- #
168
- def filter_resources(resources, opts)
169
- if opts[:type] && opts[:name]
170
- resources.select { |r| r.type == opts[:type] && r.name == opts[:name] }
171
- elsif opts[:type]
172
- resources.select { |r| r.type == opts[:type] }
173
- elsif opts[:name]
174
- resources.select { |r| r.name == opts[:name] }
175
- else
176
- resources
177
- end
178
- end
179
- end
180
- end
181
-
182
- # Class to create methods on the calling object at run time.
183
- # Each of the Azure Resources have different attributes and properties, and they all need
184
- # to be testable. To do this no methods are hardcoded, each on is craeted based on the
185
- # information returned from Azure.
186
- #
187
- # The class is a helper class essentially as it creates the methods on the calling class
188
- # rather than itself. This means that there is less duplication of code and it can be
189
- # reused easily.
190
- #
191
- # @author Russell Seymour
192
- # @since 0.2.0
193
- class AzureResourceDynamicMethods
194
- # Given the calling object and its data, create the methods on the object according
195
- # to the data that has been retrieved. Various types of data can be returned so the method
196
- # checks the type to ensure that the necessary methods are configured correctly
197
- #
198
- # @param AzureResourceProbe|AzureResource object The object on which the methods should be craeted
199
- # @param variant data The data from which the methods should be created
200
- def create_methods(object, data)
201
- # Check the type of data as this affects the setup of the methods
202
- # If it is an Azure Generic Resource then setup methods for each of
203
- # the instance variables
204
- case data.class.to_s
205
- when /^Azure::Resources::Mgmt::.*::Models::GenericResource$/,
206
- /^Azure::Resources::Mgmt::.*::Models::ResourceGroup$/
207
- # iterate around the instance variables
208
- data.instance_variables.each do |var|
209
- create_method(object, var.to_s.delete('@'), data.instance_variable_get(var))
210
- end
211
- # When the data is a Hash object iterate around each of the key value pairs and
212
- # craete a method for each one.
213
- when 'Hash'
214
- data.each do |key, value|
215
- create_method(object, key, value)
216
- end
217
- end
218
- end
219
-
220
- private
221
-
222
- # Method that is responsible for creating the method on the calling object. This is
223
- # because some nesting maybe required. For example of the value is a Hash then it will
224
- # need to have an AzureResourceProbe create for each key, whereas if it is a simple
225
- # string then the value just needs to be returned
226
- #
227
- # @private
228
- #
229
- # @param AzureResourceProbe|AzureResource object Object on which the methods need to be created
230
- # @param string name The name of the method
231
- # @param variant value The value that needs to be returned by the method
232
- def create_method(object, name, value)
233
- # Create the necessary method based on the var that has been passed
234
- # Test the value for its type so that the method can be setup correctly
235
- case value.class.to_s
236
- when 'String', 'Integer', 'TrueClass', 'FalseClass', 'Fixnum'
237
- object.define_singleton_method name do
238
- value
239
- end
240
- when 'Hash'
241
- value.count.zero? ? return_value = value : return_value = AzureResourceProbe.new(value)
242
- object.define_singleton_method name do
243
- return_value
244
- end
245
- when /^Azure::Resources::Mgmt::.*::Models::ResourceGroupProperties$/
246
- # This is a special case where the properties of the resource group is not a simple JSON model
247
- # This is because the plugin is using the Azure SDK to get this information so it is an SDK object
248
- # that has to be interrogated in a different way. This is the only object type that behaves like this
249
- value.instance_variables.each do |var|
250
- create_method(object, var.to_s.delete('@'), value.instance_variable_get(var))
251
- end
252
- when 'Array'
253
- # Some things are just string or integer arrays
254
- # Check this by seeing if the first element is a string / integer / boolean or
255
- # a hashtable
256
- # This may not be the best methid, but short of testing all elements in the array, this is
257
- # the quickest test
258
- case value[0].class.to_s
259
- when 'String', 'Integer', 'TrueClass', 'FalseClass', 'Fixnum'
260
- probes = value
261
- else
262
- probes = []
263
- value.each do |value_item|
264
- probes << AzureResourceProbe.new(value_item)
265
- end
266
- end
267
- object.define_singleton_method name do
268
- probes
269
- end
270
- end
271
- end
272
- end
273
-
274
- # Class object to maintain a count of the Azure Resource types that are found
275
- # when a less specific test is carried out. For example if all the resoures of a resource
276
- # group are called for, there will be variaous types and number of those types.
277
- #
278
- # Each type is namespaced, so for example a virtual machine has the type 'Microsoft.Compute/virtualMachines'
279
- # This is broken down into the 'Microsoft' class with the type 'Compute/virtualMachines'
280
- # This has been done for two reasons:
281
- # 1. Enable the dotted notation to work in the test
282
- # 2. Allow third party resource types ot be catered for if they are ever enabled by Microsoft
283
- #
284
- # @author Russell Seymour
285
- # @since 0.2.0
286
- class AzureResourceTypeCounts
287
- # Constructor to setup a new class for a specific Azure Resource type.
288
- # It should be passed a hashtable with information such as:
289
- # {
290
- # "Compute/virtualMachines" => 2,
291
- # "Network/networkInterfaces" => 3
292
- # }
293
- # This will result in two methods being created on the class:
294
- # - Compute/virtualNetworks
295
- # - Network/networkInterfaces
296
- # Each of which will return the corresponding count value
297
- #
298
- # @param Hash counts Hash table of types and the count of each one
299
- #
300
- # @return AzureResourceTypeCounts
301
- def initialize(counts)
302
- counts.each do |type, count|
303
- define_singleton_method type do
304
- count
305
- end
306
- end
307
- end
308
- end
309
-
310
- # Class object that is created for each element that is returned by Azure.
311
- # This is what is interogated by Inspec. If they are nested hashes, then this results
312
- # in nested AzureResourceProbe objects.
313
- #
314
- # For example, if the following was seen in an Azure Resource
315
- # properties -> storageProfile -> imageReference
316
- # Would result in the following nestec classes
317
- # AzureResource -> AzureResourceProbe -> AzureResourceProbe
318
- #
319
- # The methods for each of the classes are dynamically defined at run time and will
320
- # match the items that are retrieved from Azure. See the 'test/integration/verify/controls' for
321
- # examples
322
- #
323
- # This class will not be called externally
324
- #
325
- # @author Russell Seymour
326
- # @since 0.2.0
327
- # @attr_reader string name Name of the Azure resource
328
- # @attr_reader string type Type of the Azure Resource
329
- # @attr_reader string location Location in Azure of the resource
330
- class AzureResourceProbe
331
- attr_reader :name, :type, :location, :item, :count
332
-
333
- # Initialize method for the class. Accepts an item, be it a scalar value, hash or Azure object
334
- # It will then create the necessary dynamic methods so that they can be called in the tests
335
- # This is accomplished by call the AzureResourceDynamicMethods
336
- #
337
- # @param varaint The item from which the class will be initialized
338
- #
339
- # @return AzureResourceProbe
340
- def initialize(item)
341
- dm = AzureResourceDynamicMethods.new
342
- dm.create_methods(self, item)
343
-
344
- # Set the item as a property on the class
345
- # This is so that it is possible to interrogate what has been added to the class and isolate them from
346
- # the standard methods that a Ruby class has.
347
- # This used for checking Tags on a resource for example
348
- # It also allows direct access if so required
349
- @item = item
350
-
351
- # Set how many items have been set
352
- @count = item.length
353
- end
354
-
355
- # Allows resources to respond to the include test
356
- # This means that things like tags can be checked for and then their value tested
357
- #
358
- # @author Russell Seymour
359
- #
360
- # @param [String] key Name of the item to look for in the @item property
361
- def include?(key)
362
- @item.key?(key)
363
- end
364
-
365
- # Give a sting like `computer_name` return the camelCase version, e.g.
366
- # computerName
367
- #
368
- # @param string data Data that needs to be converted from snake_case to camelCase
369
- #
370
- # @return string
371
- def camel_case(data)
372
- camel_case_data = data.split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
373
-
374
- # Ensure that gb (as in gigabytes) is uppercased
375
- camel_case_data.gsub(/[gb]/, &:upcase)
376
- end
377
- end
1
+ # Base class for Azure Resources. This allows the generic class to work
2
+ # as well as the specific target resources for Azure Resources
3
+ #
4
+ # @author Russell Seymour
5
+ module Inspec::Resources
6
+ class AzureResourceBase < Inspec.resource(1)
7
+ attr_reader :opts, :client, :azure
8
+
9
+ # Constructor that retreives the specified resource
10
+ #
11
+ # The opts hash should contain the following
12
+ # :group_name - name of the resource group in which to look for items
13
+ # :type - the type of Azure resource to look for
14
+ # :apiversion - API version to use when looking for a specific resource
15
+ # :name - name of the resource to find
16
+ #
17
+ # @author Russell Seymour
18
+ #
19
+ # @param [Hash] opts Hashtable of options as highlighted above
20
+ # rubocop:disable Metrics/AbcSize
21
+ def initialize(opts)
22
+ # declare the hashtable of counts
23
+ @counts = {}
24
+ @total = 0
25
+ @opts = opts
26
+
27
+ # Determine if the environment variables for the options have been set
28
+ option_var_names = {
29
+ group_name: 'AZURE_RESOURCE_GROUP_NAME',
30
+ name: 'AZURE_RESOURCE_NAME',
31
+ type: 'AZURE_RESOURCE_TYPE',
32
+ apiversion: 'AZURE_RESOURCE_API_VERSION',
33
+ }
34
+ option_var_names.each do |option_name, env_var_name|
35
+ opts[option_name] = ENV[env_var_name] unless ENV[env_var_name].nil?
36
+ end
37
+
38
+ @azure = inspec.backend
39
+ @client = azure.azure_client
40
+ @failed_resource = false
41
+ end
42
+
43
+ def failed_resource?
44
+ @failed_resource
45
+ end
46
+
47
+ def catch_azure_errors
48
+ yield
49
+ rescue MsRestAzure::AzureOperationError => e
50
+ # e.message is actually a massive stringified JSON, which might be useful in the future.
51
+ # You want error_message here.
52
+ fail_resource e.error_message
53
+ @failed_resource = true
54
+ nil
55
+ end
56
+
57
+ # Return information about the resource group
58
+ def resource_group
59
+ catch_azure_errors do
60
+ resource_group = client.resource_groups.get(opts[:group_name])
61
+
62
+ # create the methods for the resource group object
63
+ dm = AzureResourceDynamicMethods.new
64
+ dm.create_methods(self, resource_group)
65
+ end
66
+ end
67
+
68
+ def resources
69
+ resources = nil
70
+ catch_azure_errors do
71
+ resources = client.resources.list_by_resource_group(opts[:group_name])
72
+ end
73
+ return if failed_resource?
74
+
75
+ # filter the resources based on the type, and the name if they been specified
76
+ resources = filter_resources(resources, opts)
77
+
78
+ # if there is one resource then define methods on this class
79
+ if resources.count == 1
80
+ @total = 1
81
+
82
+ resource = nil
83
+ catch_azure_errors do
84
+ # get the apiversion for the resource, if one has not been specified
85
+ apiversion = azure.get_api_version(resources[0].type, opts)
86
+
87
+ # get the resource by id so it can be interrogated
88
+ resource = client.resources.get_by_id(resources[0].id, apiversion)
89
+ end
90
+ return if failed_resource?
91
+
92
+ dm = AzureResourceDynamicMethods.new
93
+
94
+ dm.create_methods(self, resource)
95
+ else
96
+
97
+ # As there are many resources, parse each one so that it can be
98
+ # interrogated by the FilterTable
99
+ # @probes = parse_resources(resources, azure)
100
+ @probes = resources.each.map do |item|
101
+ # update the total
102
+ @total += 1
103
+
104
+ # determine the counts for each type
105
+ namespace, type_name = item.type.split(/\./)
106
+ counts.key?(namespace) ? false : counts[namespace] = {}
107
+ counts[namespace].key?(type_name) ? counts[namespace][type_name] += 1 : counts[namespace][type_name] = 1
108
+
109
+ # get the detail about the resource
110
+ apiversion = azure.get_api_version(item.type, opts)
111
+ resource = client.resources.get_by_id(item.id, apiversion)
112
+
113
+ # parse the resource
114
+ parse_resource(resource)
115
+ end.compact
116
+
117
+ # Iterate around the counts and create the necessary classes
118
+ counts.each do |namespace, ns_counts|
119
+ define_singleton_method namespace do
120
+ AzureResourceTypeCounts.new(ns_counts)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ # Does the resource have any tags?
127
+ #
128
+ # If it is a Hashtable then it does not, because there was nothing to parse so there is not
129
+ # a nested object to work with
130
+ #
131
+ # @author Russell Seymour
132
+ def has_tags?
133
+ tags.is_a?(Hash) ? false : true
134
+ end
135
+
136
+ # Returns how many tags have been set on the resource
137
+ #
138
+ # @author Russell Seymour
139
+ def tag_count
140
+ tags.count
141
+ end
142
+
143
+ # It is necessary to be able to test the tags of a resource. It is possible to say of the
144
+ # resource has tags or not, and it is possible to check that the tags include a specific tag
145
+ # However the value is not accessible, this function creates methods for all the tags that
146
+ # are available.
147
+ #
148
+ # The format of the method name is '<TAG_NAME>_tag' and will return the value of that tag
149
+ #
150
+ # Disabling rubopcop check. If this is set as a normal if..then..end statement there is a
151
+ # violation stating it should use a guard. When using a guard it throws this error
152
+ #
153
+ # @author Russell Seymour
154
+ def create_tag_methods
155
+ # Iterate around the items of the tags and create the necessary access methods
156
+ tags.item.each do |name, value|
157
+ method_name = format('%s_tag', name)
158
+ define_singleton_method method_name do
159
+ value
160
+ end
161
+ end if defined?(tags.item)
162
+ end
163
+
164
+ private
165
+
166
+ # Filter the resources that are returned by the options that have been specified
167
+ #
168
+ def filter_resources(resources, opts)
169
+ if opts[:type] && opts[:name]
170
+ resources.select { |r| r.type == opts[:type] && r.name == opts[:name] }
171
+ elsif opts[:type]
172
+ resources.select { |r| r.type == opts[:type] }
173
+ elsif opts[:name]
174
+ resources.select { |r| r.name == opts[:name] }
175
+ else
176
+ resources
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ # Class to create methods on the calling object at run time.
183
+ # Each of the Azure Resources have different attributes and properties, and they all need
184
+ # to be testable. To do this no methods are hardcoded, each on is craeted based on the
185
+ # information returned from Azure.
186
+ #
187
+ # The class is a helper class essentially as it creates the methods on the calling class
188
+ # rather than itself. This means that there is less duplication of code and it can be
189
+ # reused easily.
190
+ #
191
+ # @author Russell Seymour
192
+ # @since 0.2.0
193
+ class AzureResourceDynamicMethods
194
+ # Given the calling object and its data, create the methods on the object according
195
+ # to the data that has been retrieved. Various types of data can be returned so the method
196
+ # checks the type to ensure that the necessary methods are configured correctly
197
+ #
198
+ # @param AzureResourceProbe|AzureResource object The object on which the methods should be craeted
199
+ # @param variant data The data from which the methods should be created
200
+ def create_methods(object, data)
201
+ # Check the type of data as this affects the setup of the methods
202
+ # If it is an Azure Generic Resource then setup methods for each of
203
+ # the instance variables
204
+ case data.class.to_s
205
+ when /^Azure::Resources::Mgmt::.*::Models::GenericResource$/,
206
+ /^Azure::Resources::Mgmt::.*::Models::ResourceGroup$/
207
+ # iterate around the instance variables
208
+ data.instance_variables.each do |var|
209
+ create_method(object, var.to_s.delete('@'), data.instance_variable_get(var))
210
+ end
211
+ # When the data is a Hash object iterate around each of the key value pairs and
212
+ # craete a method for each one.
213
+ when 'Hash'
214
+ data.each do |key, value|
215
+ create_method(object, key, value)
216
+ end
217
+ end
218
+ end
219
+
220
+ private
221
+
222
+ # Method that is responsible for creating the method on the calling object. This is
223
+ # because some nesting maybe required. For example of the value is a Hash then it will
224
+ # need to have an AzureResourceProbe create for each key, whereas if it is a simple
225
+ # string then the value just needs to be returned
226
+ #
227
+ # @private
228
+ #
229
+ # @param AzureResourceProbe|AzureResource object Object on which the methods need to be created
230
+ # @param string name The name of the method
231
+ # @param variant value The value that needs to be returned by the method
232
+ def create_method(object, name, value)
233
+ # Create the necessary method based on the var that has been passed
234
+ # Test the value for its type so that the method can be setup correctly
235
+ case value.class.to_s
236
+ when 'String', 'Integer', 'TrueClass', 'FalseClass', 'Fixnum'
237
+ object.define_singleton_method name do
238
+ value
239
+ end
240
+ when 'Hash'
241
+ value.count.zero? ? return_value = value : return_value = AzureResourceProbe.new(value)
242
+ object.define_singleton_method name do
243
+ return_value
244
+ end
245
+ when /^Azure::Resources::Mgmt::.*::Models::ResourceGroupProperties$/
246
+ # This is a special case where the properties of the resource group is not a simple JSON model
247
+ # This is because the plugin is using the Azure SDK to get this information so it is an SDK object
248
+ # that has to be interrogated in a different way. This is the only object type that behaves like this
249
+ value.instance_variables.each do |var|
250
+ create_method(object, var.to_s.delete('@'), value.instance_variable_get(var))
251
+ end
252
+ when 'Array'
253
+ # Some things are just string or integer arrays
254
+ # Check this by seeing if the first element is a string / integer / boolean or
255
+ # a hashtable
256
+ # This may not be the best methid, but short of testing all elements in the array, this is
257
+ # the quickest test
258
+ case value[0].class.to_s
259
+ when 'String', 'Integer', 'TrueClass', 'FalseClass', 'Fixnum'
260
+ probes = value
261
+ else
262
+ probes = []
263
+ value.each do |value_item|
264
+ probes << AzureResourceProbe.new(value_item)
265
+ end
266
+ end
267
+ object.define_singleton_method name do
268
+ probes
269
+ end
270
+ end
271
+ end
272
+ end
273
+
274
+ # Class object to maintain a count of the Azure Resource types that are found
275
+ # when a less specific test is carried out. For example if all the resoures of a resource
276
+ # group are called for, there will be variaous types and number of those types.
277
+ #
278
+ # Each type is namespaced, so for example a virtual machine has the type 'Microsoft.Compute/virtualMachines'
279
+ # This is broken down into the 'Microsoft' class with the type 'Compute/virtualMachines'
280
+ # This has been done for two reasons:
281
+ # 1. Enable the dotted notation to work in the test
282
+ # 2. Allow third party resource types ot be catered for if they are ever enabled by Microsoft
283
+ #
284
+ # @author Russell Seymour
285
+ # @since 0.2.0
286
+ class AzureResourceTypeCounts
287
+ # Constructor to setup a new class for a specific Azure Resource type.
288
+ # It should be passed a hashtable with information such as:
289
+ # {
290
+ # "Compute/virtualMachines" => 2,
291
+ # "Network/networkInterfaces" => 3
292
+ # }
293
+ # This will result in two methods being created on the class:
294
+ # - Compute/virtualNetworks
295
+ # - Network/networkInterfaces
296
+ # Each of which will return the corresponding count value
297
+ #
298
+ # @param Hash counts Hash table of types and the count of each one
299
+ #
300
+ # @return AzureResourceTypeCounts
301
+ def initialize(counts)
302
+ counts.each do |type, count|
303
+ define_singleton_method type do
304
+ count
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ # Class object that is created for each element that is returned by Azure.
311
+ # This is what is interogated by Inspec. If they are nested hashes, then this results
312
+ # in nested AzureResourceProbe objects.
313
+ #
314
+ # For example, if the following was seen in an Azure Resource
315
+ # properties -> storageProfile -> imageReference
316
+ # Would result in the following nestec classes
317
+ # AzureResource -> AzureResourceProbe -> AzureResourceProbe
318
+ #
319
+ # The methods for each of the classes are dynamically defined at run time and will
320
+ # match the items that are retrieved from Azure. See the 'test/integration/verify/controls' for
321
+ # examples
322
+ #
323
+ # This class will not be called externally
324
+ #
325
+ # @author Russell Seymour
326
+ # @since 0.2.0
327
+ # @attr_reader string name Name of the Azure resource
328
+ # @attr_reader string type Type of the Azure Resource
329
+ # @attr_reader string location Location in Azure of the resource
330
+ class AzureResourceProbe
331
+ attr_reader :name, :type, :location, :item, :count
332
+
333
+ # Initialize method for the class. Accepts an item, be it a scalar value, hash or Azure object
334
+ # It will then create the necessary dynamic methods so that they can be called in the tests
335
+ # This is accomplished by call the AzureResourceDynamicMethods
336
+ #
337
+ # @param varaint The item from which the class will be initialized
338
+ #
339
+ # @return AzureResourceProbe
340
+ def initialize(item)
341
+ dm = AzureResourceDynamicMethods.new
342
+ dm.create_methods(self, item)
343
+
344
+ # Set the item as a property on the class
345
+ # This is so that it is possible to interrogate what has been added to the class and isolate them from
346
+ # the standard methods that a Ruby class has.
347
+ # This used for checking Tags on a resource for example
348
+ # It also allows direct access if so required
349
+ @item = item
350
+
351
+ # Set how many items have been set
352
+ @count = item.length
353
+ end
354
+
355
+ # Allows resources to respond to the include test
356
+ # This means that things like tags can be checked for and then their value tested
357
+ #
358
+ # @author Russell Seymour
359
+ #
360
+ # @param [String] key Name of the item to look for in the @item property
361
+ def include?(key)
362
+ @item.key?(key)
363
+ end
364
+
365
+ # Give a sting like `computer_name` return the camelCase version, e.g.
366
+ # computerName
367
+ #
368
+ # @param string data Data that needs to be converted from snake_case to camelCase
369
+ #
370
+ # @return string
371
+ def camel_case(data)
372
+ camel_case_data = data.split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
373
+
374
+ # Ensure that gb (as in gigabytes) is uppercased
375
+ camel_case_data.gsub(/[gb]/, &:upcase)
376
+ end
377
+ end