inspec 1.0.0 → 1.35.1

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 (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +933 -101
  3. data/Gemfile +8 -17
  4. data/MAINTAINERS.md +2 -1
  5. data/MAINTAINERS.toml +9 -4
  6. data/README.md +49 -28
  7. data/Rakefile +54 -39
  8. data/bin/inspec +1 -1
  9. data/docs/dsl_inspec.md +17 -4
  10. data/docs/dsl_resource.md +1 -1
  11. data/docs/habitat.md +192 -0
  12. data/docs/inspec_and_friends.md +4 -2
  13. data/docs/matchers.md +11 -0
  14. data/docs/migration.md +293 -0
  15. data/docs/profiles.md +124 -76
  16. data/docs/resources/aide_conf.md.erb +81 -0
  17. data/docs/resources/apache_conf.md.erb +10 -10
  18. data/docs/resources/apt.md.erb +13 -13
  19. data/docs/resources/audit_policy.md.erb +10 -10
  20. data/docs/resources/auditd_conf.md.erb +10 -10
  21. data/docs/resources/auditd_rules.md.erb +11 -11
  22. data/docs/resources/bash.md.erb +12 -12
  23. data/docs/resources/bond.md.erb +15 -15
  24. data/docs/resources/bridge.md.erb +11 -11
  25. data/docs/resources/bsd_service.md.erb +11 -11
  26. data/docs/resources/command.md.erb +23 -23
  27. data/docs/resources/crontab.md.erb +84 -0
  28. data/docs/resources/csv.md.erb +10 -10
  29. data/docs/resources/dh_params.md +191 -0
  30. data/docs/resources/directory.md.erb +8 -8
  31. data/docs/resources/docker.md.erb +160 -0
  32. data/docs/resources/docker_container.md.erb +89 -0
  33. data/docs/resources/docker_image.md.erb +86 -0
  34. data/docs/resources/etc_group.md.erb +16 -16
  35. data/docs/resources/etc_hosts.md.erb +62 -0
  36. data/docs/resources/file.md.erb +80 -58
  37. data/docs/resources/gem.md.erb +32 -13
  38. data/docs/resources/group.md.erb +12 -12
  39. data/docs/resources/grub_conf.md.erb +11 -11
  40. data/docs/resources/host.md.erb +27 -18
  41. data/docs/resources/http.md.erb +104 -0
  42. data/docs/resources/iis_app.md.erb +126 -0
  43. data/docs/resources/iis_site.md.erb +17 -17
  44. data/docs/resources/inetd_conf.md.erb +10 -10
  45. data/docs/resources/ini.md.erb +9 -9
  46. data/docs/resources/interface.md.erb +13 -13
  47. data/docs/resources/iptables.md.erb +21 -14
  48. data/docs/resources/json.md.erb +11 -11
  49. data/docs/resources/kernel_module.md.erb +73 -12
  50. data/docs/resources/kernel_parameter.md.erb +12 -12
  51. data/docs/resources/key_rsa.md.erb +70 -0
  52. data/docs/resources/launchd_service.md.erb +11 -11
  53. data/docs/resources/limits_conf.md.erb +10 -10
  54. data/docs/resources/login_def.md.erb +12 -12
  55. data/docs/resources/mount.md.erb +14 -14
  56. data/docs/resources/mssql_session.md.erb +62 -0
  57. data/docs/resources/mysql_conf.md.erb +14 -14
  58. data/docs/resources/mysql_session.md.erb +22 -10
  59. data/docs/resources/npm.md.erb +13 -13
  60. data/docs/resources/ntp_conf.md.erb +9 -9
  61. data/docs/resources/oneget.md.erb +11 -11
  62. data/docs/resources/oracledb_session.md.erb +53 -0
  63. data/docs/resources/os.md.erb +17 -17
  64. data/docs/resources/os_env.md.erb +12 -12
  65. data/docs/resources/package.md.erb +29 -16
  66. data/docs/resources/parse_config.md.erb +18 -18
  67. data/docs/resources/parse_config_file.md.erb +29 -23
  68. data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +17 -17
  69. data/docs/resources/pip.md.erb +15 -15
  70. data/docs/resources/port.md.erb +23 -23
  71. data/docs/resources/postgres_conf.md.erb +15 -13
  72. data/docs/resources/postgres_hba_conf.md.erb +104 -0
  73. data/docs/resources/postgres_ident_conf.md.erb +87 -0
  74. data/docs/resources/postgres_session.md.erb +28 -21
  75. data/docs/resources/powershell.md.erb +14 -14
  76. data/docs/resources/processes.md.erb +123 -0
  77. data/docs/resources/rabbitmq_config.md.erb +55 -0
  78. data/docs/resources/registry_key.md.erb +44 -21
  79. data/docs/resources/runit_service.md.erb +11 -11
  80. data/docs/resources/security_policy.md.erb +10 -10
  81. data/docs/resources/service.md.erb +18 -18
  82. data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +19 -19
  83. data/docs/resources/ssh_config.md.erb +13 -13
  84. data/docs/resources/sshd_config.md.erb +15 -15
  85. data/docs/resources/ssl.md.erb +13 -13
  86. data/docs/resources/sys_info.md.erb +10 -10
  87. data/docs/resources/systemd_service.md.erb +11 -11
  88. data/docs/resources/sysv_service.md.erb +11 -11
  89. data/docs/resources/upstart_service.md.erb +11 -11
  90. data/docs/resources/user.md.erb +20 -20
  91. data/docs/resources/users.md.erb +19 -19
  92. data/docs/resources/vbscript.md.erb +13 -13
  93. data/docs/resources/virtualization.md.erb +71 -0
  94. data/docs/resources/windows_feature.md.erb +10 -10
  95. data/docs/resources/windows_task.md.erb +103 -0
  96. data/docs/resources/wmi.md.erb +10 -10
  97. data/docs/resources/x509_certificate.md.erb +146 -0
  98. data/docs/resources/xinetd_conf.md.erb +17 -17
  99. data/docs/resources/xml.md.erb +75 -0
  100. data/docs/resources/yaml.md.erb +25 -11
  101. data/docs/resources/yum.md.erb +24 -16
  102. data/docs/resources/zfs_dataset.md.erb +63 -0
  103. data/docs/resources/zfs_pool.md.erb +57 -0
  104. data/docs/ruby_usage.md +50 -0
  105. data/docs/shared/matcher_cmp.md.erb +4 -6
  106. data/examples/inheritance/README.md +49 -3
  107. data/examples/inheritance/controls/example.rb +4 -1
  108. data/examples/inheritance/inspec.yml +3 -1
  109. data/examples/meta-profile/README.md +29 -3
  110. data/examples/meta-profile/controls/example.rb +10 -5
  111. data/examples/meta-profile/inspec.yml +4 -8
  112. data/examples/profile/README.md +1 -1
  113. data/examples/profile/controls/example.rb +0 -1
  114. data/examples/profile/controls/gordon.rb +0 -1
  115. data/examples/profile/inspec.yml +1 -1
  116. data/examples/profile-attribute/inspec.yml +1 -1
  117. data/examples/profile-sensitive/README.md +29 -0
  118. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
  119. data/examples/profile-sensitive/controls/sensitive.rb +9 -0
  120. data/examples/profile-sensitive/inspec.yml +8 -0
  121. data/inspec.gemspec +10 -2
  122. data/lib/bundles/inspec-artifact/README.md +1 -0
  123. data/lib/bundles/inspec-artifact/cli.rb +284 -0
  124. data/lib/bundles/inspec-artifact.rb +7 -0
  125. data/lib/bundles/inspec-compliance/README.md +44 -15
  126. data/lib/bundles/inspec-compliance/api.rb +135 -29
  127. data/lib/bundles/inspec-compliance/cli.rb +128 -21
  128. data/lib/bundles/inspec-compliance/configuration.rb +8 -0
  129. data/lib/bundles/inspec-compliance/http.rb +26 -19
  130. data/lib/bundles/inspec-compliance/target.rb +50 -25
  131. data/lib/bundles/inspec-habitat/cli.rb +31 -0
  132. data/lib/bundles/inspec-habitat/log.rb +10 -0
  133. data/lib/bundles/inspec-habitat/profile.rb +372 -0
  134. data/lib/bundles/inspec-habitat.rb +12 -0
  135. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +0 -1
  136. data/lib/bundles/inspec-init/templates/profile/inspec.yml +1 -1
  137. data/lib/bundles/inspec-supermarket/api.rb +7 -5
  138. data/lib/bundles/inspec-supermarket/cli.rb +2 -2
  139. data/lib/fetchers/git.rb +4 -2
  140. data/lib/fetchers/local.rb +4 -1
  141. data/lib/fetchers/url.rb +64 -10
  142. data/lib/inspec/archive/tar.rb +1 -1
  143. data/lib/inspec/backend.rb +26 -3
  144. data/lib/inspec/base_cli.rb +44 -7
  145. data/lib/inspec/cached_fetcher.rb +2 -2
  146. data/lib/inspec/cli.rb +34 -12
  147. data/lib/inspec/completions/fish.sh.erb +34 -0
  148. data/lib/inspec/control_eval_context.rb +0 -2
  149. data/lib/inspec/dependencies/cache.rb +0 -1
  150. data/lib/inspec/dependencies/dependency_set.rb +2 -2
  151. data/lib/inspec/dependencies/lockfile.rb +13 -6
  152. data/lib/inspec/dependencies/requirement.rb +6 -6
  153. data/lib/inspec/dependencies/resolver.rb +4 -4
  154. data/lib/inspec/dsl.rb +3 -5
  155. data/lib/inspec/env_printer.rb +9 -1
  156. data/lib/inspec/exceptions.rb +8 -0
  157. data/lib/inspec/fetcher.rb +1 -1
  158. data/lib/inspec/file_provider.rb +47 -11
  159. data/lib/inspec/library_eval_context.rb +1 -1
  160. data/lib/inspec/metadata.rb +62 -18
  161. data/lib/inspec/method_source.rb +24 -0
  162. data/lib/inspec/objects/attribute.rb +21 -0
  163. data/lib/inspec/objects/control.rb +21 -3
  164. data/lib/inspec/objects/each_loop.rb +2 -1
  165. data/lib/inspec/objects/list.rb +1 -1
  166. data/lib/inspec/objects/or_test.rb +17 -2
  167. data/lib/inspec/objects/tag.rb +27 -0
  168. data/lib/inspec/objects/test.rb +9 -8
  169. data/lib/inspec/objects.rb +1 -0
  170. data/lib/inspec/plugins/fetcher.rb +4 -5
  171. data/lib/inspec/plugins/resource.rb +1 -2
  172. data/lib/inspec/plugins/source_reader.rb +3 -3
  173. data/lib/inspec/plugins.rb +1 -1
  174. data/lib/inspec/polyfill.rb +0 -1
  175. data/lib/inspec/profile.rb +92 -23
  176. data/lib/inspec/profile_context.rb +1 -1
  177. data/lib/inspec/profile_vendor.rb +66 -0
  178. data/lib/inspec/resource.rb +29 -3
  179. data/lib/inspec/rspec_json_formatter.rb +672 -285
  180. data/lib/inspec/rule.rb +12 -16
  181. data/lib/inspec/runner.rb +26 -15
  182. data/lib/inspec/runner_rspec.rb +1 -0
  183. data/lib/inspec/runtime_profile.rb +26 -0
  184. data/lib/inspec/schema.rb +185 -0
  185. data/lib/inspec/secrets/yaml.rb +8 -1
  186. data/lib/inspec/secrets.rb +1 -1
  187. data/lib/inspec/shell.rb +92 -22
  188. data/lib/inspec/source_reader.rb +1 -1
  189. data/lib/inspec/version.rb +1 -1
  190. data/lib/inspec.rb +1 -1
  191. data/lib/matchers/matchers.rb +67 -17
  192. data/lib/resources/aide_conf.rb +162 -0
  193. data/lib/resources/apache.rb +0 -1
  194. data/lib/resources/apache_conf.rb +3 -3
  195. data/lib/resources/apt.rb +2 -1
  196. data/lib/resources/audit_policy.rb +0 -1
  197. data/lib/resources/auditd_conf.rb +1 -2
  198. data/lib/resources/auditd_rules.rb +5 -5
  199. data/lib/resources/bond.rb +1 -1
  200. data/lib/resources/bridge.rb +1 -1
  201. data/lib/resources/command.rb +5 -3
  202. data/lib/resources/crontab.rb +102 -0
  203. data/lib/resources/csv.rb +18 -1
  204. data/lib/resources/dh_params.rb +84 -0
  205. data/lib/resources/directory.rb +7 -3
  206. data/lib/resources/docker.rb +198 -0
  207. data/lib/resources/docker_container.rb +114 -0
  208. data/lib/resources/docker_image.rb +96 -0
  209. data/lib/resources/etc_group.rb +2 -3
  210. data/lib/resources/etc_hosts.rb +81 -0
  211. data/lib/resources/file.rb +88 -30
  212. data/lib/resources/gem.rb +26 -6
  213. data/lib/resources/groups.rb +4 -5
  214. data/lib/resources/grub_conf.rb +3 -4
  215. data/lib/resources/host.rb +175 -35
  216. data/lib/resources/http.rb +73 -0
  217. data/lib/resources/iis_app.rb +103 -0
  218. data/lib/resources/iis_site.rb +23 -0
  219. data/lib/resources/inetd_conf.rb +9 -4
  220. data/lib/resources/interface.rb +4 -3
  221. data/lib/resources/json.rb +37 -14
  222. data/lib/resources/kernel_module.rb +77 -10
  223. data/lib/resources/kernel_parameter.rb +0 -1
  224. data/lib/resources/key_rsa.rb +67 -0
  225. data/lib/resources/limits_conf.rb +3 -4
  226. data/lib/resources/login_def.rb +2 -3
  227. data/lib/resources/mount.rb +34 -4
  228. data/lib/resources/mssql_session.rb +81 -12
  229. data/lib/resources/mysql.rb +0 -1
  230. data/lib/resources/mysql_conf.rb +1 -2
  231. data/lib/resources/mysql_session.rb +18 -7
  232. data/lib/resources/nginx_conf.rb +95 -0
  233. data/lib/resources/ntp_conf.rb +2 -3
  234. data/lib/resources/oracledb_session.rb +138 -0
  235. data/lib/resources/os_env.rb +7 -5
  236. data/lib/resources/package.rb +70 -13
  237. data/lib/resources/packages.rb +111 -0
  238. data/lib/resources/parse_config.rb +3 -4
  239. data/lib/resources/passwd.rb +4 -5
  240. data/lib/resources/pip.rb +29 -21
  241. data/lib/resources/port.rb +133 -14
  242. data/lib/resources/postgres.rb +53 -43
  243. data/lib/resources/postgres_conf.rb +40 -13
  244. data/lib/resources/postgres_hba_conf.rb +101 -0
  245. data/lib/resources/postgres_ident_conf.rb +79 -0
  246. data/lib/resources/postgres_session.rb +28 -20
  247. data/lib/resources/powershell.rb +2 -2
  248. data/lib/resources/processes.rb +61 -26
  249. data/lib/resources/rabbitmq_conf.rb +53 -0
  250. data/lib/resources/registry_key.rb +34 -11
  251. data/lib/resources/security_policy.rb +2 -2
  252. data/lib/resources/service.rb +17 -7
  253. data/lib/resources/ssh_conf.rb +17 -6
  254. data/lib/resources/ssl.rb +3 -4
  255. data/lib/resources/sys_info.rb +1 -1
  256. data/lib/resources/toml.rb +26 -0
  257. data/lib/resources/users.rb +41 -41
  258. data/lib/resources/virtualization.rb +252 -0
  259. data/lib/resources/windows_task.rb +106 -0
  260. data/lib/resources/x509_certificate.rb +143 -0
  261. data/lib/resources/xinetd.rb +18 -2
  262. data/lib/resources/xml.rb +27 -0
  263. data/lib/resources/yaml.rb +10 -2
  264. data/lib/resources/yum.rb +25 -7
  265. data/lib/resources/zfs_dataset.rb +60 -0
  266. data/lib/resources/zfs_pool.rb +49 -0
  267. data/lib/source_readers/flat.rb +2 -1
  268. data/lib/source_readers/inspec.rb +30 -11
  269. data/lib/utils/command_wrapper.rb +3 -3
  270. data/lib/utils/database_helpers.rb +77 -0
  271. data/lib/utils/erlang_parser.rb +192 -0
  272. data/lib/utils/filter.rb +2 -1
  273. data/lib/utils/filter_array.rb +0 -1
  274. data/lib/utils/find_files.rb +1 -2
  275. data/lib/utils/latest_version.rb +21 -0
  276. data/lib/utils/nginx_parser.rb +76 -0
  277. data/lib/utils/object_traversal.rb +5 -4
  278. data/lib/utils/parser.rb +23 -4
  279. data/lib/utils/plugin_registry.rb +3 -3
  280. data/lib/utils/simpleconfig.rb +25 -8
  281. data/lib/utils/spdx.rb +13 -0
  282. data/lib/utils/spdx.txt +344 -0
  283. metadata +168 -22
  284. data/docs/cli.md +0 -342
  285. data/docs/resources/process.md.erb +0 -73
  286. /data/docs/{plugin_kitchen_inspec.html.md → plugin_kitchen_inspec.md} +0 -0
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Richter
4
+
5
+ module DatabaseHelper
6
+ class SQLColumn
7
+ def initialize(row, name)
8
+ @row = row
9
+ @name = name
10
+ end
11
+
12
+ def value
13
+ @row[@name.downcase]
14
+ end
15
+
16
+ def to_s
17
+ 'SQL Column'
18
+ end
19
+ end
20
+
21
+ class SQLRow
22
+ def initialize(query, row)
23
+ @query = query
24
+ @row = row
25
+ end
26
+
27
+ def column(column)
28
+ SQLColumn.new(@row, column)
29
+ end
30
+
31
+ def to_s
32
+ 'SQL Row'
33
+ end
34
+ end
35
+
36
+ class SQLQueryResult
37
+ attr_reader :error
38
+ def initialize(cmd, results)
39
+ @cmd = cmd
40
+ @results = results
41
+ end
42
+
43
+ def empty?
44
+ @results.empty?
45
+ end
46
+
47
+ def successful?
48
+ @cmd.exit_status == 0 && @error.nil?
49
+ end
50
+
51
+ def row(id)
52
+ SQLRow.new(self, @results[id])
53
+ end
54
+
55
+ def size
56
+ @results.size
57
+ end
58
+
59
+ def stdout
60
+ warn '[DEPRECATION] The `stdout` method is deprecated. Use `row` instead.'
61
+ @cmd.stdout
62
+ end
63
+
64
+ def stderr
65
+ warn '[DEPRECATION] The `stderr` method is deprecated. Use `successful?` instead.'
66
+ @cmd.stderr
67
+ end
68
+
69
+ def inspect
70
+ to_s
71
+ end
72
+
73
+ def to_s
74
+ 'SQL ResultSet'
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,192 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require 'parslet'
6
+
7
+ class ErlangParser < Parslet::Parser
8
+ root :outermost
9
+ # only designed for rabbitmq config files for now:
10
+ rule(:outermost) { filler? >> array.maybe >> dot.maybe }
11
+
12
+ rule(:exp) {
13
+ (tuple | array | binary | string | bool | identifier | float | integer) >> filler?
14
+ }
15
+
16
+ rule(:array) {
17
+ str('[') >> filler? >> (
18
+ exp.repeat(1) >>
19
+ (comma >> exp).repeat
20
+ ).maybe.as(:array) >> str(']') >> filler?
21
+ }
22
+
23
+ rule(:tuple) {
24
+ str('{') >> filler? >> (
25
+ exp.repeat(1) >> filler? >>
26
+ (comma >> exp).repeat
27
+ ).maybe.as(:tuple) >> str('}') >> filler?
28
+ }
29
+
30
+ rule(:filler?) { space.repeat }
31
+ rule(:space) { match('\s+') | match["\n"] | comment }
32
+
33
+ rule(:comment) { str('%') >> (match["\n\r"].absent? >> any).repeat }
34
+ rule(:comma) { str(',') >> filler? }
35
+ rule(:dot) { str('.') >> filler? }
36
+ rule(:bool) { str('true').as(:bool) | str('false').as(:bool) }
37
+
38
+ rule(:identifier) {
39
+ (match('[a-zA-Z]') >> match('[a-zA-Z0-9_]').repeat).as(:identifier) >> filler?
40
+ }
41
+
42
+ rule(:float) {
43
+ (
44
+ integer >> (
45
+ str('.') >> match('[0-9]').repeat(1) |
46
+ str('e') >> match('[0-9]').repeat(1)
47
+ ).as(:e)
48
+ ).as(:float) >> filler?
49
+ }
50
+
51
+ rule(:integer) {
52
+ ((str('+') | str('-')).maybe >> match('[0-9]').repeat(1)).as(:integer) >> filler?
53
+ }
54
+
55
+ rule(:string) { stringS | stringD }
56
+
57
+ rule(:stringS) {
58
+ str("'") >> (
59
+ str('\\') >> any | str("'").absent? >> any
60
+ ).repeat.as(:string) >> str("'") >> filler?
61
+ }
62
+
63
+ rule(:stringD) {
64
+ str('"') >> (
65
+ str('\\') >> any | str('"').absent? >> any
66
+ ).repeat.as(:string) >> str('"') >> filler?
67
+ }
68
+
69
+ rule(:binary_item) {
70
+ (string | integer) >>
71
+ (str(':') >> integer).maybe.as(:size) >>
72
+ (str('/') >> identifier).maybe.as(:type) >>
73
+ filler?
74
+ }
75
+
76
+ rule(:binary) {
77
+ str('<<') >> filler? >> (
78
+ binary_item.repeat(1) >>
79
+ (comma >> binary_item).repeat
80
+ ).maybe.as(:binary) >> str('>>') >> filler?
81
+ }
82
+ end
83
+
84
+ class ErlangBitstream
85
+ def initialize
86
+ @data = [] # a stream of 8-bit numbers
87
+ @cur_bits = '' # a string of binary bits 10010010...
88
+ end
89
+
90
+ TYPES = {
91
+ 'integer' => 8,
92
+ 'float' => 8*8,
93
+ 'utf8' => 8,
94
+ 'utf16' => 8*2,
95
+ 'utf32' => 8*4,
96
+ }.freeze
97
+
98
+ def bit_size(size, type)
99
+ raise 'Cannot specify size and type at the same time.' if !type.nil? && !size.nil?
100
+ return (size || 8).to_i if type.nil?
101
+ TYPES[type] || raise("Cannot handle binary-stream type #{type}")
102
+ end
103
+
104
+ def add(i)
105
+ if i[:integer].nil? && i[:string].nil?
106
+ raise 'No data provided, internal error for binary-stream processing!'
107
+ end
108
+ s = bit_size(i[:size], i[:type])
109
+ unless i[:string].nil?
110
+ str2int(i[:string].to_s, i[:type]).map { |e| add_bits(int2bits(e, 8)) }
111
+ else
112
+ add_int(i[:integer], s)
113
+ end
114
+ rescue RuntimeError => e
115
+ raise 'Error processing Erlang bit string '\
116
+ "'#{i[:string] || i[:integer]}:#{i[:size]}/#{i[:type]}'. #{e.message}"
117
+ end
118
+
119
+ def str2int(s, type)
120
+ case type
121
+ when 'utf8' then s.encode('utf-8').unpack('C*')
122
+ when 'utf16' then s.encode('utf-16').unpack('C*').drop(2)
123
+ when 'utf32' then s.encode('utf-32').unpack('C*').drop(4)
124
+ when 'integer', 'float' then raise "Cannot handle bit string as type #{type}"
125
+ else s.split('').map { |x| x.ord & 0xff }
126
+ end
127
+ end
128
+
129
+ def int2bits(i, len)
130
+ format("%0#{len}b", i)
131
+ end
132
+
133
+ def add_int(v, size)
134
+ x = v.to_i & (2**size - 1) # only get the bits specified in size
135
+ add_bits(int2bits(x, size))
136
+ end
137
+
138
+ def add_bits(s)
139
+ b = (@cur_bits + s).scan(/.{1,8}/)
140
+ @data += b[0..-2].map { |x| x.to_i(2) }
141
+ @cur_bits = b.last
142
+ end
143
+
144
+ def value(encoding = 'utf-8')
145
+ # fill in the rest
146
+ rest = '0' * (8 - @cur_bits.length) + @cur_bits
147
+ arr = @data + [rest.to_i(2)]
148
+ s = arr.pack('C*')
149
+ s.force_encoding(encoding) unless encoding.nil?
150
+ s
151
+ end
152
+ end
153
+
154
+ class ErlangTransform < Parslet::Transform
155
+ class Tuple < Array; end
156
+ class Identifier < String; end
157
+
158
+ def self.assemble_binary(seq)
159
+ b = ErlangBitstream.new
160
+ seq.each { |i| b.add(i) }
161
+ b.value
162
+ end
163
+
164
+ rule(string: simple(:x)) { x.to_s }
165
+ rule(string: []) { '' }
166
+ rule(integer: simple(:x)) { x.to_i }
167
+ rule(float: { integer: simple(:a), e: simple(:b) }) { (a+b).to_f }
168
+ rule(bool: 'true') { true }
169
+ rule(bool: 'false') { false }
170
+ rule(binary: subtree(:x)) { x.nil? ? '' : ErlangTransform.assemble_binary(x) }
171
+ rule(identifier: simple(:x)) { Identifier.new(x.to_s) }
172
+ rule(array: subtree(:x)) { Array(x) }
173
+ rule(tuple: subtree(:x)) {
174
+ x.nil? ? Tuple.new : Tuple.new(x)
175
+ }
176
+ end
177
+
178
+ class ErlangConfigFile
179
+ def self.parse(content)
180
+ lex = ErlangParser.new.parse(content)
181
+ tree = ErlangTransform.new.apply(lex)
182
+ turn_to_hash(tree)
183
+ end
184
+
185
+ def self.turn_to_hash(t)
186
+ if t.is_a?(Array) && t.all? { |x| x.class == ErlangTransform::Tuple && x.length == 2 }
187
+ Hash[t.map { |i| [i[0], turn_to_hash(i[1])] }]
188
+ else
189
+ t
190
+ end
191
+ end
192
+ end
data/lib/utils/filter.rb CHANGED
@@ -44,6 +44,7 @@ module FilterTable
44
44
  def initialize(resource, params, filters)
45
45
  @resource = resource
46
46
  @params = params
47
+ @params = [] if @params.nil?
47
48
  @filters = filters
48
49
  end
49
50
 
@@ -69,7 +70,7 @@ module FilterTable
69
70
  end
70
71
 
71
72
  def new_entry(*_)
72
- fail "#{self.class} must not be used on its own. It must be inherited "\
73
+ raise "#{self.class} must not be used on its own. It must be inherited "\
73
74
  'and the #new_entry method must be implemented. This is an internal '\
74
75
  'error and should not happen.'
75
76
  end
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
  # copyright: 2015, Chef Software, Inc.
3
- # license: All rights reserved
4
3
  # author: Stephan Renatus
5
4
 
6
5
  class FilterArray
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
  # copyright: 2015, Vulcano Security GmbH
3
- # license: All rights reserved
4
3
  # author: Dominik Richter
5
4
  # author: Christoph Hartmann
6
5
 
@@ -26,8 +25,8 @@ module FindFiles
26
25
  type = TYPES[opts[:type].to_sym] if opts[:type]
27
26
 
28
27
  cmd = "find #{path}"
29
- cmd += " -maxdepth #{depth.to_i}" if depth.to_i > 0
30
28
  cmd += " -type #{type}" unless type.nil?
29
+ cmd += " -maxdepth #{depth.to_i}" if depth.to_i > 0
31
30
 
32
31
  result = inspec.command(cmd)
33
32
  exit_status = result.exit_status
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+
4
+ require 'json'
5
+ require 'net/http'
6
+
7
+ class LatestInSpecVersion
8
+ # fetches the latest version from rubygems server
9
+ def latest
10
+ uri = URI('https://rubygems.org/api/v1/gems/inspec.json')
11
+ res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https',
12
+ open_timeout: 0.5, read_timeout: 0.5
13
+ ) {|http|
14
+ http.get(uri.path)
15
+ }
16
+ inspec_info = JSON.parse(res.body)
17
+ inspec_info['version']
18
+ rescue Exception # rubocop:disable Lint/RescueException
19
+ nil
20
+ end
21
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require 'parslet'
6
+
7
+ class NginxParser < Parslet::Parser
8
+ root :outermost
9
+ # only designed for rabbitmq config files for now:
10
+ rule(:outermost) { filler? >> exp.repeat }
11
+
12
+ rule(:filler?) { one_filler.repeat }
13
+ rule(:one_filler) { match('\s+') | match["\n"] | comment }
14
+ rule(:space) { match('\s+') }
15
+ rule(:comment) { str('#') >> (match["\n\r"].absent? >> any).repeat }
16
+
17
+ rule(:exp) {
18
+ section | assignment
19
+ }
20
+ rule(:assignment) {
21
+ (identifier >> values.maybe.as(:args)).as(:assignment) >> str(';') >> filler?
22
+ }
23
+
24
+ rule(:identifier) {
25
+ (match('[a-zA-Z]') >> match('\S').repeat).as(:identifier) >> space >> space.repeat
26
+ }
27
+
28
+ rule(:value) {
29
+ ((match('[#;{]').absent? >> any) >> (
30
+ str('\\') >> any | match('[#;{]|\s').absent? >> any
31
+ ).repeat).as(:value) >> space.repeat
32
+ }
33
+ rule(:values) {
34
+ value.repeat >> space.maybe
35
+ }
36
+
37
+ rule(:section) {
38
+ identifier.as(:section) >> values.maybe.as(:args) >> str('{') >> filler? >> exp.repeat.as(:expressions) >> str('}') >> filler?
39
+ }
40
+ end
41
+
42
+ class NginxTransform < Parslet::Transform
43
+ Group = Struct.new(:id, :args, :body)
44
+ Exp = Struct.new(:key, :vals)
45
+
46
+ def self.assemble_binary(seq)
47
+ b = ErlangBitstream.new
48
+ seq.each { |i| b.add(i) }
49
+ b.value
50
+ end
51
+
52
+ rule(section: { identifier: simple(:x) }, args: subtree(:y), expressions: subtree(:z)) { Group.new(x.to_s, y, z) }
53
+ rule(assignment: { identifier: simple(:x), args: subtree(:y) }) { Exp.new(x.to_s, y) }
54
+ rule(value: simple(:x)) { x.to_s }
55
+ end
56
+
57
+ class NginxConfig
58
+ def self.parse(content)
59
+ lex = NginxParser.new.parse(content)
60
+ tree = NginxTransform.new.apply(lex)
61
+ gtree = NginxTransform::Group.new(nil, '', tree)
62
+ read_nginx_group(gtree)
63
+ rescue Parslet::ParseFailed => err
64
+ raise "Failed to parse NginX config: #{err}"
65
+ end
66
+
67
+ def self.read_nginx_group(t)
68
+ agg_conf = Hash.new([])
69
+ agg_conf['_'] = t.args unless t.args == ''
70
+
71
+ groups, conf = t.body.partition { |i| i.is_a? NginxTransform::Group }
72
+ conf.each { |x| agg_conf[x.key] += [x.vals] }
73
+ groups.each { |x| agg_conf[x.id] += [read_nginx_group(x)] }
74
+ agg_conf
75
+ end
76
+ end
@@ -6,11 +6,12 @@ module ObjectTraverser
6
6
  key = keys.shift
7
7
  return nil if key.nil? || value.nil?
8
8
 
9
- # if value is an array, iterate over each child
10
9
  if value.is_a?(Array)
11
- value = value.map { |i|
12
- extract_value([key], i)
13
- }
10
+ value = if key.is_a?(Fixnum)
11
+ value[key]
12
+ elsif value.respond_to?(key.to_sym)
13
+ value.send(key.to_sym)
14
+ end
14
15
  else
15
16
  value = value[key.to_s].nil? ? nil : value[key.to_s]
16
17
  end
data/lib/utils/parser.rb CHANGED
@@ -63,7 +63,7 @@ module CommentParser
63
63
  end
64
64
  end
65
65
 
66
- module MountParser
66
+ module LinuxMountParser
67
67
  # this parses the output of mount command (only tested on linux)
68
68
  # this method expects only one line of the mount output
69
69
  def parse_mount_options(mount_line, compatibility = false)
@@ -94,6 +94,20 @@ module MountParser
94
94
  end
95
95
  end
96
96
 
97
+ module BsdMountParser
98
+ # this parses the output of mount command (only tested on freebsd)
99
+ # this method expects only one line of the mount output
100
+ def parse_mount_options(mount_line, _compatibility = false)
101
+ return {} if mount_line.nil? || mount_line.empty?
102
+
103
+ mount = mount_line.chomp.split(' ', 4)
104
+ options = mount[3].tr('()', '').split(', ')
105
+
106
+ # parse device and type
107
+ { device: mount[0], type: options.shift, options: options }
108
+ end
109
+ end
110
+
97
111
  module SolarisNetstatParser
98
112
  # takes this as a input and parses the values
99
113
  # UDP: IPv4
@@ -197,7 +211,7 @@ module XinetdParser
197
211
  res = {}
198
212
  cur_group = nil
199
213
  simple_conf = []
200
- rest = raw
214
+ rest = raw + "\n"
201
215
  until rest.empty?
202
216
  # extract content line
203
217
  nl = rest.index("\n") || (rest.length-1)
@@ -209,7 +223,12 @@ module XinetdParser
209
223
  next if inner_line.empty?
210
224
 
211
225
  if inner_line == '}'
212
- res[cur_group] = SimpleConfig.new(simple_conf.join("\n"))
226
+ if cur_group == 'defaults'
227
+ res[cur_group] = SimpleConfig.new(simple_conf.join("\n"))
228
+ else
229
+ res[cur_group] ||= []
230
+ res[cur_group].push(SimpleConfig.new(simple_conf.join("\n")))
231
+ end
213
232
  cur_group = nil
214
233
  elsif rest.lstrip[0] == '{'
215
234
  cur_group = inner_line
@@ -224,7 +243,7 @@ module XinetdParser
224
243
  others.each { |ores|
225
244
  ores.each { |k, v|
226
245
  res[k] ||= []
227
- res[k].push(v)
246
+ res[k].concat(v)
228
247
  }
229
248
  }
230
249
  else
@@ -39,7 +39,7 @@ class PluginRegistry
39
39
  #
40
40
  # @return [PluginRegistry] plugin registry for this plugin
41
41
  def self.plugin_registry
42
- fail "Plugin #{self} does not implement `self.plugin_registry()`. This method is required"
42
+ raise "Plugin #{self} does not implement `self.plugin_registry()`. This method is required"
43
43
  end
44
44
 
45
45
  # Register a new plugin by name
@@ -47,7 +47,7 @@ class PluginRegistry
47
47
  # @param [String] the unique name of this plugin
48
48
  # @return [nil] disregard
49
49
  def self.name(name)
50
- fail "Trying to register #{self} with name == nil" if name.nil?
50
+ raise "Trying to register #{self} with name == nil" if name.nil?
51
51
  @name = name
52
52
  plugin_registry.registry[name] = self
53
53
  end
@@ -72,7 +72,7 @@ class PluginRegistry
72
72
  # @param [String] target to try to resolve
73
73
  # @return [Plugin] instance if it can be resolved, nil otherwise
74
74
  def self.resolve(_target)
75
- fail "Plugin #{self} does not implement `self.resolve(target)`. This method is required"
75
+ raise "Plugin #{self} does not implement `self.resolve(target)`. This method is required"
76
76
  end
77
77
 
78
78
  # When a plugin's resolve doesn't lead to the final state, it can
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
  # copyright: 2015, Dominik Richter
3
- # license: All rights reserved
4
3
  # author: Dominik Richter
5
4
  # author: Christoph Hartmann
6
5
 
@@ -33,7 +32,7 @@ class SimpleConfig
33
32
  raw_data = raw_data.tr(options[:line_separator], "\n")
34
33
  end
35
34
  rest = raw_data
36
- rest = parse_rest(rest, options) while rest.length > 0
35
+ rest = parse_rest(rest, options) until rest.empty?
37
36
  end
38
37
 
39
38
  private
@@ -55,16 +54,28 @@ class SimpleConfig
55
54
  end
56
55
 
57
56
  def parse_params_line(line, opts)
57
+ # Deprecation handling
58
+ if opts.key?(:assignment_re)
59
+ warn '[DEPRECATION] `:assignment_re` is deprecated in favor of `:assignment_regex` '\
60
+ 'and will be removed in the next major version. See: https://github.com/chef/inspec/issues/1709'
61
+ opts[:assignment_regex] = opts[:assignment_re]
62
+ end
63
+ if opts.key?(:key_vals)
64
+ warn '[DEPRECATION] `:key_vals` is deprecated in favor of `:key_values` '\
65
+ 'and will be removed in the next major version. See: https://github.com/chef/inspec/issues/1709'
66
+ opts[:key_values] = opts[:key_vals]
67
+ end
68
+
58
69
  # now line contains what we are interested in parsing
59
70
  # check if it is an assignment
60
- m = opts[:assignment_re].match(line)
71
+ m = opts[:assignment_regex].match(line)
61
72
  return nil if m.nil?
62
73
 
63
74
  if opts[:multiple_values]
64
75
  @vals[m[1]] ||= []
65
- @vals[m[1]].push(parse_values(m, opts[:key_vals]))
76
+ @vals[m[1]].push(parse_values(m, opts[:key_values]))
66
77
  else
67
- @vals[m[1]] = parse_values(m, opts[:key_vals])
78
+ @vals[m[1]] = parse_values(m, opts[:key_values])
68
79
  end
69
80
  end
70
81
 
@@ -73,7 +84,13 @@ class SimpleConfig
73
84
  m = opts[:group_re].match(line)
74
85
  return nil if m.nil?
75
86
  @groups.push(m[1])
76
- @vals = @params[m[1]] = {}
87
+
88
+ # We use a Hashie::Mash to provide method syntax for retrieving
89
+ # values. For configs that have keys whose values may be hashes
90
+ # (such as a mysql config that has [sections]), providing
91
+ # a hash whose values are accessible via methods provide
92
+ # a better user experience with `its` blocks.
93
+ @vals = @params[m[1]] = Hashie::Mash.new
77
94
  end
78
95
 
79
96
  def parse_implicit_assignment_line(line, opts)
@@ -105,9 +122,9 @@ class SimpleConfig
105
122
  multiline: false,
106
123
  comment_char: '#',
107
124
  line_separator: nil, # uses this char to seperate lines before parsing
108
- assignment_re: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
125
+ assignment_regex: /^\s*([^=]*?)\s*=\s*(.*?)\s*$/,
109
126
  group_re: /\[([^\]]+)\]\s*$/,
110
- key_vals: 1, # default for key=value, may require for 'key val1 val2 val3'
127
+ key_values: 1, # default for key=value, may require for 'key val1 val2 val3'
111
128
  standalone_comments: false,
112
129
  multiple_values: false,
113
130
  }
data/lib/utils/spdx.rb ADDED
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Richter
4
+ class Spdx
5
+ def self.licenses
6
+ spdx_file = File.join(File.dirname(__FILE__), 'spdx.txt').freeze
7
+ File.read(spdx_file).split("\n")
8
+ end
9
+
10
+ def self.valid_license?(license)
11
+ licenses.include?(license)
12
+ end
13
+ end