inspec 2.0.16 → 2.0.17

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 (480) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +101 -101
  3. data/CHANGELOG.md +2949 -2944
  4. data/Gemfile +55 -55
  5. data/LICENSE +14 -14
  6. data/MAINTAINERS.md +31 -31
  7. data/MAINTAINERS.toml +47 -47
  8. data/README.md +438 -438
  9. data/Rakefile +284 -284
  10. data/bin/inspec +12 -12
  11. data/docs/.gitignore +2 -2
  12. data/docs/README.md +40 -40
  13. data/docs/dsl_inspec.md +258 -258
  14. data/docs/dsl_resource.md +93 -93
  15. data/docs/glossary.md +99 -99
  16. data/docs/habitat.md +191 -191
  17. data/docs/inspec_and_friends.md +107 -107
  18. data/docs/matchers.md +165 -165
  19. data/docs/migration.md +293 -293
  20. data/docs/platforms.md +118 -118
  21. data/docs/plugin_kitchen_inspec.md +49 -49
  22. data/docs/profiles.md +370 -370
  23. data/docs/reporters.md +105 -105
  24. data/docs/resources/aide_conf.md.erb +75 -75
  25. data/docs/resources/apache.md.erb +67 -67
  26. data/docs/resources/apache_conf.md.erb +68 -68
  27. data/docs/resources/apt.md.erb +71 -71
  28. data/docs/resources/audit_policy.md.erb +47 -47
  29. data/docs/resources/auditd.md.erb +79 -79
  30. data/docs/resources/auditd_conf.md.erb +68 -68
  31. data/docs/resources/aws_cloudtrail_trail.md.erb +140 -140
  32. data/docs/resources/aws_cloudtrail_trails.md.erb +81 -81
  33. data/docs/resources/aws_cloudwatch_alarm.md.erb +86 -86
  34. data/docs/resources/aws_cloudwatch_log_metric_filter.md.erb +151 -151
  35. data/docs/resources/aws_ec2_instance.md.erb +106 -106
  36. data/docs/resources/aws_iam_access_key.md.erb +123 -123
  37. data/docs/resources/aws_iam_access_keys.md.erb +198 -198
  38. data/docs/resources/aws_iam_group.md.erb +46 -46
  39. data/docs/resources/aws_iam_groups.md.erb +43 -43
  40. data/docs/resources/aws_iam_password_policy.md.erb +76 -76
  41. data/docs/resources/aws_iam_policies.md.erb +82 -82
  42. data/docs/resources/aws_iam_policy.md.erb +146 -146
  43. data/docs/resources/aws_iam_role.md.erb +65 -65
  44. data/docs/resources/aws_iam_root_user.md.erb +58 -58
  45. data/docs/resources/aws_iam_user.md.erb +64 -64
  46. data/docs/resources/aws_iam_users.md.erb +89 -89
  47. data/docs/resources/aws_kms_keys.md.erb +84 -84
  48. data/docs/resources/aws_route_table.md.erb +47 -47
  49. data/docs/resources/aws_s3_bucket.md.erb +134 -134
  50. data/docs/resources/aws_security_group.md.erb +152 -152
  51. data/docs/resources/aws_security_groups.md.erb +92 -92
  52. data/docs/resources/aws_sns_topic.md.erb +62 -62
  53. data/docs/resources/aws_subnet.md.erb +133 -133
  54. data/docs/resources/aws_subnets.md.erb +126 -126
  55. data/docs/resources/aws_vpc.md.erb +120 -120
  56. data/docs/resources/aws_vpcs.md.erb +48 -48
  57. data/docs/resources/azure_generic_resource.md.erb +170 -139
  58. data/docs/resources/azure_resource_group.md.erb +284 -284
  59. data/docs/resources/azure_virtual_machine.md.erb +347 -314
  60. data/docs/resources/azure_virtual_machine_data_disk.md.erb +224 -182
  61. data/docs/resources/bash.md.erb +75 -75
  62. data/docs/resources/bond.md.erb +90 -90
  63. data/docs/resources/bridge.md.erb +57 -57
  64. data/docs/resources/bsd_service.md.erb +67 -67
  65. data/docs/resources/command.md.erb +138 -138
  66. data/docs/resources/cpan.md.erb +79 -79
  67. data/docs/resources/cran.md.erb +64 -64
  68. data/docs/resources/crontab.md.erb +88 -88
  69. data/docs/resources/csv.md.erb +54 -54
  70. data/docs/resources/dh_params.md.erb +217 -217
  71. data/docs/resources/directory.md.erb +30 -30
  72. data/docs/resources/docker.md.erb +164 -164
  73. data/docs/resources/docker_container.md.erb +104 -104
  74. data/docs/resources/docker_image.md.erb +94 -94
  75. data/docs/resources/docker_service.md.erb +114 -114
  76. data/docs/resources/elasticsearch.md.erb +242 -242
  77. data/docs/resources/etc_fstab.md.erb +125 -125
  78. data/docs/resources/etc_group.md.erb +75 -75
  79. data/docs/resources/etc_hosts.md.erb +78 -78
  80. data/docs/resources/etc_hosts_allow.md.erb +74 -74
  81. data/docs/resources/etc_hosts_deny.md.erb +74 -74
  82. data/docs/resources/file.md.erb +515 -515
  83. data/docs/resources/filesystem.md.erb +41 -41
  84. data/docs/resources/firewalld.md.erb +107 -107
  85. data/docs/resources/gem.md.erb +79 -79
  86. data/docs/resources/group.md.erb +61 -61
  87. data/docs/resources/grub_conf.md.erb +101 -101
  88. data/docs/resources/host.md.erb +78 -78
  89. data/docs/resources/http.md.erb +101 -101
  90. data/docs/resources/iis_app.md.erb +122 -122
  91. data/docs/resources/iis_site.md.erb +135 -135
  92. data/docs/resources/inetd_conf.md.erb +94 -94
  93. data/docs/resources/ini.md.erb +76 -76
  94. data/docs/resources/interface.md.erb +58 -58
  95. data/docs/resources/iptables.md.erb +64 -64
  96. data/docs/resources/json.md.erb +62 -62
  97. data/docs/resources/kernel_module.md.erb +107 -107
  98. data/docs/resources/kernel_parameter.md.erb +53 -53
  99. data/docs/resources/key_rsa.md.erb +85 -85
  100. data/docs/resources/launchd_service.md.erb +57 -57
  101. data/docs/resources/limits_conf.md.erb +75 -75
  102. data/docs/resources/login_def.md.erb +71 -71
  103. data/docs/resources/mount.md.erb +69 -69
  104. data/docs/resources/mssql_session.md.erb +60 -60
  105. data/docs/resources/mysql_conf.md.erb +99 -99
  106. data/docs/resources/mysql_session.md.erb +74 -74
  107. data/docs/resources/nginx.md.erb +79 -79
  108. data/docs/resources/nginx_conf.md.erb +128 -128
  109. data/docs/resources/npm.md.erb +60 -60
  110. data/docs/resources/ntp_conf.md.erb +60 -60
  111. data/docs/resources/oneget.md.erb +53 -53
  112. data/docs/resources/oracledb_session.md.erb +52 -52
  113. data/docs/resources/os.md.erb +141 -141
  114. data/docs/resources/os_env.md.erb +78 -78
  115. data/docs/resources/package.md.erb +120 -120
  116. data/docs/resources/packages.md.erb +67 -67
  117. data/docs/resources/parse_config.md.erb +103 -103
  118. data/docs/resources/parse_config_file.md.erb +138 -138
  119. data/docs/resources/passwd.md.erb +141 -141
  120. data/docs/resources/pip.md.erb +67 -67
  121. data/docs/resources/port.md.erb +137 -137
  122. data/docs/resources/postgres_conf.md.erb +79 -79
  123. data/docs/resources/postgres_hba_conf.md.erb +93 -93
  124. data/docs/resources/postgres_ident_conf.md.erb +76 -76
  125. data/docs/resources/postgres_session.md.erb +69 -69
  126. data/docs/resources/powershell.md.erb +102 -102
  127. data/docs/resources/processes.md.erb +109 -109
  128. data/docs/resources/rabbitmq_config.md.erb +41 -41
  129. data/docs/resources/registry_key.md.erb +158 -158
  130. data/docs/resources/runit_service.md.erb +57 -57
  131. data/docs/resources/security_policy.md.erb +47 -47
  132. data/docs/resources/service.md.erb +121 -121
  133. data/docs/resources/shadow.md.erb +144 -144
  134. data/docs/resources/ssh_config.md.erb +80 -80
  135. data/docs/resources/sshd_config.md.erb +83 -83
  136. data/docs/resources/ssl.md.erb +119 -119
  137. data/docs/resources/sys_info.md.erb +42 -42
  138. data/docs/resources/systemd_service.md.erb +57 -57
  139. data/docs/resources/sysv_service.md.erb +57 -57
  140. data/docs/resources/upstart_service.md.erb +57 -57
  141. data/docs/resources/user.md.erb +140 -140
  142. data/docs/resources/users.md.erb +127 -127
  143. data/docs/resources/vbscript.md.erb +55 -55
  144. data/docs/resources/virtualization.md.erb +57 -57
  145. data/docs/resources/windows_feature.md.erb +47 -47
  146. data/docs/resources/windows_hotfix.md.erb +53 -53
  147. data/docs/resources/windows_task.md.erb +95 -95
  148. data/docs/resources/wmi.md.erb +81 -81
  149. data/docs/resources/x509_certificate.md.erb +151 -151
  150. data/docs/resources/xinetd_conf.md.erb +156 -156
  151. data/docs/resources/xml.md.erb +85 -85
  152. data/docs/resources/yaml.md.erb +69 -69
  153. data/docs/resources/yum.md.erb +98 -98
  154. data/docs/resources/zfs_dataset.md.erb +53 -53
  155. data/docs/resources/zfs_pool.md.erb +47 -47
  156. data/docs/ruby_usage.md +203 -203
  157. data/docs/shared/matcher_be.md.erb +1 -1
  158. data/docs/shared/matcher_cmp.md.erb +43 -43
  159. data/docs/shared/matcher_eq.md.erb +3 -3
  160. data/docs/shared/matcher_include.md.erb +1 -1
  161. data/docs/shared/matcher_match.md.erb +1 -1
  162. data/docs/shell.md +172 -172
  163. data/examples/README.md +8 -8
  164. data/examples/inheritance/README.md +65 -65
  165. data/examples/inheritance/controls/example.rb +14 -14
  166. data/examples/inheritance/inspec.yml +15 -15
  167. data/examples/kitchen-ansible/.kitchen.yml +25 -25
  168. data/examples/kitchen-ansible/Gemfile +19 -19
  169. data/examples/kitchen-ansible/README.md +53 -53
  170. data/examples/kitchen-ansible/files/nginx.repo +6 -6
  171. data/examples/kitchen-ansible/tasks/main.yml +16 -16
  172. data/examples/kitchen-ansible/test/integration/default/default.yml +5 -5
  173. data/examples/kitchen-ansible/test/integration/default/web_spec.rb +28 -28
  174. data/examples/kitchen-chef/.kitchen.yml +20 -20
  175. data/examples/kitchen-chef/Berksfile +3 -3
  176. data/examples/kitchen-chef/Gemfile +19 -19
  177. data/examples/kitchen-chef/README.md +27 -27
  178. data/examples/kitchen-chef/metadata.rb +7 -7
  179. data/examples/kitchen-chef/recipes/default.rb +6 -6
  180. data/examples/kitchen-chef/recipes/nginx.rb +30 -30
  181. data/examples/kitchen-chef/test/integration/default/web_spec.rb +28 -28
  182. data/examples/kitchen-puppet/.kitchen.yml +22 -22
  183. data/examples/kitchen-puppet/Gemfile +20 -20
  184. data/examples/kitchen-puppet/Puppetfile +25 -25
  185. data/examples/kitchen-puppet/README.md +53 -53
  186. data/examples/kitchen-puppet/manifests/site.pp +33 -33
  187. data/examples/kitchen-puppet/metadata.json +11 -11
  188. data/examples/kitchen-puppet/test/integration/default/web_spec.rb +28 -28
  189. data/examples/meta-profile/README.md +37 -37
  190. data/examples/meta-profile/controls/example.rb +13 -13
  191. data/examples/meta-profile/inspec.yml +13 -13
  192. data/examples/profile-attribute.yml +2 -2
  193. data/examples/profile-attribute/README.md +14 -14
  194. data/examples/profile-attribute/controls/example.rb +11 -11
  195. data/examples/profile-attribute/inspec.yml +8 -8
  196. data/examples/profile-aws/controls/iam_password_policy_expiration.rb +8 -8
  197. data/examples/profile-aws/controls/iam_password_policy_max_age.rb +8 -8
  198. data/examples/profile-aws/controls/iam_root_user_mfa.rb +8 -8
  199. data/examples/profile-aws/controls/iam_users_access_key_age.rb +8 -8
  200. data/examples/profile-aws/controls/iam_users_console_users_mfa.rb +8 -8
  201. data/examples/profile-aws/inspec.yml +11 -11
  202. data/examples/profile-azure/controls/azure_resource_group_example.rb +24 -24
  203. data/examples/profile-azure/controls/azure_vm_example.rb +29 -29
  204. data/examples/profile-azure/inspec.yml +11 -11
  205. data/examples/profile-sensitive/README.md +29 -29
  206. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -9
  207. data/examples/profile-sensitive/controls/sensitive.rb +9 -9
  208. data/examples/profile-sensitive/inspec.yml +8 -8
  209. data/examples/profile/README.md +48 -48
  210. data/examples/profile/controls/example.rb +23 -23
  211. data/examples/profile/controls/gordon.rb +36 -36
  212. data/examples/profile/controls/meta.rb +34 -34
  213. data/examples/profile/inspec.yml +10 -10
  214. data/examples/profile/libraries/gordon_config.rb +53 -53
  215. data/inspec.gemspec +47 -47
  216. data/lib/bundles/README.md +3 -3
  217. data/lib/bundles/inspec-artifact.rb +7 -7
  218. data/lib/bundles/inspec-artifact/README.md +1 -1
  219. data/lib/bundles/inspec-artifact/cli.rb +277 -277
  220. data/lib/bundles/inspec-compliance.rb +16 -16
  221. data/lib/bundles/inspec-compliance/.kitchen.yml +20 -20
  222. data/lib/bundles/inspec-compliance/README.md +185 -185
  223. data/lib/bundles/inspec-compliance/api.rb +316 -316
  224. data/lib/bundles/inspec-compliance/api/login.rb +152 -152
  225. data/lib/bundles/inspec-compliance/bootstrap.sh +41 -41
  226. data/lib/bundles/inspec-compliance/cli.rb +254 -254
  227. data/lib/bundles/inspec-compliance/configuration.rb +103 -103
  228. data/lib/bundles/inspec-compliance/http.rb +86 -86
  229. data/lib/bundles/inspec-compliance/support.rb +36 -36
  230. data/lib/bundles/inspec-compliance/target.rb +98 -98
  231. data/lib/bundles/inspec-compliance/test/integration/default/cli.rb +93 -93
  232. data/lib/bundles/inspec-habitat.rb +12 -12
  233. data/lib/bundles/inspec-habitat/cli.rb +36 -36
  234. data/lib/bundles/inspec-habitat/log.rb +10 -10
  235. data/lib/bundles/inspec-habitat/profile.rb +390 -390
  236. data/lib/bundles/inspec-init.rb +8 -8
  237. data/lib/bundles/inspec-init/README.md +31 -31
  238. data/lib/bundles/inspec-init/cli.rb +97 -97
  239. data/lib/bundles/inspec-init/templates/profile/README.md +3 -3
  240. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +19 -19
  241. data/lib/bundles/inspec-init/templates/profile/inspec.yml +8 -8
  242. data/lib/bundles/inspec-supermarket.rb +13 -13
  243. data/lib/bundles/inspec-supermarket/README.md +45 -45
  244. data/lib/bundles/inspec-supermarket/api.rb +84 -84
  245. data/lib/bundles/inspec-supermarket/cli.rb +73 -73
  246. data/lib/bundles/inspec-supermarket/target.rb +34 -34
  247. data/lib/fetchers/git.rb +163 -163
  248. data/lib/fetchers/local.rb +74 -74
  249. data/lib/fetchers/mock.rb +35 -35
  250. data/lib/fetchers/url.rb +204 -204
  251. data/lib/inspec.rb +24 -24
  252. data/lib/inspec/archive/tar.rb +29 -29
  253. data/lib/inspec/archive/zip.rb +19 -19
  254. data/lib/inspec/backend.rb +92 -92
  255. data/lib/inspec/base_cli.rb +350 -333
  256. data/lib/inspec/cached_fetcher.rb +66 -66
  257. data/lib/inspec/cli.rb +292 -302
  258. data/lib/inspec/completions/bash.sh.erb +45 -45
  259. data/lib/inspec/completions/fish.sh.erb +34 -34
  260. data/lib/inspec/completions/zsh.sh.erb +61 -61
  261. data/lib/inspec/control_eval_context.rb +179 -179
  262. data/lib/inspec/dependencies/cache.rb +72 -72
  263. data/lib/inspec/dependencies/dependency_set.rb +92 -92
  264. data/lib/inspec/dependencies/lockfile.rb +115 -115
  265. data/lib/inspec/dependencies/requirement.rb +123 -123
  266. data/lib/inspec/dependencies/resolver.rb +86 -86
  267. data/lib/inspec/describe.rb +27 -27
  268. data/lib/inspec/dsl.rb +66 -66
  269. data/lib/inspec/dsl_shared.rb +33 -33
  270. data/lib/inspec/env_printer.rb +157 -157
  271. data/lib/inspec/errors.rb +13 -13
  272. data/lib/inspec/exceptions.rb +12 -12
  273. data/lib/inspec/expect.rb +45 -45
  274. data/lib/inspec/fetcher.rb +45 -45
  275. data/lib/inspec/file_provider.rb +275 -275
  276. data/lib/inspec/formatters.rb +3 -3
  277. data/lib/inspec/formatters/base.rb +250 -250
  278. data/lib/inspec/formatters/json_rspec.rb +20 -20
  279. data/lib/inspec/formatters/show_progress.rb +12 -12
  280. data/lib/inspec/library_eval_context.rb +58 -58
  281. data/lib/inspec/log.rb +11 -11
  282. data/lib/inspec/metadata.rb +247 -247
  283. data/lib/inspec/method_source.rb +24 -24
  284. data/lib/inspec/objects.rb +14 -14
  285. data/lib/inspec/objects/attribute.rb +65 -65
  286. data/lib/inspec/objects/control.rb +61 -61
  287. data/lib/inspec/objects/describe.rb +92 -92
  288. data/lib/inspec/objects/each_loop.rb +36 -36
  289. data/lib/inspec/objects/list.rb +15 -15
  290. data/lib/inspec/objects/or_test.rb +40 -40
  291. data/lib/inspec/objects/ruby_helper.rb +15 -15
  292. data/lib/inspec/objects/tag.rb +27 -27
  293. data/lib/inspec/objects/test.rb +87 -87
  294. data/lib/inspec/objects/value.rb +27 -27
  295. data/lib/inspec/plugins.rb +60 -60
  296. data/lib/inspec/plugins/cli.rb +24 -24
  297. data/lib/inspec/plugins/fetcher.rb +86 -86
  298. data/lib/inspec/plugins/resource.rb +133 -133
  299. data/lib/inspec/plugins/secret.rb +15 -15
  300. data/lib/inspec/plugins/source_reader.rb +40 -40
  301. data/lib/inspec/polyfill.rb +12 -12
  302. data/lib/inspec/profile.rb +510 -510
  303. data/lib/inspec/profile_context.rb +207 -207
  304. data/lib/inspec/profile_vendor.rb +66 -66
  305. data/lib/inspec/reporters.rb +50 -50
  306. data/lib/inspec/reporters/base.rb +24 -24
  307. data/lib/inspec/reporters/cli.rb +356 -356
  308. data/lib/inspec/reporters/json.rb +116 -116
  309. data/lib/inspec/reporters/json_min.rb +48 -48
  310. data/lib/inspec/reporters/junit.rb +77 -77
  311. data/lib/inspec/require_loader.rb +33 -33
  312. data/lib/inspec/resource.rb +186 -186
  313. data/lib/inspec/rule.rb +266 -266
  314. data/lib/inspec/runner.rb +344 -344
  315. data/lib/inspec/runner_mock.rb +41 -41
  316. data/lib/inspec/runner_rspec.rb +174 -174
  317. data/lib/inspec/runtime_profile.rb +26 -26
  318. data/lib/inspec/schema.rb +213 -213
  319. data/lib/inspec/secrets.rb +19 -19
  320. data/lib/inspec/secrets/yaml.rb +30 -30
  321. data/lib/inspec/shell.rb +220 -223
  322. data/lib/inspec/shell_detector.rb +90 -90
  323. data/lib/inspec/source_reader.rb +29 -29
  324. data/lib/inspec/version.rb +8 -8
  325. data/lib/matchers/matchers.rb +339 -339
  326. data/lib/resource_support/aws.rb +40 -40
  327. data/lib/resource_support/aws/aws_backend_base.rb +12 -12
  328. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +12 -12
  329. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +21 -21
  330. data/lib/resource_support/aws/aws_resource_mixin.rb +66 -66
  331. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +24 -24
  332. data/lib/resources/aide_conf.rb +160 -160
  333. data/lib/resources/apache.rb +48 -48
  334. data/lib/resources/apache_conf.rb +156 -156
  335. data/lib/resources/apt.rb +149 -149
  336. data/lib/resources/audit_policy.rb +63 -63
  337. data/lib/resources/auditd.rb +231 -231
  338. data/lib/resources/auditd_conf.rb +55 -55
  339. data/lib/resources/aws/aws_cloudtrail_trail.rb +77 -77
  340. data/lib/resources/aws/aws_cloudtrail_trails.rb +47 -47
  341. data/lib/resources/aws/aws_cloudwatch_alarm.rb +62 -62
  342. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +100 -100
  343. data/lib/resources/aws/aws_ec2_instance.rb +157 -157
  344. data/lib/resources/aws/aws_iam_access_key.rb +106 -106
  345. data/lib/resources/aws/aws_iam_access_keys.rb +144 -144
  346. data/lib/resources/aws/aws_iam_group.rb +56 -56
  347. data/lib/resources/aws/aws_iam_groups.rb +45 -45
  348. data/lib/resources/aws/aws_iam_password_policy.rb +116 -116
  349. data/lib/resources/aws/aws_iam_policies.rb +46 -46
  350. data/lib/resources/aws/aws_iam_policy.rb +119 -119
  351. data/lib/resources/aws/aws_iam_role.rb +51 -51
  352. data/lib/resources/aws/aws_iam_root_user.rb +60 -60
  353. data/lib/resources/aws/aws_iam_user.rb +111 -111
  354. data/lib/resources/aws/aws_iam_users.rb +96 -96
  355. data/lib/resources/aws/aws_kms_keys.rb +46 -46
  356. data/lib/resources/aws/aws_route_table.rb +61 -61
  357. data/lib/resources/aws/aws_s3_bucket.rb +115 -115
  358. data/lib/resources/aws/aws_security_group.rb +93 -93
  359. data/lib/resources/aws/aws_security_groups.rb +68 -68
  360. data/lib/resources/aws/aws_sns_topic.rb +53 -53
  361. data/lib/resources/aws/aws_subnet.rb +88 -88
  362. data/lib/resources/aws/aws_subnets.rb +53 -53
  363. data/lib/resources/aws/aws_vpc.rb +69 -69
  364. data/lib/resources/aws/aws_vpcs.rb +45 -45
  365. data/lib/resources/azure/azure_backend.rb +377 -377
  366. data/lib/resources/azure/azure_generic_resource.rb +59 -59
  367. data/lib/resources/azure/azure_resource_group.rb +152 -152
  368. data/lib/resources/azure/azure_virtual_machine.rb +264 -264
  369. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +136 -136
  370. data/lib/resources/bash.rb +35 -35
  371. data/lib/resources/bond.rb +68 -68
  372. data/lib/resources/bridge.rb +122 -122
  373. data/lib/resources/command.rb +69 -69
  374. data/lib/resources/cpan.rb +58 -58
  375. data/lib/resources/cran.rb +64 -64
  376. data/lib/resources/crontab.rb +170 -170
  377. data/lib/resources/csv.rb +60 -60
  378. data/lib/resources/dh_params.rb +82 -82
  379. data/lib/resources/directory.rb +25 -25
  380. data/lib/resources/docker.rb +236 -236
  381. data/lib/resources/docker_container.rb +89 -89
  382. data/lib/resources/docker_image.rb +83 -83
  383. data/lib/resources/docker_object.rb +57 -57
  384. data/lib/resources/docker_service.rb +90 -90
  385. data/lib/resources/elasticsearch.rb +169 -169
  386. data/lib/resources/etc_fstab.rb +102 -102
  387. data/lib/resources/etc_group.rb +156 -156
  388. data/lib/resources/etc_hosts.rb +81 -81
  389. data/lib/resources/etc_hosts_allow_deny.rb +123 -123
  390. data/lib/resources/file.rb +298 -298
  391. data/lib/resources/filesystem.rb +31 -31
  392. data/lib/resources/firewalld.rb +144 -144
  393. data/lib/resources/gem.rb +70 -70
  394. data/lib/resources/groups.rb +215 -215
  395. data/lib/resources/grub_conf.rb +237 -237
  396. data/lib/resources/host.rb +300 -300
  397. data/lib/resources/http.rb +250 -250
  398. data/lib/resources/iis_app.rb +104 -104
  399. data/lib/resources/iis_site.rb +148 -148
  400. data/lib/resources/inetd_conf.rb +62 -62
  401. data/lib/resources/ini.rb +29 -29
  402. data/lib/resources/interface.rb +129 -129
  403. data/lib/resources/iptables.rb +69 -69
  404. data/lib/resources/json.rb +117 -117
  405. data/lib/resources/kernel_module.rb +107 -107
  406. data/lib/resources/kernel_parameter.rb +58 -58
  407. data/lib/resources/key_rsa.rb +67 -67
  408. data/lib/resources/limits_conf.rb +55 -55
  409. data/lib/resources/login_def.rb +66 -66
  410. data/lib/resources/mount.rb +88 -88
  411. data/lib/resources/mssql_session.rb +101 -101
  412. data/lib/resources/mysql.rb +81 -81
  413. data/lib/resources/mysql_conf.rb +134 -134
  414. data/lib/resources/mysql_session.rb +71 -71
  415. data/lib/resources/nginx.rb +96 -96
  416. data/lib/resources/nginx_conf.rb +227 -227
  417. data/lib/resources/npm.rb +48 -48
  418. data/lib/resources/ntp_conf.rb +58 -58
  419. data/lib/resources/oneget.rb +71 -71
  420. data/lib/resources/oracledb_session.rb +139 -139
  421. data/lib/resources/os.rb +36 -36
  422. data/lib/resources/os_env.rb +76 -76
  423. data/lib/resources/package.rb +363 -363
  424. data/lib/resources/packages.rb +111 -111
  425. data/lib/resources/parse_config.rb +116 -116
  426. data/lib/resources/passwd.rb +74 -74
  427. data/lib/resources/pip.rb +89 -89
  428. data/lib/resources/platform.rb +109 -109
  429. data/lib/resources/port.rb +771 -771
  430. data/lib/resources/postgres.rb +130 -130
  431. data/lib/resources/postgres_conf.rb +121 -121
  432. data/lib/resources/postgres_hba_conf.rb +100 -100
  433. data/lib/resources/postgres_ident_conf.rb +78 -78
  434. data/lib/resources/postgres_session.rb +71 -71
  435. data/lib/resources/powershell.rb +57 -57
  436. data/lib/resources/processes.rb +204 -204
  437. data/lib/resources/rabbitmq_conf.rb +52 -52
  438. data/lib/resources/registry_key.rb +296 -296
  439. data/lib/resources/security_policy.rb +180 -180
  440. data/lib/resources/service.rb +789 -789
  441. data/lib/resources/shadow.rb +140 -140
  442. data/lib/resources/ssh_conf.rb +102 -102
  443. data/lib/resources/ssl.rb +99 -99
  444. data/lib/resources/sys_info.rb +28 -28
  445. data/lib/resources/toml.rb +32 -32
  446. data/lib/resources/users.rb +654 -654
  447. data/lib/resources/vbscript.rb +69 -69
  448. data/lib/resources/virtualization.rb +251 -251
  449. data/lib/resources/windows_feature.rb +84 -84
  450. data/lib/resources/windows_hotfix.rb +35 -35
  451. data/lib/resources/windows_task.rb +105 -105
  452. data/lib/resources/wmi.rb +113 -113
  453. data/lib/resources/x509_certificate.rb +143 -143
  454. data/lib/resources/xinetd.rb +111 -111
  455. data/lib/resources/xml.rb +46 -46
  456. data/lib/resources/yaml.rb +47 -47
  457. data/lib/resources/yum.rb +180 -180
  458. data/lib/resources/zfs_dataset.rb +60 -60
  459. data/lib/resources/zfs_pool.rb +49 -49
  460. data/lib/source_readers/flat.rb +39 -39
  461. data/lib/source_readers/inspec.rb +75 -75
  462. data/lib/utils/command_wrapper.rb +27 -27
  463. data/lib/utils/convert.rb +12 -12
  464. data/lib/utils/database_helpers.rb +77 -77
  465. data/lib/utils/erlang_parser.rb +192 -192
  466. data/lib/utils/filter.rb +272 -272
  467. data/lib/utils/filter_array.rb +27 -27
  468. data/lib/utils/find_files.rb +44 -44
  469. data/lib/utils/hash.rb +41 -41
  470. data/lib/utils/json_log.rb +18 -18
  471. data/lib/utils/latest_version.rb +22 -22
  472. data/lib/utils/modulator.rb +12 -12
  473. data/lib/utils/nginx_parser.rb +85 -85
  474. data/lib/utils/object_traversal.rb +49 -49
  475. data/lib/utils/parser.rb +274 -274
  476. data/lib/utils/plugin_registry.rb +93 -93
  477. data/lib/utils/simpleconfig.rb +120 -120
  478. data/lib/utils/spdx.rb +13 -13
  479. data/lib/utils/spdx.txt +343 -343
  480. metadata +1 -1
@@ -1,180 +1,180 @@
1
- # encoding: utf-8
2
- #
3
- # Security Configuration and Analysis
4
- #
5
- # Export local security policy:
6
- # secedit /export /cfg secpol.cfg
7
- #
8
- # @link http://www.microsoft.com/en-us/download/details.aspx?id=25250
9
- #
10
- # In Windows, some security options are managed differently that the local GPO
11
- # All local GPO parameters can be examined via Registry, but not all security
12
- # parameters. Therefore we need a combination of Registry and secedit output
13
-
14
- require 'hashie'
15
-
16
- module Inspec::Resources
17
- # known and supported MS privilege rights
18
- # @see https://technet.microsoft.com/en-us/library/dd277311.aspx
19
- # @see https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
20
- MS_PRIVILEGES_RIGHTS = [
21
- 'SeNetworkLogonRight',
22
- 'SeBackupPrivilege',
23
- 'SeChangeNotifyPrivilege',
24
- 'SeSystemtimePrivilege',
25
- 'SeCreatePagefilePrivilege',
26
- 'SeDebugPrivilege',
27
- 'SeRemoteShutdownPrivilege',
28
- 'SeAuditPrivilege',
29
- 'SeIncreaseQuotaPrivilege',
30
- 'SeIncreaseBasePriorityPrivilege',
31
- 'SeLoadDriverPrivilege',
32
- 'SeBatchLogonRight',
33
- 'SeServiceLogonRight',
34
- 'SeInteractiveLogonRight',
35
- 'SeSecurityPrivilege',
36
- 'SeSystemEnvironmentPrivilege',
37
- 'SeProfileSingleProcessPrivilege',
38
- 'SeSystemProfilePrivilege',
39
- 'SeAssignPrimaryTokenPrivilege',
40
- 'SeRestorePrivilege',
41
- 'SeShutdownPrivilege',
42
- 'SeTakeOwnershipPrivilege',
43
- 'SeUndockPrivilege',
44
- 'SeManageVolumePrivilege',
45
- 'SeRemoteInteractiveLogonRight',
46
- 'SeImpersonatePrivilege',
47
- 'SeCreateGlobalPrivilege',
48
- 'SeIncreaseWorking',
49
- 'SeTimeZonePrivilege',
50
- 'SeCreateSymbolicLinkPrivilege',
51
- 'SeDenyNetworkLogonRight', # Deny access to this computer from the network
52
- 'SeDenyInteractiveLogonRight', # Deny logon locally
53
- 'SeDenyBatchLogonRight', # Deny logon as a batch job
54
- 'SeDenyServiceLogonRight', # Deny logon as a service
55
- 'SeTcbPrivilege',
56
- 'SeMachineAccountPrivilege',
57
- 'SeCreateTokenPrivilege',
58
- 'SeCreatePermanentPrivilege',
59
- 'SeEnableDelegationPrivilege',
60
- 'SeLockMemoryPrivilege',
61
- 'SeSyncAgentPrivilege',
62
- 'SeUnsolicitedInputPrivilege',
63
- 'SeTrustedCredManAccessPrivilege',
64
- 'SeRelabelPrivilege', # the privilege to change a Windows integrity label (new to Windows Vista)
65
- 'SeDenyRemoteInteractiveLogonRight', # Deny logon through Terminal Services
66
- ].freeze
67
-
68
- class SecurityPolicy < Inspec.resource(1)
69
- name 'security_policy'
70
- supports platform: 'windows'
71
- desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
72
- example "
73
- describe security_policy do
74
- its('SeNetworkLogonRight') { should include 'S-1-5-11' }
75
- end
76
-
77
- describe security_policy(translate_sid: true) do
78
- its('SeNetworkLogonRight') { should include 'NT AUTHORITY\\Authenticated Users' }
79
- end
80
- "
81
-
82
- def initialize(opts = {})
83
- @translate_sid = opts[:translate_sid] || false
84
- end
85
-
86
- def content
87
- read_content
88
- end
89
-
90
- def params(*opts)
91
- opts.inject(read_params) do |res, nxt|
92
- res.respond_to?(:key) ? res[nxt] : nil
93
- end
94
- end
95
-
96
- def method_missing(name)
97
- params = read_params
98
- return nil if params.nil?
99
-
100
- # deep search for hash key
101
- params.extend Hashie::Extensions::DeepFind
102
- res = params.deep_find(name.to_s)
103
-
104
- # return an empty array if configuration does not include rights configuration
105
- return [] if res.nil? && MS_PRIVILEGES_RIGHTS.include?(name.to_s)
106
- res
107
- end
108
-
109
- def to_s
110
- 'Security Policy'
111
- end
112
-
113
- private
114
-
115
- def read_content
116
- return @content if defined?(@content)
117
-
118
- # using process pid to prevent any race conditions with multiple runners
119
- export_file = "win_secpol-#{Process.pid}.cfg"
120
-
121
- # export the security policy
122
- cmd = inspec.command("secedit /export /cfg #{export_file}")
123
- return nil if cmd.exit_status.to_i != 0
124
-
125
- # store file content
126
- cmd = inspec.command("Get-Content #{export_file}")
127
- return skip_resource "Can't read security policy" if cmd.exit_status.to_i != 0
128
-
129
- @content = cmd.stdout
130
- ensure
131
- # delete temp file
132
- inspec.command("Remove-Item #{export_file}").exit_status.to_i
133
- end
134
-
135
- def read_params
136
- return @params if defined?(@params)
137
- return @params = {} if read_content.nil?
138
-
139
- conf = SimpleConfig.new(
140
- @content,
141
- assignment_regex: /^\s*(.*)=\s*(\S*)\s*$/,
142
- )
143
- @params = convert_hash(conf.params)
144
- end
145
-
146
- # extracts the values, this methods detects:
147
- # numbers and SIDs and optimizes them for further usage
148
- def extract_value(val)
149
- if val =~ /^\d+$/
150
- val.to_i
151
- # special handling for SID array
152
- elsif val =~ /[,]{0,1}\*\S/
153
- if @translate_sid
154
- val.split(',').map { |v|
155
- object_name = inspec.command("(New-Object System.Security.Principal.SecurityIdentifier(\"#{v.sub('*S', 'S')}\")).Translate( [System.Security.Principal.NTAccount]).Value").stdout.to_s.strip
156
- object_name.empty? || object_name.nil? ? v.sub('*S', 'S') : object_name
157
- }
158
- else
159
- val.split(',').map { |v|
160
- v.sub('*S', 'S')
161
- }
162
- end
163
- # special handling for string values with "
164
- elsif !(m = /^\"(.*)\"$/.match(val)).nil?
165
- m[1]
166
- else
167
- val
168
- end
169
- end
170
-
171
- def convert_hash(hash)
172
- new_hash = {}
173
- hash.each do |k, v|
174
- v.is_a?(Hash) ? value = convert_hash(v) : value = extract_value(v)
175
- new_hash[k.strip] = value
176
- end
177
- new_hash
178
- end
179
- end
180
- end
1
+ # encoding: utf-8
2
+ #
3
+ # Security Configuration and Analysis
4
+ #
5
+ # Export local security policy:
6
+ # secedit /export /cfg secpol.cfg
7
+ #
8
+ # @link http://www.microsoft.com/en-us/download/details.aspx?id=25250
9
+ #
10
+ # In Windows, some security options are managed differently that the local GPO
11
+ # All local GPO parameters can be examined via Registry, but not all security
12
+ # parameters. Therefore we need a combination of Registry and secedit output
13
+
14
+ require 'hashie'
15
+
16
+ module Inspec::Resources
17
+ # known and supported MS privilege rights
18
+ # @see https://technet.microsoft.com/en-us/library/dd277311.aspx
19
+ # @see https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
20
+ MS_PRIVILEGES_RIGHTS = [
21
+ 'SeNetworkLogonRight',
22
+ 'SeBackupPrivilege',
23
+ 'SeChangeNotifyPrivilege',
24
+ 'SeSystemtimePrivilege',
25
+ 'SeCreatePagefilePrivilege',
26
+ 'SeDebugPrivilege',
27
+ 'SeRemoteShutdownPrivilege',
28
+ 'SeAuditPrivilege',
29
+ 'SeIncreaseQuotaPrivilege',
30
+ 'SeIncreaseBasePriorityPrivilege',
31
+ 'SeLoadDriverPrivilege',
32
+ 'SeBatchLogonRight',
33
+ 'SeServiceLogonRight',
34
+ 'SeInteractiveLogonRight',
35
+ 'SeSecurityPrivilege',
36
+ 'SeSystemEnvironmentPrivilege',
37
+ 'SeProfileSingleProcessPrivilege',
38
+ 'SeSystemProfilePrivilege',
39
+ 'SeAssignPrimaryTokenPrivilege',
40
+ 'SeRestorePrivilege',
41
+ 'SeShutdownPrivilege',
42
+ 'SeTakeOwnershipPrivilege',
43
+ 'SeUndockPrivilege',
44
+ 'SeManageVolumePrivilege',
45
+ 'SeRemoteInteractiveLogonRight',
46
+ 'SeImpersonatePrivilege',
47
+ 'SeCreateGlobalPrivilege',
48
+ 'SeIncreaseWorking',
49
+ 'SeTimeZonePrivilege',
50
+ 'SeCreateSymbolicLinkPrivilege',
51
+ 'SeDenyNetworkLogonRight', # Deny access to this computer from the network
52
+ 'SeDenyInteractiveLogonRight', # Deny logon locally
53
+ 'SeDenyBatchLogonRight', # Deny logon as a batch job
54
+ 'SeDenyServiceLogonRight', # Deny logon as a service
55
+ 'SeTcbPrivilege',
56
+ 'SeMachineAccountPrivilege',
57
+ 'SeCreateTokenPrivilege',
58
+ 'SeCreatePermanentPrivilege',
59
+ 'SeEnableDelegationPrivilege',
60
+ 'SeLockMemoryPrivilege',
61
+ 'SeSyncAgentPrivilege',
62
+ 'SeUnsolicitedInputPrivilege',
63
+ 'SeTrustedCredManAccessPrivilege',
64
+ 'SeRelabelPrivilege', # the privilege to change a Windows integrity label (new to Windows Vista)
65
+ 'SeDenyRemoteInteractiveLogonRight', # Deny logon through Terminal Services
66
+ ].freeze
67
+
68
+ class SecurityPolicy < Inspec.resource(1)
69
+ name 'security_policy'
70
+ supports platform: 'windows'
71
+ desc 'Use the security_policy InSpec audit resource to test security policies on the Microsoft Windows platform.'
72
+ example "
73
+ describe security_policy do
74
+ its('SeNetworkLogonRight') { should include 'S-1-5-11' }
75
+ end
76
+
77
+ describe security_policy(translate_sid: true) do
78
+ its('SeNetworkLogonRight') { should include 'NT AUTHORITY\\Authenticated Users' }
79
+ end
80
+ "
81
+
82
+ def initialize(opts = {})
83
+ @translate_sid = opts[:translate_sid] || false
84
+ end
85
+
86
+ def content
87
+ read_content
88
+ end
89
+
90
+ def params(*opts)
91
+ opts.inject(read_params) do |res, nxt|
92
+ res.respond_to?(:key) ? res[nxt] : nil
93
+ end
94
+ end
95
+
96
+ def method_missing(name)
97
+ params = read_params
98
+ return nil if params.nil?
99
+
100
+ # deep search for hash key
101
+ params.extend Hashie::Extensions::DeepFind
102
+ res = params.deep_find(name.to_s)
103
+
104
+ # return an empty array if configuration does not include rights configuration
105
+ return [] if res.nil? && MS_PRIVILEGES_RIGHTS.include?(name.to_s)
106
+ res
107
+ end
108
+
109
+ def to_s
110
+ 'Security Policy'
111
+ end
112
+
113
+ private
114
+
115
+ def read_content
116
+ return @content if defined?(@content)
117
+
118
+ # using process pid to prevent any race conditions with multiple runners
119
+ export_file = "win_secpol-#{Process.pid}.cfg"
120
+
121
+ # export the security policy
122
+ cmd = inspec.command("secedit /export /cfg #{export_file}")
123
+ return nil if cmd.exit_status.to_i != 0
124
+
125
+ # store file content
126
+ cmd = inspec.command("Get-Content #{export_file}")
127
+ return skip_resource "Can't read security policy" if cmd.exit_status.to_i != 0
128
+
129
+ @content = cmd.stdout
130
+ ensure
131
+ # delete temp file
132
+ inspec.command("Remove-Item #{export_file}").exit_status.to_i
133
+ end
134
+
135
+ def read_params
136
+ return @params if defined?(@params)
137
+ return @params = {} if read_content.nil?
138
+
139
+ conf = SimpleConfig.new(
140
+ @content,
141
+ assignment_regex: /^\s*(.*)=\s*(\S*)\s*$/,
142
+ )
143
+ @params = convert_hash(conf.params)
144
+ end
145
+
146
+ # extracts the values, this methods detects:
147
+ # numbers and SIDs and optimizes them for further usage
148
+ def extract_value(val)
149
+ if val =~ /^\d+$/
150
+ val.to_i
151
+ # special handling for SID array
152
+ elsif val =~ /[,]{0,1}\*\S/
153
+ if @translate_sid
154
+ val.split(',').map { |v|
155
+ object_name = inspec.command("(New-Object System.Security.Principal.SecurityIdentifier(\"#{v.sub('*S', 'S')}\")).Translate( [System.Security.Principal.NTAccount]).Value").stdout.to_s.strip
156
+ object_name.empty? || object_name.nil? ? v.sub('*S', 'S') : object_name
157
+ }
158
+ else
159
+ val.split(',').map { |v|
160
+ v.sub('*S', 'S')
161
+ }
162
+ end
163
+ # special handling for string values with "
164
+ elsif !(m = /^\"(.*)\"$/.match(val)).nil?
165
+ m[1]
166
+ else
167
+ val
168
+ end
169
+ end
170
+
171
+ def convert_hash(hash)
172
+ new_hash = {}
173
+ hash.each do |k, v|
174
+ v.is_a?(Hash) ? value = convert_hash(v) : value = extract_value(v)
175
+ new_hash[k.strip] = value
176
+ end
177
+ new_hash
178
+ end
179
+ end
180
+ end
@@ -1,789 +1,789 @@
1
- # encoding: utf-8
2
-
3
- require 'hashie'
4
-
5
- module Inspec::Resources
6
- class Runlevels < Hash
7
- attr_accessor :owner
8
-
9
- def self.from_hash(owner, hash = {}, filter = nil)
10
- res = Runlevels.new(owner)
11
- filter = filter.first if filter.is_a?(Array) && filter.length <= 1
12
-
13
- ks = case filter
14
- when nil
15
- hash.keys
16
- when Regexp
17
- hash.keys.find_all { |x| x.to_s =~ filter }
18
- when Array
19
- f = filter.map(&:to_s)
20
- hash.keys.find_all { |x| f.include?(x.to_s) }
21
- when Numeric
22
- hash.keys.include?(filter) ? [filter] : []
23
- else
24
- hash.keys.find_all { |x| x == filter }
25
- end
26
-
27
- ks.each { |k| res[k] = hash[k] }
28
- res
29
- end
30
-
31
- def initialize(owner, default = false)
32
- @owner = owner
33
- super(default)
34
- end
35
-
36
- def filter(f)
37
- Runlevels.from_hash(owner, self, f)
38
- end
39
-
40
- # Check if all runlevels are enabled
41
- #
42
- # @return [boolean] true if all runlevels are enabled
43
- def enabled?
44
- values.all?
45
- end
46
-
47
- # Check if all runlevels are disabled
48
- #
49
- # @return [boolean] true if all runlevels are disabled
50
- def disabled?
51
- values.none?
52
- end
53
-
54
- def to_s
55
- "#{owner} runlevels #{keys.join(', ')}"
56
- end
57
- end
58
-
59
- # We detect the init system for each operating system, based on the operating
60
- # system.
61
- #
62
- # Fedora 15 : systemd
63
- # RedHat 7 : systemd
64
- # Ubuntu 15.04 : systemd
65
- # Ubuntu < 15.04 : upstart
66
- #
67
- # TODO: extend the logic to detect the running init system, independently of OS
68
- class Service < Inspec.resource(1)
69
- name 'service'
70
- supports platform: 'unix'
71
- supports platform: 'windows'
72
- desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
73
- example "
74
- describe service('service_name') do
75
- it { should be_installed }
76
- it { should be_enabled }
77
- it { should be_running }
78
- its('type') { should be 'systemd' }
79
- its ('startmode') { should be 'Auto'}
80
- end
81
-
82
- describe service('service_name').runlevels(3, 5) do
83
- it { should be_enabled }
84
- end
85
-
86
- describe service('service_name').params do
87
- its('UnitFileState') { should eq 'enabled' }
88
- end
89
- "
90
-
91
- attr_reader :service_ctl
92
-
93
- def initialize(service_name, service_ctl = nil)
94
- @service_name = service_name
95
- @service_mgmt = nil
96
- @service_ctl ||= service_ctl
97
- @cache = nil
98
- @service_mgmt = select_service_mgmt
99
-
100
- return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
101
- end
102
-
103
- def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
104
- os = inspec.os
105
- platform = os[:name]
106
-
107
- # Ubuntu
108
- # @see: https://wiki.ubuntu.com/SystemdForUpstartUsers
109
- # Ubuntu 15.04 : Systemd
110
- # Systemd runs with PID 1 as /sbin/init.
111
- # Upstart runs with PID 1 as /sbin/upstart.
112
- # Ubuntu < 15.04 : Upstart
113
- # Upstart runs with PID 1 as /sbin/init.
114
- # Systemd runs with PID 1 as /lib/systemd/systemd.
115
- if %w{ubuntu}.include?(platform)
116
- version = os[:release].to_f
117
- if version < 15.04
118
- Upstart.new(inspec, service_ctl)
119
- else
120
- Systemd.new(inspec, service_ctl)
121
- end
122
- elsif %w{linuxmint}.include?(platform)
123
- version = os[:release].to_f
124
- if version < 18
125
- Upstart.new(inspec, service_ctl)
126
- else
127
- Systemd.new(inspec, service_ctl)
128
- end
129
- elsif %w{debian}.include?(platform)
130
- version = os[:release].to_i
131
- if version > 7
132
- Systemd.new(inspec, service_ctl)
133
- else
134
- SysV.new(inspec, service_ctl || '/usr/sbin/service')
135
- end
136
- elsif %w{redhat fedora centos oracle}.include?(platform)
137
- version = os[:release].to_i
138
- if (%w{redhat centos oracle}.include?(platform) && version >= 7) || (platform == 'fedora' && version >= 15)
139
- Systemd.new(inspec, service_ctl)
140
- else
141
- SysV.new(inspec, service_ctl || '/sbin/service')
142
- end
143
- elsif %w{wrlinux}.include?(platform)
144
- SysV.new(inspec, service_ctl)
145
- elsif %w{mac_os_x}.include?(platform)
146
- LaunchCtl.new(inspec, service_ctl)
147
- elsif os.windows?
148
- WindowsSrv.new(inspec)
149
- elsif %w{freebsd}.include?(platform)
150
- BSDInit.new(inspec, service_ctl)
151
- elsif %w{arch}.include?(platform)
152
- Systemd.new(inspec, service_ctl)
153
- elsif %w{coreos}.include?(platform)
154
- Systemd.new(inspec, service_ctl)
155
- elsif %w{suse opensuse}.include?(platform)
156
- if os[:release].to_i >= 12
157
- Systemd.new(inspec, service_ctl)
158
- else
159
- SysV.new(inspec, service_ctl || '/sbin/service')
160
- end
161
- elsif %w{aix}.include?(platform)
162
- SrcMstr.new(inspec)
163
- elsif %w{amazon}.include?(platform)
164
- Upstart.new(inspec, service_ctl)
165
- elsif os.solaris?
166
- Svcs.new(inspec)
167
- end
168
- end
169
-
170
- def info
171
- return nil if @service_mgmt.nil?
172
- @cache ||= @service_mgmt.info(@service_name)
173
- end
174
-
175
- # verifies if the service is enabled
176
- def enabled?(_level = nil)
177
- return false if info.nil?
178
- info[:enabled]
179
- end
180
-
181
- def params
182
- return {} if info.nil?
183
- Hashie::Mash.new(info[:params] || {})
184
- end
185
-
186
- # verifies the service is registered
187
- def installed?(_name = nil, _version = nil)
188
- return false if info.nil?
189
- info[:installed]
190
- end
191
-
192
- # verifies the service is currently running
193
- def running?(_under = nil)
194
- return false if info.nil?
195
- info[:running]
196
- end
197
-
198
- # get all runlevels that are available and their configuration
199
- def runlevels(*args)
200
- return Runlevels.new(self) if info.nil? or info[:runlevels].nil?
201
- Runlevels.from_hash(self, info[:runlevels], args)
202
- end
203
-
204
- # returns the service type from info
205
- def type
206
- return nil if info.nil?
207
- info[:type]
208
- end
209
-
210
- # returns the service name from info
211
- def name
212
- return @service_name if info.nil?
213
- info[:name]
214
- end
215
-
216
- # returns the service description from info
217
- def description
218
- return nil if info.nil?
219
- info[:description]
220
- end
221
-
222
- # returns the service start up mode from info
223
- def startmode
224
- return nil if info.nil?
225
- info[:startmode]
226
- end
227
-
228
- def to_s
229
- "Service #{@service_name}"
230
- end
231
-
232
- private :info
233
- end
234
-
235
- class ServiceManager
236
- attr_reader :inspec, :service_ctl
237
- def initialize(inspec, service_ctl = nil)
238
- @inspec = inspec
239
- @service_ctl ||= service_ctl
240
- end
241
- end
242
-
243
- # @see: http://www.freedesktop.org/software/systemd/man/systemctl.html
244
- # @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html
245
- class Systemd < ServiceManager
246
- def initialize(inspec, service_ctl = nil)
247
- @service_ctl = service_ctl || 'systemctl'
248
- super
249
- end
250
-
251
- def is_enabled?(service_name)
252
- result = inspec.command("#{service_ctl} is-enabled #{service_name} --quiet")
253
- return true if result.exit_status == 0
254
-
255
- # Some systems may not have a `.service` file for a particular service
256
- # which causes the `systemctl is-enabled` check to fail despite the
257
- # service being enabled. In that event we fallback to `sysv_service`.
258
- if result.stderr =~ /Failed to get.*No such file or directory/
259
- return inspec.sysv_service(service_name).enabled?
260
- end
261
-
262
- false
263
- end
264
-
265
- def is_active?(service_name)
266
- inspec.command("#{service_ctl} is-active #{service_name} --quiet").exit_status == 0
267
- end
268
-
269
- def info(service_name)
270
- cmd = inspec.command("#{service_ctl} show --all #{service_name}")
271
- return nil if cmd.exit_status.to_i != 0
272
-
273
- # parse data
274
- params = SimpleConfig.new(
275
- cmd.stdout.chomp,
276
- assignment_regex: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
277
- multiple_values: false,
278
- ).params
279
-
280
- # LoadState values eg. loaded, not-found
281
- installed = params['LoadState'] == 'loaded'
282
-
283
- {
284
- name: params['Id'],
285
- description: params['Description'],
286
- installed: installed,
287
- running: is_active?(service_name),
288
- enabled: is_enabled?(service_name),
289
- type: 'systemd',
290
- params: params,
291
- }
292
- end
293
- end
294
-
295
- # AIX services
296
- class SrcMstr < ServiceManager
297
- attr_reader :name
298
-
299
- def info(service_name)
300
- @name = service_name
301
- running = status?
302
- return nil if running.nil?
303
-
304
- {
305
- name: service_name,
306
- description: nil,
307
- installed: true,
308
- running: running,
309
- enabled: enabled?,
310
- type: 'srcmstr',
311
- }
312
- end
313
-
314
- private
315
-
316
- def status?
317
- status_cmd = inspec.command("lssrc -s #{@name}")
318
- return nil if status_cmd.exit_status.to_i != 0
319
- status_cmd.stdout.split(/\n/).last.chomp =~ /active$/ ? true : false
320
- end
321
-
322
- def enabled?
323
- enabled_rc_tcpip? || enabled_inittab?
324
- end
325
-
326
- def enabled_rc_tcpip?
327
- inspec.command(
328
- "grep -v ^# /etc/rc.tcpip | grep 'start ' | grep -Eq '(/{0,1}| )#{name} '",
329
- ).exit_status == 0
330
- end
331
-
332
- def enabled_inittab?
333
- inspec.command("lsitab #{name}").exit_status == 0
334
- end
335
- end
336
-
337
- # @see: http://upstart.ubuntu.com
338
- class Upstart < ServiceManager
339
- def initialize(service_name, service_ctl = nil)
340
- @service_ctl = service_ctl || 'initctl'
341
- super
342
- end
343
-
344
- def info(service_name)
345
- # get the status of upstart service
346
- status = inspec.command("#{service_ctl} status #{service_name}")
347
-
348
- # fallback for systemv services, those are not handled via `initctl`
349
- return SysV.new(inspec).info(service_name) if status.exit_status.to_i != 0 || status.stdout == ''
350
-
351
- # @see: http://upstart.ubuntu.com/cookbook/#job-states
352
- # grep for running to indicate the service is there
353
- running = !status.stdout[%r{start/running}].nil?
354
-
355
- {
356
- name: service_name,
357
- description: nil,
358
- installed: true,
359
- running: running,
360
- enabled: info_enabled(service_name),
361
- type: 'upstart',
362
- }
363
- end
364
-
365
- private
366
-
367
- def info_enabled(service_name)
368
- # check if a service is enabled
369
- config = inspec.file("/etc/init/#{service_name}.conf").content
370
-
371
- # disregard if the config does not exist
372
- return nil if config.nil?
373
-
374
- !config.match(/^\s*start on/).nil?
375
- end
376
-
377
- def version
378
- @version ||= begin
379
- out = inspec.command("#{service_ctl} --version").stdout
380
- Gem::Version.new(out[/\(upstart ([^\)]+)\)/, 1])
381
- end
382
- end
383
- end
384
-
385
- class SysV < ServiceManager
386
- RUNLEVELS = { 0=>false, 1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false }.freeze
387
-
388
- def initialize(service_name, service_ctl = nil)
389
- @service_ctl = service_ctl || 'service'
390
- super
391
- end
392
-
393
- def info(service_name)
394
- # check if service is installed
395
- # read all available services via ls /etc/init.d/
396
- srvlist = inspec.command('ls -1 /etc/init.d/')
397
- return nil if srvlist.exit_status != 0
398
-
399
- # check if the service is in list
400
- service = srvlist.stdout.split("\n").select { |srv| srv == service_name }
401
-
402
- # abort if we could not find any service
403
- return nil if service.empty?
404
-
405
- # read all enabled services from runlevel
406
- # on rhel via: 'chkconfig --list', is not installed by default
407
- # bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
408
- enabled_services_cmd = inspec.command('find /etc/rc*.d /etc/init.d/rc*.d -name "S*"').stdout
409
- service_line = %r{rc(?<runlevel>[0-6])\.d/S[^/]*?#{Regexp.escape service_name}$}
410
- all_services = enabled_services_cmd.split("\n").map { |line|
411
- service_line.match(line)
412
- }.compact
413
- enabled = !all_services.empty?
414
-
415
- # Determine a list of runlevels which this service is activated for
416
- runlevels = RUNLEVELS.dup
417
- all_services.each { |x| runlevels[x[:runlevel].to_i] = true }
418
-
419
- # check if service is really running
420
- # service throws an exit code if the service is not installed or
421
- # not enabled
422
-
423
- cmd = inspec.command("#{service_ctl} #{service_name} status")
424
- running = cmd.exit_status == 0
425
- {
426
- name: service_name,
427
- description: nil,
428
- installed: true,
429
- running: running,
430
- enabled: enabled,
431
- runlevels: runlevels,
432
- type: 'sysv',
433
- }
434
- end
435
- end
436
-
437
- # @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html
438
- # @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5
439
- class BSDInit < ServiceManager
440
- def initialize(service_name, service_ctl = nil)
441
- @service_ctl = service_ctl || 'service'
442
- super
443
- end
444
-
445
- def info(service_name)
446
- # check if service is enabled
447
- # services are enabled in /etc/rc.conf and /etc/defaults/rc.conf
448
- # via #{service_name}_enable="YES"
449
- # service SERVICE status returns the following result if not activated:
450
- # Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'.
451
- # gather all enabled services
452
- cmd = inspec.command("#{service_ctl} -e")
453
- return nil if cmd.exit_status != 0
454
-
455
- # search for the service
456
- srv = /(^.*#{service_name}$)/.match(cmd.stdout)
457
- return nil if srv.nil? || srv[0].nil?
458
- enabled = true
459
-
460
- # check if the service is running
461
- # if the service is not available or not running, we always get an error code
462
- cmd = inspec.command("#{service_ctl} #{service_name} onestatus")
463
- running = cmd.exit_status == 0
464
-
465
- {
466
- name: service_name,
467
- description: nil,
468
- installed: true,
469
- running: running,
470
- enabled: enabled,
471
- type: 'bsd-init',
472
- }
473
- end
474
- end
475
-
476
- class Runit < ServiceManager
477
- def initialize(service_name, service_ctl = nil)
478
- @service_ctl = service_ctl || 'sv'
479
- super
480
- end
481
-
482
- # rubocop:disable Style/DoubleNegation
483
- def info(service_name)
484
- # get the status of runit service
485
- cmd = inspec.command("#{service_ctl} status #{service_name}")
486
- # return nil unless cmd.exit_status == 0 # NOTE(sr) why do we do this?
487
-
488
- installed = cmd.exit_status == 0
489
- running = installed && !!(cmd.stdout =~ /^run:/)
490
- enabled = installed && (running || !!(cmd.stdout =~ /normally up/) || !!(cmd.stdout =~ /want up/))
491
-
492
- {
493
- name: service_name,
494
- description: nil,
495
- installed: installed,
496
- running: running,
497
- enabled: enabled,
498
- type: 'runit',
499
- }
500
- end
501
- end
502
-
503
- # MacOS / Darwin
504
- # new launctl on macos 10.10
505
- class LaunchCtl < ServiceManager
506
- def initialize(service_name, service_ctl = nil)
507
- @service_ctl = service_ctl || 'launchctl'
508
- super
509
- end
510
-
511
- def info(service_name)
512
- # get the status of upstart service
513
- cmd = inspec.command("#{service_ctl} list")
514
- return nil if cmd.exit_status != 0
515
-
516
- # search for the service
517
- srv = /(^.*#{service_name}.*)/.match(cmd.stdout)
518
- return nil if srv.nil? || srv[0].nil?
519
-
520
- # extract values from service
521
- parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[0-9]+)\t(?<name>\S*)$/.match(srv[0])
522
- enabled = !parsed_srv['name'].nil? # it's in the list
523
-
524
- # check if the service is running
525
- pid = parsed_srv['pid']
526
- running = pid != '-'
527
-
528
- # extract service label
529
- srv = parsed_srv['name'] || service_name
530
-
531
- {
532
- name: srv,
533
- description: nil,
534
- installed: true,
535
- running: running,
536
- enabled: enabled,
537
- type: 'darwin',
538
- }
539
- end
540
- end
541
-
542
- # Determine the service state from Windows
543
- # Uses Powershell to retrieve the information
544
- class WindowsSrv < ServiceManager
545
- # Determine service details
546
- # PS: Get-Service -Name 'dhcp'| Select-Object -Property Name, DisplayName, Status | ConvertTo-Json
547
- # {
548
- # "Name": "dhcp",
549
- # "DisplayName": "DHCP Client",
550
- # "Status": 4
551
- # }
552
- #
553
- # Until StartMode is not added to Get-Service, we need to do a workaround
554
- # @see: https://connect.microsoft.com/PowerShell/feedback/details/424948/i-would-like-to-see-the-property-starttype-added-to-get-services
555
- # Also see: https://msdn.microsoft.com/en-us/library/aa384896(v=vs.85).aspx
556
- # Use the following powershell to determine the start mode
557
- # PS: Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} | Select-Object -Prop
558
- # erty Name, StartMode, State, Status | ConvertTo-Json
559
- # {
560
- # "Name": "Dhcp",
561
- # "StartMode": "Auto",
562
- # "State": "Running",
563
- # "Status": "OK"
564
- # }
565
- #
566
- # Windows Services have the following status code:
567
- # @see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
568
- # - 1: Stopped
569
- # - 2: Starting
570
- # - 3: Stopping
571
- # - 4: Running
572
- # - 5: Continue Pending
573
- # - 6: Pause Pending
574
- # - 7: Paused
575
- def info(service_name)
576
- cmd = inspec.command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name '#{service_name}'| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq '#{service_name}' -or $_.DisplayName -eq '#{service_name}'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json")
577
-
578
- # cannot rely on exit code for now, successful command returns exit code 1
579
- # return nil if cmd.exit_status != 0
580
- # try to parse json
581
- begin
582
- service = JSON.parse(cmd.stdout)
583
- rescue JSON::ParserError => _e
584
- return nil
585
- end
586
-
587
- # check that we got a response
588
- return nil if service.nil? || service['Service'].nil?
589
-
590
- {
591
- name: service['Service']['Name'],
592
- description: service['Service']['DisplayName'],
593
- installed: true,
594
- running: service_running?(service),
595
- enabled: service_enabled?(service),
596
- startmode: service['WMI']['StartMode'],
597
- type: 'windows',
598
- }
599
- end
600
-
601
- private
602
-
603
- # detect if service is enabled
604
- def service_enabled?(service)
605
- !service['WMI'].nil? &&
606
- !service['WMI']['StartMode'].nil? &&
607
- (service['WMI']['StartMode'] == 'Auto' ||
608
- service['WMI']['StartMode'] == 'Manual')
609
- end
610
-
611
- # detect if service is running
612
- def service_running?(service)
613
- !service['Service']['Status'].nil? && service['Service']['Status'] == 4
614
- end
615
- end
616
-
617
- # Solaris services
618
- class Svcs < ServiceManager
619
- def initialize(service_name, service_ctl = nil)
620
- @service_ctl = service_ctl || 'svcs'
621
- super
622
- end
623
-
624
- def info(service_name)
625
- # get the status of runit service
626
- cmd = inspec.command("#{service_ctl} -l #{service_name}")
627
- return nil if cmd.exit_status != 0
628
-
629
- params = SimpleConfig.new(
630
- cmd.stdout.chomp,
631
- assignment_regex: /^(\w+)\s*(.*)$/,
632
- multiple_values: false,
633
- ).params
634
-
635
- installed = cmd.exit_status == 0
636
- running = installed && (params['state'] == 'online')
637
- enabled = installed && (params['enabled'] == 'true')
638
-
639
- {
640
- name: service_name,
641
- description: params['name'],
642
- installed: installed,
643
- running: running,
644
- enabled: enabled,
645
- type: 'svcs',
646
- }
647
- end
648
- end
649
-
650
- # specific resources for specific service managers
651
-
652
- class SystemdService < Service
653
- name 'systemd_service'
654
- supports platform: 'unix'
655
- desc 'Use the systemd_service InSpec audit resource to test if the named service (controlled by systemd) is installed, running and/or enabled.'
656
- example "
657
- # to override service mgmt auto-detection
658
- describe systemd_service('service_name') do
659
- it { should be_installed }
660
- it { should be_enabled }
661
- it { should be_running }
662
- end
663
-
664
- # to set a non-standard systemctl path
665
- describe systemd_service('service_name', '/path/to/systemctl') do
666
- it { should be_running }
667
- end
668
- "
669
-
670
- def select_service_mgmt
671
- Systemd.new(inspec, service_ctl)
672
- end
673
- end
674
-
675
- class UpstartService < Service
676
- name 'upstart_service'
677
- supports platform: 'unix'
678
- desc 'Use the upstart_service InSpec audit resource to test if the named service (controlled by upstart) is installed, running and/or enabled.'
679
- example "
680
- # to override service mgmt auto-detection
681
- describe upstart_service('service_name') do
682
- it { should be_installed }
683
- it { should be_enabled }
684
- it { should be_running }
685
- end
686
-
687
- # to set a non-standard initctl path
688
- describe upstart_service('service_name', '/path/to/initctl') do
689
- it { should be_running }
690
- end
691
- "
692
-
693
- def select_service_mgmt
694
- Upstart.new(inspec, service_ctl)
695
- end
696
- end
697
-
698
- class SysVService < Service
699
- name 'sysv_service'
700
- supports platform: 'unix'
701
- desc 'Use the sysv_service InSpec audit resource to test if the named service (controlled by SysV) is installed, running and/or enabled.'
702
- example "
703
- # to override service mgmt auto-detection
704
- describe sysv_service('service_name') do
705
- it { should be_installed }
706
- it { should be_enabled }
707
- it { should be_running }
708
- end
709
-
710
- # to set a non-standard service path
711
- describe sysv_service('service_name', '/path/to/service') do
712
- it { should be_running }
713
- end
714
- "
715
-
716
- def select_service_mgmt
717
- SysV.new(inspec, service_ctl)
718
- end
719
- end
720
-
721
- class BSDService < Service
722
- name 'bsd_service'
723
- supports platform: 'unix'
724
- desc 'Use the bsd_service InSpec audit resource to test if the named service (controlled by BSD init) is installed, running and/or enabled.'
725
- example "
726
- # to override service mgmt auto-detection
727
- describe bsd_service('service_name') do
728
- it { should be_installed }
729
- it { should be_enabled }
730
- it { should be_running }
731
- end
732
-
733
- # to set a non-standard service path
734
- describe bsd_service('service_name', '/path/to/service') do
735
- it { should be_running }
736
- end
737
- "
738
-
739
- def select_service_mgmt
740
- BSDInit.new(inspec, service_ctl)
741
- end
742
- end
743
-
744
- class LaunchdService < Service
745
- name 'launchd_service'
746
- supports platform: 'unix'
747
- desc 'Use the launchd_service InSpec audit resource to test if the named service (controlled by launchd) is installed, running and/or enabled.'
748
- example "
749
- # to override service mgmt auto-detection
750
- describe launchd_service('service_name') do
751
- it { should be_installed }
752
- it { should be_enabled }
753
- it { should be_running }
754
- end
755
-
756
- # to set a non-standard launchctl path
757
- describe launchd_service('service_name', '/path/to/launchctl') do
758
- it { should be_running }
759
- end
760
- "
761
-
762
- def select_service_mgmt
763
- LaunchCtl.new(inspec, service_ctl)
764
- end
765
- end
766
-
767
- class RunitService < Service
768
- name 'runit_service'
769
- supports platform: 'unix'
770
- desc 'Use the runit_service InSpec audit resource to test if the named service (controlled by runit) is installed, running and/or enabled.'
771
- example "
772
- # to override service mgmt auto-detection
773
- describe runit_service('service_name') do
774
- it { should be_installed }
775
- it { should be_enabled }
776
- it { should be_running }
777
- end
778
-
779
- # to set a non-standard sv path
780
- describe runit_service('service_name', '/path/to/sv') do
781
- it { should be_running }
782
- end
783
- "
784
-
785
- def select_service_mgmt
786
- Runit.new(inspec, service_ctl)
787
- end
788
- end
789
- end
1
+ # encoding: utf-8
2
+
3
+ require 'hashie'
4
+
5
+ module Inspec::Resources
6
+ class Runlevels < Hash
7
+ attr_accessor :owner
8
+
9
+ def self.from_hash(owner, hash = {}, filter = nil)
10
+ res = Runlevels.new(owner)
11
+ filter = filter.first if filter.is_a?(Array) && filter.length <= 1
12
+
13
+ ks = case filter
14
+ when nil
15
+ hash.keys
16
+ when Regexp
17
+ hash.keys.find_all { |x| x.to_s =~ filter }
18
+ when Array
19
+ f = filter.map(&:to_s)
20
+ hash.keys.find_all { |x| f.include?(x.to_s) }
21
+ when Numeric
22
+ hash.keys.include?(filter) ? [filter] : []
23
+ else
24
+ hash.keys.find_all { |x| x == filter }
25
+ end
26
+
27
+ ks.each { |k| res[k] = hash[k] }
28
+ res
29
+ end
30
+
31
+ def initialize(owner, default = false)
32
+ @owner = owner
33
+ super(default)
34
+ end
35
+
36
+ def filter(f)
37
+ Runlevels.from_hash(owner, self, f)
38
+ end
39
+
40
+ # Check if all runlevels are enabled
41
+ #
42
+ # @return [boolean] true if all runlevels are enabled
43
+ def enabled?
44
+ values.all?
45
+ end
46
+
47
+ # Check if all runlevels are disabled
48
+ #
49
+ # @return [boolean] true if all runlevels are disabled
50
+ def disabled?
51
+ values.none?
52
+ end
53
+
54
+ def to_s
55
+ "#{owner} runlevels #{keys.join(', ')}"
56
+ end
57
+ end
58
+
59
+ # We detect the init system for each operating system, based on the operating
60
+ # system.
61
+ #
62
+ # Fedora 15 : systemd
63
+ # RedHat 7 : systemd
64
+ # Ubuntu 15.04 : systemd
65
+ # Ubuntu < 15.04 : upstart
66
+ #
67
+ # TODO: extend the logic to detect the running init system, independently of OS
68
+ class Service < Inspec.resource(1)
69
+ name 'service'
70
+ supports platform: 'unix'
71
+ supports platform: 'windows'
72
+ desc 'Use the service InSpec audit resource to test if the named service is installed, running and/or enabled.'
73
+ example "
74
+ describe service('service_name') do
75
+ it { should be_installed }
76
+ it { should be_enabled }
77
+ it { should be_running }
78
+ its('type') { should be 'systemd' }
79
+ its ('startmode') { should be 'Auto'}
80
+ end
81
+
82
+ describe service('service_name').runlevels(3, 5) do
83
+ it { should be_enabled }
84
+ end
85
+
86
+ describe service('service_name').params do
87
+ its('UnitFileState') { should eq 'enabled' }
88
+ end
89
+ "
90
+
91
+ attr_reader :service_ctl
92
+
93
+ def initialize(service_name, service_ctl = nil)
94
+ @service_name = service_name
95
+ @service_mgmt = nil
96
+ @service_ctl ||= service_ctl
97
+ @cache = nil
98
+ @service_mgmt = select_service_mgmt
99
+
100
+ return skip_resource 'The `service` resource is not supported on your OS yet.' if @service_mgmt.nil?
101
+ end
102
+
103
+ def select_service_mgmt # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
104
+ os = inspec.os
105
+ platform = os[:name]
106
+
107
+ # Ubuntu
108
+ # @see: https://wiki.ubuntu.com/SystemdForUpstartUsers
109
+ # Ubuntu 15.04 : Systemd
110
+ # Systemd runs with PID 1 as /sbin/init.
111
+ # Upstart runs with PID 1 as /sbin/upstart.
112
+ # Ubuntu < 15.04 : Upstart
113
+ # Upstart runs with PID 1 as /sbin/init.
114
+ # Systemd runs with PID 1 as /lib/systemd/systemd.
115
+ if %w{ubuntu}.include?(platform)
116
+ version = os[:release].to_f
117
+ if version < 15.04
118
+ Upstart.new(inspec, service_ctl)
119
+ else
120
+ Systemd.new(inspec, service_ctl)
121
+ end
122
+ elsif %w{linuxmint}.include?(platform)
123
+ version = os[:release].to_f
124
+ if version < 18
125
+ Upstart.new(inspec, service_ctl)
126
+ else
127
+ Systemd.new(inspec, service_ctl)
128
+ end
129
+ elsif %w{debian}.include?(platform)
130
+ version = os[:release].to_i
131
+ if version > 7
132
+ Systemd.new(inspec, service_ctl)
133
+ else
134
+ SysV.new(inspec, service_ctl || '/usr/sbin/service')
135
+ end
136
+ elsif %w{redhat fedora centos oracle}.include?(platform)
137
+ version = os[:release].to_i
138
+ if (%w{redhat centos oracle}.include?(platform) && version >= 7) || (platform == 'fedora' && version >= 15)
139
+ Systemd.new(inspec, service_ctl)
140
+ else
141
+ SysV.new(inspec, service_ctl || '/sbin/service')
142
+ end
143
+ elsif %w{wrlinux}.include?(platform)
144
+ SysV.new(inspec, service_ctl)
145
+ elsif %w{mac_os_x}.include?(platform)
146
+ LaunchCtl.new(inspec, service_ctl)
147
+ elsif os.windows?
148
+ WindowsSrv.new(inspec)
149
+ elsif %w{freebsd}.include?(platform)
150
+ BSDInit.new(inspec, service_ctl)
151
+ elsif %w{arch}.include?(platform)
152
+ Systemd.new(inspec, service_ctl)
153
+ elsif %w{coreos}.include?(platform)
154
+ Systemd.new(inspec, service_ctl)
155
+ elsif %w{suse opensuse}.include?(platform)
156
+ if os[:release].to_i >= 12
157
+ Systemd.new(inspec, service_ctl)
158
+ else
159
+ SysV.new(inspec, service_ctl || '/sbin/service')
160
+ end
161
+ elsif %w{aix}.include?(platform)
162
+ SrcMstr.new(inspec)
163
+ elsif %w{amazon}.include?(platform)
164
+ Upstart.new(inspec, service_ctl)
165
+ elsif os.solaris?
166
+ Svcs.new(inspec)
167
+ end
168
+ end
169
+
170
+ def info
171
+ return nil if @service_mgmt.nil?
172
+ @cache ||= @service_mgmt.info(@service_name)
173
+ end
174
+
175
+ # verifies if the service is enabled
176
+ def enabled?(_level = nil)
177
+ return false if info.nil?
178
+ info[:enabled]
179
+ end
180
+
181
+ def params
182
+ return {} if info.nil?
183
+ Hashie::Mash.new(info[:params] || {})
184
+ end
185
+
186
+ # verifies the service is registered
187
+ def installed?(_name = nil, _version = nil)
188
+ return false if info.nil?
189
+ info[:installed]
190
+ end
191
+
192
+ # verifies the service is currently running
193
+ def running?(_under = nil)
194
+ return false if info.nil?
195
+ info[:running]
196
+ end
197
+
198
+ # get all runlevels that are available and their configuration
199
+ def runlevels(*args)
200
+ return Runlevels.new(self) if info.nil? or info[:runlevels].nil?
201
+ Runlevels.from_hash(self, info[:runlevels], args)
202
+ end
203
+
204
+ # returns the service type from info
205
+ def type
206
+ return nil if info.nil?
207
+ info[:type]
208
+ end
209
+
210
+ # returns the service name from info
211
+ def name
212
+ return @service_name if info.nil?
213
+ info[:name]
214
+ end
215
+
216
+ # returns the service description from info
217
+ def description
218
+ return nil if info.nil?
219
+ info[:description]
220
+ end
221
+
222
+ # returns the service start up mode from info
223
+ def startmode
224
+ return nil if info.nil?
225
+ info[:startmode]
226
+ end
227
+
228
+ def to_s
229
+ "Service #{@service_name}"
230
+ end
231
+
232
+ private :info
233
+ end
234
+
235
+ class ServiceManager
236
+ attr_reader :inspec, :service_ctl
237
+ def initialize(inspec, service_ctl = nil)
238
+ @inspec = inspec
239
+ @service_ctl ||= service_ctl
240
+ end
241
+ end
242
+
243
+ # @see: http://www.freedesktop.org/software/systemd/man/systemctl.html
244
+ # @see: http://www.freedesktop.org/software/systemd/man/systemd-system.conf.html
245
+ class Systemd < ServiceManager
246
+ def initialize(inspec, service_ctl = nil)
247
+ @service_ctl = service_ctl || 'systemctl'
248
+ super
249
+ end
250
+
251
+ def is_enabled?(service_name)
252
+ result = inspec.command("#{service_ctl} is-enabled #{service_name} --quiet")
253
+ return true if result.exit_status == 0
254
+
255
+ # Some systems may not have a `.service` file for a particular service
256
+ # which causes the `systemctl is-enabled` check to fail despite the
257
+ # service being enabled. In that event we fallback to `sysv_service`.
258
+ if result.stderr =~ /Failed to get.*No such file or directory/
259
+ return inspec.sysv_service(service_name).enabled?
260
+ end
261
+
262
+ false
263
+ end
264
+
265
+ def is_active?(service_name)
266
+ inspec.command("#{service_ctl} is-active #{service_name} --quiet").exit_status == 0
267
+ end
268
+
269
+ def info(service_name)
270
+ cmd = inspec.command("#{service_ctl} show --all #{service_name}")
271
+ return nil if cmd.exit_status.to_i != 0
272
+
273
+ # parse data
274
+ params = SimpleConfig.new(
275
+ cmd.stdout.chomp,
276
+ assignment_regex: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
277
+ multiple_values: false,
278
+ ).params
279
+
280
+ # LoadState values eg. loaded, not-found
281
+ installed = params['LoadState'] == 'loaded'
282
+
283
+ {
284
+ name: params['Id'],
285
+ description: params['Description'],
286
+ installed: installed,
287
+ running: is_active?(service_name),
288
+ enabled: is_enabled?(service_name),
289
+ type: 'systemd',
290
+ params: params,
291
+ }
292
+ end
293
+ end
294
+
295
+ # AIX services
296
+ class SrcMstr < ServiceManager
297
+ attr_reader :name
298
+
299
+ def info(service_name)
300
+ @name = service_name
301
+ running = status?
302
+ return nil if running.nil?
303
+
304
+ {
305
+ name: service_name,
306
+ description: nil,
307
+ installed: true,
308
+ running: running,
309
+ enabled: enabled?,
310
+ type: 'srcmstr',
311
+ }
312
+ end
313
+
314
+ private
315
+
316
+ def status?
317
+ status_cmd = inspec.command("lssrc -s #{@name}")
318
+ return nil if status_cmd.exit_status.to_i != 0
319
+ status_cmd.stdout.split(/\n/).last.chomp =~ /active$/ ? true : false
320
+ end
321
+
322
+ def enabled?
323
+ enabled_rc_tcpip? || enabled_inittab?
324
+ end
325
+
326
+ def enabled_rc_tcpip?
327
+ inspec.command(
328
+ "grep -v ^# /etc/rc.tcpip | grep 'start ' | grep -Eq '(/{0,1}| )#{name} '",
329
+ ).exit_status == 0
330
+ end
331
+
332
+ def enabled_inittab?
333
+ inspec.command("lsitab #{name}").exit_status == 0
334
+ end
335
+ end
336
+
337
+ # @see: http://upstart.ubuntu.com
338
+ class Upstart < ServiceManager
339
+ def initialize(service_name, service_ctl = nil)
340
+ @service_ctl = service_ctl || 'initctl'
341
+ super
342
+ end
343
+
344
+ def info(service_name)
345
+ # get the status of upstart service
346
+ status = inspec.command("#{service_ctl} status #{service_name}")
347
+
348
+ # fallback for systemv services, those are not handled via `initctl`
349
+ return SysV.new(inspec).info(service_name) if status.exit_status.to_i != 0 || status.stdout == ''
350
+
351
+ # @see: http://upstart.ubuntu.com/cookbook/#job-states
352
+ # grep for running to indicate the service is there
353
+ running = !status.stdout[%r{start/running}].nil?
354
+
355
+ {
356
+ name: service_name,
357
+ description: nil,
358
+ installed: true,
359
+ running: running,
360
+ enabled: info_enabled(service_name),
361
+ type: 'upstart',
362
+ }
363
+ end
364
+
365
+ private
366
+
367
+ def info_enabled(service_name)
368
+ # check if a service is enabled
369
+ config = inspec.file("/etc/init/#{service_name}.conf").content
370
+
371
+ # disregard if the config does not exist
372
+ return nil if config.nil?
373
+
374
+ !config.match(/^\s*start on/).nil?
375
+ end
376
+
377
+ def version
378
+ @version ||= begin
379
+ out = inspec.command("#{service_ctl} --version").stdout
380
+ Gem::Version.new(out[/\(upstart ([^\)]+)\)/, 1])
381
+ end
382
+ end
383
+ end
384
+
385
+ class SysV < ServiceManager
386
+ RUNLEVELS = { 0=>false, 1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false }.freeze
387
+
388
+ def initialize(service_name, service_ctl = nil)
389
+ @service_ctl = service_ctl || 'service'
390
+ super
391
+ end
392
+
393
+ def info(service_name)
394
+ # check if service is installed
395
+ # read all available services via ls /etc/init.d/
396
+ srvlist = inspec.command('ls -1 /etc/init.d/')
397
+ return nil if srvlist.exit_status != 0
398
+
399
+ # check if the service is in list
400
+ service = srvlist.stdout.split("\n").select { |srv| srv == service_name }
401
+
402
+ # abort if we could not find any service
403
+ return nil if service.empty?
404
+
405
+ # read all enabled services from runlevel
406
+ # on rhel via: 'chkconfig --list', is not installed by default
407
+ # bash: for i in `find /etc/rc*.d -name S*`; do basename $i | sed -r 's/^S[0-9]+//'; done | sort | uniq
408
+ enabled_services_cmd = inspec.command('find /etc/rc*.d /etc/init.d/rc*.d -name "S*"').stdout
409
+ service_line = %r{rc(?<runlevel>[0-6])\.d/S[^/]*?#{Regexp.escape service_name}$}
410
+ all_services = enabled_services_cmd.split("\n").map { |line|
411
+ service_line.match(line)
412
+ }.compact
413
+ enabled = !all_services.empty?
414
+
415
+ # Determine a list of runlevels which this service is activated for
416
+ runlevels = RUNLEVELS.dup
417
+ all_services.each { |x| runlevels[x[:runlevel].to_i] = true }
418
+
419
+ # check if service is really running
420
+ # service throws an exit code if the service is not installed or
421
+ # not enabled
422
+
423
+ cmd = inspec.command("#{service_ctl} #{service_name} status")
424
+ running = cmd.exit_status == 0
425
+ {
426
+ name: service_name,
427
+ description: nil,
428
+ installed: true,
429
+ running: running,
430
+ enabled: enabled,
431
+ runlevels: runlevels,
432
+ type: 'sysv',
433
+ }
434
+ end
435
+ end
436
+
437
+ # @see: https://www.freebsd.org/doc/en/articles/linux-users/startup.html
438
+ # @see: https://www.freebsd.org/cgi/man.cgi?query=rc.conf&sektion=5
439
+ class BSDInit < ServiceManager
440
+ def initialize(service_name, service_ctl = nil)
441
+ @service_ctl = service_ctl || 'service'
442
+ super
443
+ end
444
+
445
+ def info(service_name)
446
+ # check if service is enabled
447
+ # services are enabled in /etc/rc.conf and /etc/defaults/rc.conf
448
+ # via #{service_name}_enable="YES"
449
+ # service SERVICE status returns the following result if not activated:
450
+ # Cannot 'status' sshd. Set sshd_enable to YES in /etc/rc.conf or use 'onestatus' instead of 'status'.
451
+ # gather all enabled services
452
+ cmd = inspec.command("#{service_ctl} -e")
453
+ return nil if cmd.exit_status != 0
454
+
455
+ # search for the service
456
+ srv = /(^.*#{service_name}$)/.match(cmd.stdout)
457
+ return nil if srv.nil? || srv[0].nil?
458
+ enabled = true
459
+
460
+ # check if the service is running
461
+ # if the service is not available or not running, we always get an error code
462
+ cmd = inspec.command("#{service_ctl} #{service_name} onestatus")
463
+ running = cmd.exit_status == 0
464
+
465
+ {
466
+ name: service_name,
467
+ description: nil,
468
+ installed: true,
469
+ running: running,
470
+ enabled: enabled,
471
+ type: 'bsd-init',
472
+ }
473
+ end
474
+ end
475
+
476
+ class Runit < ServiceManager
477
+ def initialize(service_name, service_ctl = nil)
478
+ @service_ctl = service_ctl || 'sv'
479
+ super
480
+ end
481
+
482
+ # rubocop:disable Style/DoubleNegation
483
+ def info(service_name)
484
+ # get the status of runit service
485
+ cmd = inspec.command("#{service_ctl} status #{service_name}")
486
+ # return nil unless cmd.exit_status == 0 # NOTE(sr) why do we do this?
487
+
488
+ installed = cmd.exit_status == 0
489
+ running = installed && !!(cmd.stdout =~ /^run:/)
490
+ enabled = installed && (running || !!(cmd.stdout =~ /normally up/) || !!(cmd.stdout =~ /want up/))
491
+
492
+ {
493
+ name: service_name,
494
+ description: nil,
495
+ installed: installed,
496
+ running: running,
497
+ enabled: enabled,
498
+ type: 'runit',
499
+ }
500
+ end
501
+ end
502
+
503
+ # MacOS / Darwin
504
+ # new launctl on macos 10.10
505
+ class LaunchCtl < ServiceManager
506
+ def initialize(service_name, service_ctl = nil)
507
+ @service_ctl = service_ctl || 'launchctl'
508
+ super
509
+ end
510
+
511
+ def info(service_name)
512
+ # get the status of upstart service
513
+ cmd = inspec.command("#{service_ctl} list")
514
+ return nil if cmd.exit_status != 0
515
+
516
+ # search for the service
517
+ srv = /(^.*#{service_name}.*)/.match(cmd.stdout)
518
+ return nil if srv.nil? || srv[0].nil?
519
+
520
+ # extract values from service
521
+ parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[0-9]+)\t(?<name>\S*)$/.match(srv[0])
522
+ enabled = !parsed_srv['name'].nil? # it's in the list
523
+
524
+ # check if the service is running
525
+ pid = parsed_srv['pid']
526
+ running = pid != '-'
527
+
528
+ # extract service label
529
+ srv = parsed_srv['name'] || service_name
530
+
531
+ {
532
+ name: srv,
533
+ description: nil,
534
+ installed: true,
535
+ running: running,
536
+ enabled: enabled,
537
+ type: 'darwin',
538
+ }
539
+ end
540
+ end
541
+
542
+ # Determine the service state from Windows
543
+ # Uses Powershell to retrieve the information
544
+ class WindowsSrv < ServiceManager
545
+ # Determine service details
546
+ # PS: Get-Service -Name 'dhcp'| Select-Object -Property Name, DisplayName, Status | ConvertTo-Json
547
+ # {
548
+ # "Name": "dhcp",
549
+ # "DisplayName": "DHCP Client",
550
+ # "Status": 4
551
+ # }
552
+ #
553
+ # Until StartMode is not added to Get-Service, we need to do a workaround
554
+ # @see: https://connect.microsoft.com/PowerShell/feedback/details/424948/i-would-like-to-see-the-property-starttype-added-to-get-services
555
+ # Also see: https://msdn.microsoft.com/en-us/library/aa384896(v=vs.85).aspx
556
+ # Use the following powershell to determine the start mode
557
+ # PS: Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq $name -or $_.DisplayName -eq $name} | Select-Object -Prop
558
+ # erty Name, StartMode, State, Status | ConvertTo-Json
559
+ # {
560
+ # "Name": "Dhcp",
561
+ # "StartMode": "Auto",
562
+ # "State": "Running",
563
+ # "Status": "OK"
564
+ # }
565
+ #
566
+ # Windows Services have the following status code:
567
+ # @see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
568
+ # - 1: Stopped
569
+ # - 2: Starting
570
+ # - 3: Stopping
571
+ # - 4: Running
572
+ # - 5: Continue Pending
573
+ # - 6: Pause Pending
574
+ # - 7: Paused
575
+ def info(service_name)
576
+ cmd = inspec.command("New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Service -Value (Get-Service -Name '#{service_name}'| Select-Object -Property Name, DisplayName, Status) -PassThru | Add-Member -MemberType NoteProperty -Name WMI -Value (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq '#{service_name}' -or $_.DisplayName -eq '#{service_name}'} | Select-Object -Property StartMode) -PassThru | ConvertTo-Json")
577
+
578
+ # cannot rely on exit code for now, successful command returns exit code 1
579
+ # return nil if cmd.exit_status != 0
580
+ # try to parse json
581
+ begin
582
+ service = JSON.parse(cmd.stdout)
583
+ rescue JSON::ParserError => _e
584
+ return nil
585
+ end
586
+
587
+ # check that we got a response
588
+ return nil if service.nil? || service['Service'].nil?
589
+
590
+ {
591
+ name: service['Service']['Name'],
592
+ description: service['Service']['DisplayName'],
593
+ installed: true,
594
+ running: service_running?(service),
595
+ enabled: service_enabled?(service),
596
+ startmode: service['WMI']['StartMode'],
597
+ type: 'windows',
598
+ }
599
+ end
600
+
601
+ private
602
+
603
+ # detect if service is enabled
604
+ def service_enabled?(service)
605
+ !service['WMI'].nil? &&
606
+ !service['WMI']['StartMode'].nil? &&
607
+ (service['WMI']['StartMode'] == 'Auto' ||
608
+ service['WMI']['StartMode'] == 'Manual')
609
+ end
610
+
611
+ # detect if service is running
612
+ def service_running?(service)
613
+ !service['Service']['Status'].nil? && service['Service']['Status'] == 4
614
+ end
615
+ end
616
+
617
+ # Solaris services
618
+ class Svcs < ServiceManager
619
+ def initialize(service_name, service_ctl = nil)
620
+ @service_ctl = service_ctl || 'svcs'
621
+ super
622
+ end
623
+
624
+ def info(service_name)
625
+ # get the status of runit service
626
+ cmd = inspec.command("#{service_ctl} -l #{service_name}")
627
+ return nil if cmd.exit_status != 0
628
+
629
+ params = SimpleConfig.new(
630
+ cmd.stdout.chomp,
631
+ assignment_regex: /^(\w+)\s*(.*)$/,
632
+ multiple_values: false,
633
+ ).params
634
+
635
+ installed = cmd.exit_status == 0
636
+ running = installed && (params['state'] == 'online')
637
+ enabled = installed && (params['enabled'] == 'true')
638
+
639
+ {
640
+ name: service_name,
641
+ description: params['name'],
642
+ installed: installed,
643
+ running: running,
644
+ enabled: enabled,
645
+ type: 'svcs',
646
+ }
647
+ end
648
+ end
649
+
650
+ # specific resources for specific service managers
651
+
652
+ class SystemdService < Service
653
+ name 'systemd_service'
654
+ supports platform: 'unix'
655
+ desc 'Use the systemd_service InSpec audit resource to test if the named service (controlled by systemd) is installed, running and/or enabled.'
656
+ example "
657
+ # to override service mgmt auto-detection
658
+ describe systemd_service('service_name') do
659
+ it { should be_installed }
660
+ it { should be_enabled }
661
+ it { should be_running }
662
+ end
663
+
664
+ # to set a non-standard systemctl path
665
+ describe systemd_service('service_name', '/path/to/systemctl') do
666
+ it { should be_running }
667
+ end
668
+ "
669
+
670
+ def select_service_mgmt
671
+ Systemd.new(inspec, service_ctl)
672
+ end
673
+ end
674
+
675
+ class UpstartService < Service
676
+ name 'upstart_service'
677
+ supports platform: 'unix'
678
+ desc 'Use the upstart_service InSpec audit resource to test if the named service (controlled by upstart) is installed, running and/or enabled.'
679
+ example "
680
+ # to override service mgmt auto-detection
681
+ describe upstart_service('service_name') do
682
+ it { should be_installed }
683
+ it { should be_enabled }
684
+ it { should be_running }
685
+ end
686
+
687
+ # to set a non-standard initctl path
688
+ describe upstart_service('service_name', '/path/to/initctl') do
689
+ it { should be_running }
690
+ end
691
+ "
692
+
693
+ def select_service_mgmt
694
+ Upstart.new(inspec, service_ctl)
695
+ end
696
+ end
697
+
698
+ class SysVService < Service
699
+ name 'sysv_service'
700
+ supports platform: 'unix'
701
+ desc 'Use the sysv_service InSpec audit resource to test if the named service (controlled by SysV) is installed, running and/or enabled.'
702
+ example "
703
+ # to override service mgmt auto-detection
704
+ describe sysv_service('service_name') do
705
+ it { should be_installed }
706
+ it { should be_enabled }
707
+ it { should be_running }
708
+ end
709
+
710
+ # to set a non-standard service path
711
+ describe sysv_service('service_name', '/path/to/service') do
712
+ it { should be_running }
713
+ end
714
+ "
715
+
716
+ def select_service_mgmt
717
+ SysV.new(inspec, service_ctl)
718
+ end
719
+ end
720
+
721
+ class BSDService < Service
722
+ name 'bsd_service'
723
+ supports platform: 'unix'
724
+ desc 'Use the bsd_service InSpec audit resource to test if the named service (controlled by BSD init) is installed, running and/or enabled.'
725
+ example "
726
+ # to override service mgmt auto-detection
727
+ describe bsd_service('service_name') do
728
+ it { should be_installed }
729
+ it { should be_enabled }
730
+ it { should be_running }
731
+ end
732
+
733
+ # to set a non-standard service path
734
+ describe bsd_service('service_name', '/path/to/service') do
735
+ it { should be_running }
736
+ end
737
+ "
738
+
739
+ def select_service_mgmt
740
+ BSDInit.new(inspec, service_ctl)
741
+ end
742
+ end
743
+
744
+ class LaunchdService < Service
745
+ name 'launchd_service'
746
+ supports platform: 'unix'
747
+ desc 'Use the launchd_service InSpec audit resource to test if the named service (controlled by launchd) is installed, running and/or enabled.'
748
+ example "
749
+ # to override service mgmt auto-detection
750
+ describe launchd_service('service_name') do
751
+ it { should be_installed }
752
+ it { should be_enabled }
753
+ it { should be_running }
754
+ end
755
+
756
+ # to set a non-standard launchctl path
757
+ describe launchd_service('service_name', '/path/to/launchctl') do
758
+ it { should be_running }
759
+ end
760
+ "
761
+
762
+ def select_service_mgmt
763
+ LaunchCtl.new(inspec, service_ctl)
764
+ end
765
+ end
766
+
767
+ class RunitService < Service
768
+ name 'runit_service'
769
+ supports platform: 'unix'
770
+ desc 'Use the runit_service InSpec audit resource to test if the named service (controlled by runit) is installed, running and/or enabled.'
771
+ example "
772
+ # to override service mgmt auto-detection
773
+ describe runit_service('service_name') do
774
+ it { should be_installed }
775
+ it { should be_enabled }
776
+ it { should be_running }
777
+ end
778
+
779
+ # to set a non-standard sv path
780
+ describe runit_service('service_name', '/path/to/sv') do
781
+ it { should be_running }
782
+ end
783
+ "
784
+
785
+ def select_service_mgmt
786
+ Runit.new(inspec, service_ctl)
787
+ end
788
+ end
789
+ end