inspec 2.0.32 → 2.0.45

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