inspec 1.31.0 → 1.45.9

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 (194) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +2599 -1
  4. data/Gemfile +0 -1
  5. data/README.md +24 -34
  6. data/Rakefile +0 -31
  7. data/docs/dsl_inspec.md +10 -0
  8. data/docs/matchers.md +29 -0
  9. data/docs/plugin_kitchen_inspec.md +18 -24
  10. data/docs/profiles.md +101 -81
  11. data/docs/resources/aide_conf.md.erb +71 -0
  12. data/docs/resources/apache_conf.md.erb +19 -33
  13. data/docs/resources/apt.md.erb +22 -36
  14. data/docs/resources/audit_policy.md.erb +9 -24
  15. data/docs/resources/auditd.md.erb +78 -0
  16. data/docs/resources/auditd_conf.md.erb +20 -34
  17. data/docs/resources/auditd_rules.md.erb +8 -24
  18. data/docs/resources/bash.md.erb +4 -26
  19. data/docs/resources/bond.md.erb +25 -40
  20. data/docs/resources/bridge.md.erb +5 -25
  21. data/docs/resources/bsd_service.md.erb +5 -25
  22. data/docs/resources/command.md.erb +35 -50
  23. data/docs/resources/cpan.md.erb +62 -0
  24. data/docs/resources/cran.md.erb +54 -0
  25. data/docs/resources/crontab.md.erb +9 -23
  26. data/docs/resources/csv.md.erb +12 -27
  27. data/docs/resources/dh_params.md +1 -0
  28. data/docs/resources/directory.md.erb +5 -25
  29. data/docs/resources/docker.md.erb +61 -58
  30. data/docs/resources/docker_container.md.erb +23 -19
  31. data/docs/resources/docker_image.md.erb +20 -16
  32. data/docs/resources/elasticsearch.md.erb +245 -0
  33. data/docs/resources/etc_fstab.md.erb +120 -0
  34. data/docs/resources/etc_group.md.erb +29 -45
  35. data/docs/resources/etc_hosts.md.erb +68 -0
  36. data/docs/resources/etc_hosts_allow.md.erb +68 -0
  37. data/docs/resources/etc_hosts_deny.md.erb +68 -0
  38. data/docs/resources/file.md.erb +227 -216
  39. data/docs/resources/firewalld.md.erb +104 -0
  40. data/docs/resources/gem.md.erb +21 -35
  41. data/docs/resources/group.md.erb +16 -30
  42. data/docs/resources/grub_conf.md.erb +9 -24
  43. data/docs/resources/host.md.erb +32 -49
  44. data/docs/resources/http.md.erb +38 -44
  45. data/docs/resources/iis_app.md.erb +25 -35
  46. data/docs/resources/iis_site.md.erb +26 -40
  47. data/docs/resources/inetd_conf.md.erb +27 -42
  48. data/docs/resources/ini.md.erb +9 -23
  49. data/docs/resources/interface.md.erb +5 -25
  50. data/docs/resources/iptables.md.erb +15 -29
  51. data/docs/resources/json.md.erb +12 -27
  52. data/docs/resources/kernel_module.md.erb +47 -61
  53. data/docs/resources/kernel_parameter.md.erb +15 -29
  54. data/docs/resources/key_rsa.md.erb +3 -0
  55. data/docs/resources/launchd_service.md.erb +5 -25
  56. data/docs/resources/limits_conf.md.erb +15 -29
  57. data/docs/resources/login_def.md.erb +15 -30
  58. data/docs/resources/mount.md.erb +18 -33
  59. data/docs/resources/mssql_session.md.erb +9 -12
  60. data/docs/resources/mysql_conf.md.erb +28 -32
  61. data/docs/resources/mysql_session.md.erb +15 -29
  62. data/docs/resources/nginx.md.erb +78 -0
  63. data/docs/resources/nginx_conf.md.erb +127 -0
  64. data/docs/resources/npm.md.erb +19 -35
  65. data/docs/resources/ntp_conf.md.erb +20 -37
  66. data/docs/resources/oneget.md.erb +15 -30
  67. data/docs/resources/oracledb_session.md.erb +9 -11
  68. data/docs/resources/os.md.erb +29 -43
  69. data/docs/resources/os_env.md.erb +23 -44
  70. data/docs/resources/package.md.erb +34 -36
  71. data/docs/resources/parse_config.md.erb +5 -25
  72. data/docs/resources/parse_config_file.md.erb +31 -43
  73. data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +24 -39
  74. data/docs/resources/pip.md.erb +20 -35
  75. data/docs/resources/port.md.erb +43 -57
  76. data/docs/resources/postgres_conf.md.erb +17 -31
  77. data/docs/resources/postgres_hba_conf.md.erb +26 -38
  78. data/docs/resources/postgres_ident_conf.md.erb +25 -37
  79. data/docs/resources/postgres_session.md.erb +15 -29
  80. data/docs/resources/powershell.md.erb +27 -42
  81. data/docs/resources/processes.md.erb +17 -33
  82. data/docs/resources/rabbitmq_config.md.erb +9 -24
  83. data/docs/resources/registry_key.md.erb +27 -42
  84. data/docs/resources/runit_service.md.erb +5 -25
  85. data/docs/resources/security_policy.md.erb +12 -27
  86. data/docs/resources/service.md.erb +27 -42
  87. data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +41 -47
  88. data/docs/resources/ssh_config.md.erb +19 -34
  89. data/docs/resources/sshd_config.md.erb +19 -34
  90. data/docs/resources/ssl.md.erb +39 -54
  91. data/docs/resources/sys_info.md.erb +12 -26
  92. data/docs/resources/systemd_service.md.erb +5 -25
  93. data/docs/resources/sysv_service.md.erb +5 -25
  94. data/docs/resources/upstart_service.md.erb +5 -25
  95. data/docs/resources/user.md.erb +29 -44
  96. data/docs/resources/users.md.erb +12 -26
  97. data/docs/resources/vbscript.md.erb +9 -24
  98. data/docs/resources/virtualization.md.erb +8 -23
  99. data/docs/resources/windows_feature.md.erb +15 -30
  100. data/docs/resources/windows_hotfix.md.erb +50 -0
  101. data/docs/resources/windows_task.md.erb +12 -26
  102. data/docs/resources/wmi.md.erb +9 -24
  103. data/docs/resources/x509_certificate.md.erb +4 -0
  104. data/docs/resources/xinetd_conf.md.erb +65 -80
  105. data/docs/resources/xml.md.erb +61 -0
  106. data/docs/resources/yaml.md.erb +12 -27
  107. data/docs/resources/yum.md.erb +37 -51
  108. data/docs/resources/zfs_dataset.md.erb +15 -26
  109. data/docs/resources/zfs_pool.md.erb +9 -20
  110. data/docs/ruby_usage.md +0 -1
  111. data/examples/meta-profile/README.md +1 -1
  112. data/examples/profile-sensitive/README.md +29 -0
  113. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
  114. data/examples/profile-sensitive/controls/sensitive.rb +9 -0
  115. data/examples/profile-sensitive/inspec.yml +8 -0
  116. data/inspec.gemspec +3 -3
  117. data/lib/bundles/inspec-artifact/cli.rb +5 -5
  118. data/lib/bundles/inspec-compliance/README.md +24 -22
  119. data/lib/bundles/inspec-compliance/api/login.rb +152 -0
  120. data/lib/bundles/inspec-compliance/api.rb +46 -16
  121. data/lib/bundles/inspec-compliance/cli.rb +58 -165
  122. data/lib/bundles/inspec-compliance/target.rb +2 -3
  123. data/lib/bundles/inspec-habitat/cli.rb +7 -2
  124. data/lib/bundles/inspec-habitat/profile.rb +44 -20
  125. data/lib/bundles/inspec-init/templates/profile/README.md +1 -1
  126. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +1 -1
  127. data/lib/bundles/inspec-supermarket/api.rb +1 -1
  128. data/lib/inspec/backend.rb +8 -0
  129. data/lib/inspec/cli.rb +1 -1
  130. data/lib/inspec/control_eval_context.rb +16 -6
  131. data/lib/inspec/dependencies/requirement.rb +22 -8
  132. data/lib/inspec/dependencies/resolver.rb +1 -1
  133. data/lib/inspec/exceptions.rb +4 -0
  134. data/lib/inspec/file_provider.rb +38 -9
  135. data/lib/inspec/metadata.rb +17 -3
  136. data/lib/inspec/objects/attribute.rb +16 -7
  137. data/lib/inspec/objects/control.rb +10 -2
  138. data/lib/inspec/plugins/resource.rb +34 -5
  139. data/lib/inspec/profile.rb +10 -1
  140. data/lib/inspec/profile_context.rb +3 -1
  141. data/lib/inspec/resource.rb +17 -5
  142. data/lib/inspec/rspec_json_formatter.rb +48 -14
  143. data/lib/inspec/rule.rb +4 -0
  144. data/lib/inspec/runner.rb +72 -30
  145. data/lib/inspec/shell.rb +24 -19
  146. data/lib/inspec/version.rb +1 -1
  147. data/lib/matchers/matchers.rb +40 -0
  148. data/lib/resources/aide_conf.rb +162 -0
  149. data/lib/resources/auditd.rb +231 -0
  150. data/lib/resources/auditd_rules.rb +3 -1
  151. data/lib/resources/command.rb +1 -1
  152. data/lib/resources/cpan.rb +60 -0
  153. data/lib/resources/cran.rb +66 -0
  154. data/lib/resources/docker.rb +8 -1
  155. data/lib/resources/docker_container.rb +19 -2
  156. data/lib/resources/elasticsearch.rb +172 -0
  157. data/lib/resources/etc_fstab.rb +102 -0
  158. data/lib/resources/etc_group.rb +1 -1
  159. data/lib/resources/etc_hosts.rb +81 -0
  160. data/lib/resources/etc_hosts_allow_deny.rb +122 -0
  161. data/lib/resources/file.rb +87 -10
  162. data/lib/resources/firewalld.rb +144 -0
  163. data/lib/resources/groups.rb +0 -1
  164. data/lib/resources/host.rb +30 -15
  165. data/lib/resources/http.rb +178 -22
  166. data/lib/resources/mssql_session.rb +3 -3
  167. data/lib/resources/mysql_conf.rb +10 -0
  168. data/lib/resources/mysql_session.rb +1 -1
  169. data/lib/resources/nginx.rb +97 -0
  170. data/lib/resources/nginx_conf.rb +134 -1
  171. data/lib/resources/oracledb_session.rb +9 -8
  172. data/lib/resources/os_env.rb +7 -4
  173. data/lib/resources/package.rb +14 -2
  174. data/lib/resources/packages.rb +1 -1
  175. data/lib/resources/pip.rb +28 -20
  176. data/lib/resources/port.rb +251 -3
  177. data/lib/resources/postgres.rb +1 -1
  178. data/lib/resources/postgres_session.rb +1 -1
  179. data/lib/resources/processes.rb +106 -20
  180. data/lib/resources/registry_key.rb +11 -2
  181. data/lib/resources/service.rb +5 -24
  182. data/lib/resources/ssh_conf.rb +1 -1
  183. data/lib/resources/ssl.rb +4 -3
  184. data/lib/resources/toml.rb +2 -2
  185. data/lib/resources/windows_hotfix.rb +35 -0
  186. data/lib/resources/xinetd.rb +4 -6
  187. data/lib/resources/xml.rb +27 -0
  188. data/lib/source_readers/inspec.rb +3 -3
  189. data/lib/utils/find_files.rb +2 -1
  190. data/lib/utils/nginx_parser.rb +10 -1
  191. data/lib/utils/object_traversal.rb +35 -10
  192. data/lib/utils/parser.rb +21 -3
  193. metadata +48 -18
  194. data/docs/cli.md +0 -392
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+ # author: Aaron Lippold, lippold@gmail.com
3
+ # author: Rony Xavier, rx294@gmail.com
4
+
5
+ require 'pathname'
6
+ require 'hashie/mash'
7
+
8
+ module Inspec::Resources
9
+ class Nginx < Inspec.resource(1)
10
+ name 'nginx'
11
+ desc 'Use the nginx InSpec audit resource to test information about your NGINX instance.'
12
+ example "
13
+ describe nginx do
14
+ its('conf_path') { should cmp '/etc/nginx/nginx.conf' }
15
+ end
16
+ describe nginx('/etc/sbin/') do
17
+ its('version') { should be >= '1.0.0' }
18
+ end
19
+ describe nginx do
20
+ its('modules') { should include 'my_module' }
21
+ end
22
+ "
23
+ attr_reader :params, :bin_dir
24
+
25
+ def initialize(nginx_path = '/usr/sbin/nginx')
26
+ return skip_resource 'The `nginx` resource is not yet available on your OS.' if inspec.os.windows?
27
+ return skip_resource 'The `nginx` binary not found in the path provided.' unless inspec.command(nginx_path).exist?
28
+
29
+ cmd = inspec.command("#{nginx_path} -V 2>&1")
30
+ if !cmd.exit_status.zero?
31
+ return skip_resource 'Error using the command nginx -V'
32
+ end
33
+ @data = cmd.stdout
34
+ @params = {}
35
+ read_content
36
+ end
37
+
38
+ %w{compiler_info error_log_path http_client_body_temp_path http_fastcgi_temp_path http_log_path http_proxy_temp_path http_scgi_temp_path http_uwsgi_temp_path lock_path modules_path openssl_version prefix sbin_path service support_info version}.each do |property|
39
+ define_method(property.to_sym) do
40
+ @params[property.to_sym]
41
+ end
42
+ end
43
+
44
+ def openssl_version
45
+ result = @data.scan(/built with OpenSSL\s(\S+)\s(\d+\s\S+\s\d{4})/).flatten
46
+ Hashie::Mash.new({ 'version' => result[0], 'date' => result[1] })
47
+ end
48
+
49
+ def compiler_info
50
+ result = @data.scan(/built by (\S+)\s(\S+)\s(\S+)/).flatten
51
+ Hashie::Mash.new({ 'compiler' => result[0], 'version' => result[1], 'date' => result[2] })
52
+ end
53
+
54
+ def support_info
55
+ support_info = @data.scan(/(.*\S+) support enabled/).flatten
56
+ support_info.empty? ? nil : support_info.join(' ')
57
+ end
58
+
59
+ def modules
60
+ @data.scan(/--with-(\S+)_module/).flatten
61
+ end
62
+
63
+ def to_s
64
+ 'Nginx Environment'
65
+ end
66
+
67
+ private
68
+
69
+ def read_content
70
+ parse_config
71
+ parse_path
72
+ parse_http_path
73
+ end
74
+
75
+ def parse_config
76
+ @params[:prefix] = @data.scan(/--prefix=(\S+)\s/).flatten.first
77
+ @params[:service] = 'nginx'
78
+ @params[:version] = @data.scan(%r{nginx version: nginx\/(\S+)\s}).flatten.first
79
+ end
80
+
81
+ def parse_path
82
+ @params[:sbin_path] = @data.scan(/--sbin-path=(\S+)\s/).flatten.first
83
+ @params[:modules_path] = @data.scan(/--modules-path=(\S+)\s/).flatten.first
84
+ @params[:error_log_path] = @data.scan(/--error-log-path=(\S+)\s/).flatten.first
85
+ @params[:http_log_path] = @data.scan(/--http-log-path=(\S+)\s/).flatten.first
86
+ @params[:lock_path] = @data.scan(/--lock-path=(\S+)\s/).flatten.first
87
+ end
88
+
89
+ def parse_http_path
90
+ @params[:http_client_body_temp_path] = @data.scan(/--http-client-body-temp-path=(\S+)\s/).flatten.first
91
+ @params[:http_proxy_temp_path] = @data.scan(/--http-proxy-temp-path=(\S+)\s/).flatten.first
92
+ @params[:http_fastcgi_temp_path] = @data.scan(/--http-fastcgi-temp-path=(\S+)\s/).flatten.first
93
+ @params[:http_uwsgi_temp_path] = @data.scan(/--http-uwsgi-temp-path=(\S+)\s/).flatten.first
94
+ @params[:http_scgi_temp_path] = @data.scan(/--http-scgi-temp-path=(\S+)\s/).flatten.first
95
+ end
96
+ end
97
+ end
@@ -3,6 +3,8 @@
3
3
  # author: Christoph Hartmann
4
4
 
5
5
  require 'utils/nginx_parser'
6
+ require 'utils/find_files'
7
+ require 'forwardable'
6
8
 
7
9
  # STABILITY: Experimental
8
10
  # This resouce needs a proper interace to the underlying data, which is currently missing.
@@ -22,6 +24,10 @@ module Inspec::Resources
22
24
  describe nginx_conf('/path/to/my/nginx.conf').params ...
23
25
  "
24
26
 
27
+ extend Forwardable
28
+
29
+ include FindFiles
30
+
25
31
  attr_reader :contents
26
32
 
27
33
  def initialize(conf_path = nil)
@@ -37,6 +43,12 @@ module Inspec::Resources
37
43
  @params = {}
38
44
  end
39
45
 
46
+ def http
47
+ NginxConfHttp.new(params['http'], self)
48
+ end
49
+
50
+ def_delegators :http, :servers, :locations
51
+
40
52
  def to_s
41
53
  "nginx_conf #{@conf_path}"
42
54
  end
@@ -84,12 +96,133 @@ module Inspec::Resources
84
96
  if data.key?('include')
85
97
  data.delete('include').flatten
86
98
  .map { |x| File.expand_path(x, rel_path) }
99
+ .map { |x| find_files(x) }.flatten
87
100
  .map { |path| parse_nginx(path) }
88
- .map { |e| data.merge!(e) }
101
+ .each { |conf| merge_config!(data, conf) }
89
102
  end
90
103
 
91
104
  # Walk through the remaining hash fields to find more references
92
105
  Hash[data.map { |k, v| [k, resolve_references(v, rel_path)] }]
93
106
  end
107
+
108
+ # Deep merge fields from NginxConfig.parse.
109
+ # A regular merge would overwrite values so a deep merge is needed.
110
+ # @param data [Hash] data structure from NginxConfig.parse
111
+ # @param conf [Hash] data structure to be deep merged into data
112
+ # @return [Hash] data structure with conf and data deep merged
113
+ def merge_config!(data, conf)
114
+ # Catch edge-cases
115
+ return if data.nil? || conf.nil?
116
+ # Step through all conf items and create combined return value
117
+ data.merge!(conf) do |_, v1, v2|
118
+ if v1.is_a?(Array) && v2.is_a?(Array)
119
+ # If both the data field and the conf field are arrays, then combine them
120
+ v1 + v2
121
+ elsif v1.is_a?(Hash) && v2.is_a?(Hash)
122
+ # If both the data field and the conf field are maps, then deep merge them
123
+ merge_config!(v1, v2)
124
+ else
125
+ # All other cases, just use the new value (regular merge behavior)
126
+ v2
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ class NginxConfHttp
133
+ attr_reader :entries
134
+ def initialize(params, parent)
135
+ @parent = parent
136
+ @entries = (params || []).map { |x| NginxConfHttpEntry.new(x, parent) }
137
+ end
138
+
139
+ def servers
140
+ @entries.map(&:servers).flatten
141
+ end
142
+
143
+ def locations
144
+ servers.map(&:locations).flatten
145
+ end
146
+
147
+ def to_s
148
+ @parent.to_s + ', http entries'
149
+ end
150
+ alias inspect to_s
151
+ end
152
+
153
+ class NginxConfHttpEntry
154
+ attr_reader :params, :parent
155
+ def initialize(params, parent)
156
+ @params = params || {}
157
+ @parent = parent
158
+ end
159
+
160
+ filter = FilterTable.create
161
+ filter.add_accessor(:where)
162
+ .add(:servers, field: 'server')
163
+ .connect(self, :server_table)
164
+
165
+ def locations
166
+ servers.map(&:locations).flatten
167
+ end
168
+
169
+ def to_s
170
+ @parent.to_s + ', http entry'
171
+ end
172
+ alias inspect to_s
173
+
174
+ private
175
+
176
+ def server_table
177
+ @server_table ||= (params['server'] || []).map { |x| { 'server' => NginxConfServer.new(x, self) } }
178
+ end
179
+ end
180
+
181
+ class NginxConfServer
182
+ attr_reader :params, :parent
183
+ def initialize(params, parent)
184
+ @parent = parent
185
+ @params = params || {}
186
+ end
187
+
188
+ filter = FilterTable.create
189
+ filter.add_accessor(:where)
190
+ .add(:locations, field: 'location')
191
+ .connect(self, :location_table)
192
+
193
+ def to_s
194
+ server = ''
195
+ name = Array(params['server_name']).flatten.first
196
+ unless name.nil?
197
+ server += name
198
+ listen = Array(params['listen']).flatten.first
199
+ server += ":#{listen}" unless listen.nil?
200
+ end
201
+
202
+ # go two levels up: 1. to the http entry and 2. to the root nginx conf
203
+ @parent.parent.to_s + ", server #{server}"
204
+ end
205
+ alias inspect to_s
206
+
207
+ private
208
+
209
+ def location_table
210
+ @location_table ||= (params['location'] || []).map { |x| { 'location' => NginxConfLocation.new(x, self) } }
211
+ end
212
+ end
213
+
214
+ class NginxConfLocation
215
+ attr_reader :params, :parent
216
+ def initialize(params, parent)
217
+ @parent = parent
218
+ @params = params || {}
219
+ end
220
+
221
+ def to_s
222
+ location = Array(params['_']).join(' ')
223
+ # go three levels up: 1. to the server entry, 2. http entry and 3. to the root nginx conf
224
+ @parent.parent.parent.to_s + ", location #{location.inspect}"
225
+ end
226
+ alias inspect to_s
94
227
  end
95
228
  end
@@ -49,19 +49,20 @@ module Inspec::Resources
49
49
  escaped_query = escaped_query.gsub('$', '\\$')
50
50
 
51
51
  p = nil
52
- # check if sqlplus is available and prefer that
53
- if inspec.command(@sqlplus_bin).exist?
54
- bin = @sqlplus_bin
55
- opts = "SET MARKUP HTML ON\nSET FEEDBACK OFF"
56
- p = :parse_html_result
57
- elsif inspec.command(@sqlcl_bin).exist?
52
+ # use sqlplus if sqlcl is not available
53
+ if inspec.command(@sqlcl_bin).exist?
58
54
  bin = @sqlcl_bin
59
55
  opts = "set sqlformat csv\nSET FEEDBACK OFF"
60
56
  p = :parse_csv_result
57
+ else
58
+ bin = @sqlplus_bin
59
+ opts = "SET MARKUP HTML ON\nSET FEEDBACK OFF"
60
+ p = :parse_html_result
61
61
  end
62
62
 
63
- return skip_resource("Can't find suitable Oracle CLI") if p.nil?
64
- command = "echo \"#{opts}\n#{verify_query(escaped_query)}\nEXIT\" | #{bin} -s #{@user}/#{@password}@//#{@host}:#{@port}/#{@service}"
63
+ query = verify_query(escaped_query)
64
+ query += ';' unless query.end_with?(';')
65
+ command = %{echo "#{opts}\n#{query}\nEXIT" | #{bin} "#{@user}"/"#{@password}"@#{@host}:#{@port}/#{@service}}
65
66
  cmd = inspec.command(command)
66
67
 
67
68
  out = cmd.stdout + "\n" + cmd.stderr
@@ -25,8 +25,6 @@ module Inspec::Resources
25
25
  attr_reader :content
26
26
  def initialize(env = nil)
27
27
  @osenv = env
28
- @content = nil
29
- @content = value_for(env) unless env.nil?
30
28
  end
31
29
 
32
30
  def split
@@ -35,7 +33,12 @@ module Inspec::Resources
35
33
  path_separator = inspec.os.windows? ? ';' : ':'
36
34
  # -1 is required to catch cases like dir1::dir2:
37
35
  # where we have a trailing :
38
- @content.nil? ? [] : @content.split(path_separator, -1)
36
+ content.nil? ? [] : content.split(path_separator, -1)
37
+ end
38
+
39
+ def content
40
+ return @content if defined?(@content)
41
+ @content = value_for(@osenv) unless @osenv.nil?
39
42
  end
40
43
 
41
44
  def to_s
@@ -58,7 +61,7 @@ module Inspec::Resources
58
61
  out = inspec.command(command)
59
62
 
60
63
  unless out.exit_status == 0
61
- skip_resource "Can't read environment variables on #{os[:name]}. "\
64
+ skip_resource "Can't read environment variables on #{inspec.os.name}. "\
62
65
  "Tried `#{command}` which returned #{out.exit_status}"
63
66
  end
64
67
 
@@ -15,6 +15,7 @@ module Inspec::Resources
15
15
  example "
16
16
  describe package('nginx') do
17
17
  it { should be_installed }
18
+ it { should_not be_held } # for dpkg platforms that support holding a version from being upgraded
18
19
  its('version') { should eq 1.9.5 }
19
20
  end
20
21
  "
@@ -56,6 +57,13 @@ module Inspec::Resources
56
57
  info[:installed] == true
57
58
  end
58
59
 
60
+ # returns true it the package is held (if the OS supports it)
61
+ def held?(_provider = nil, _version = nil)
62
+ return false if info.nil?
63
+ return false unless info.key?(:held)
64
+ info[:held] == true
65
+ end
66
+
59
67
  # returns the package description
60
68
  def info
61
69
  return @cache if !@cache.nil?
@@ -107,11 +115,14 @@ module Inspec::Resources
107
115
  assignment_regex: /^\s*([^:]*?)\s*:\s*(.*?)\s*$/,
108
116
  multiple_values: false,
109
117
  ).params
118
+ # If the package is installed, Status is "install ok installed"
119
+ # If the package is installed and marked hold, Status is "hold ok installed"
110
120
  # If the package is removed and not purged, Status is "deinstall ok config-files" with exit_status 0
111
121
  # If the package is purged cmd fails with non-zero exit status
112
122
  {
113
123
  name: params['Package'],
114
- installed: params['Status'].split(' ').first == 'install',
124
+ installed: params['Status'].split(' ')[2] == 'installed',
125
+ held: params['Status'].split(' ')[0] == 'hold',
115
126
  version: params['Version'],
116
127
  type: 'deb',
117
128
  }
@@ -182,7 +193,8 @@ module Inspec::Resources
182
193
  # MacOS / Darwin implementation
183
194
  class Brew < PkgManagement
184
195
  def info(package_name)
185
- cmd = inspec.command("brew info --json=v1 #{package_name}")
196
+ brew_path = inspec.command('brew').exist? ? 'brew' : '/usr/local/bin/brew'
197
+ cmd = inspec.command("#{brew_path} info --json=v1 #{package_name}")
186
198
  return nil if cmd.exit_status.to_i != 0
187
199
  # parse data
188
200
  pkg = JSON.parse(cmd.stdout)[0]
@@ -63,7 +63,7 @@ module Inspec::Resources
63
63
  end
64
64
 
65
65
  def filtered_packages
66
- warn "The packages resource is not yet supported on OS #{inspec.os.name}" if resource_skipped
66
+ warn "The packages resource is not yet supported on OS #{inspec.os.name}" if resource_skipped?
67
67
  @list
68
68
  end
69
69
  end
data/lib/resources/pip.rb CHANGED
@@ -7,6 +7,7 @@
7
7
  # it { should be_installed }
8
8
  # end
9
9
  #
10
+
10
11
  module Inspec::Resources
11
12
  class PipPackage < Inspec.resource(1)
12
13
  name 'pip'
@@ -15,10 +16,17 @@ module Inspec::Resources
15
16
  describe pip('Jinja2') do
16
17
  it { should be_installed }
17
18
  end
19
+
20
+ describe pip('django', '/path/to/virtualenv/bin/pip') do
21
+ it { should be_installed }
22
+ its('version') { should eq('1.11.4')}
23
+ end
18
24
  "
19
25
 
20
- def initialize(package_name)
26
+ def initialize(package_name, pip_path = nil)
21
27
  @package_name = package_name
28
+ @pip_cmd = pip_path || default_pip_path
29
+ return skip_resource 'pip not found' unless inspec.command(@pip_cmd).exist?
22
30
  end
23
31
 
24
32
  def info
@@ -26,7 +34,7 @@ module Inspec::Resources
26
34
 
27
35
  @info = {}
28
36
  @info[:type] = 'pip'
29
- cmd = inspec.command("#{pip_cmd} show #{@package_name}")
37
+ cmd = inspec.command("#{@pip_cmd} show #{@package_name}")
30
38
  return @info if cmd.exit_status != 0
31
39
 
32
40
  params = SimpleConfig.new(
@@ -54,28 +62,28 @@ module Inspec::Resources
54
62
 
55
63
  private
56
64
 
57
- def pip_cmd
65
+ def default_pip_path
66
+ return 'pip' unless inspec.os.windows?
67
+
58
68
  # Pip is not on the default path for Windows, therefore we do some logic
59
69
  # to find the binary on Windows
60
- if inspec.os.windows?
61
- # we need to detect the pip command on Windows
62
- cmd = inspec.command('New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Pip -Value (Invoke-Command -ScriptBlock {where.exe pip}) -PassThru | Add-Member -MemberType NoteProperty -Name Python -Value (Invoke-Command -ScriptBlock {where.exe python}) -PassThru | ConvertTo-Json')
63
- begin
64
- paths = JSON.parse(cmd.stdout)
65
- # use pip if it on system path
66
- pipcmd = paths['Pip']
67
- # calculate path on windows
68
- if defined?(paths['Python']) && pipcmd.nil?
69
- pipdir = paths['Python'].split('\\')
70
- # remove python.exe
71
- pipdir.pop
72
- pipcmd = pipdir.push('Scripts').push('pip.exe').join('/')
73
- end
74
- rescue JSON::ParserError => _e
75
- return nil
70
+ cmd = inspec.command('New-Object -Type PSObject | Add-Member -MemberType NoteProperty -Name Pip -Value (Invoke-Command -ScriptBlock {where.exe pip}) -PassThru | Add-Member -MemberType NoteProperty -Name Python -Value (Invoke-Command -ScriptBlock {where.exe python}) -PassThru | ConvertTo-Json')
71
+ begin
72
+ paths = JSON.parse(cmd.stdout)
73
+ # use pip if it on system path
74
+ pipcmd = paths['Pip']
75
+ # calculate path on windows
76
+ if defined?(paths['Python']) && pipcmd.nil?
77
+ pipdir = paths['Python'].split('\\')
78
+ # remove python.exe
79
+ pipdir.pop
80
+ pipcmd = pipdir.push('Scripts').push('pip.exe').join('/')
76
81
  end
82
+ rescue JSON::ParserError => _e
83
+ return nil
77
84
  end
78
- pipcmd || 'pip'
85
+
86
+ pipcmd
79
87
  end
80
88
  end
81
89
  end