inspec-core 4.50.3 → 5.7.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -11
  3. data/etc/deprecations.json +12 -11
  4. data/inspec-core.gemspec +2 -2
  5. data/lib/bundles/inspec-supermarket/README.md +21 -2
  6. data/lib/bundles/inspec-supermarket/cli.rb +20 -3
  7. data/lib/bundles/inspec-supermarket/target.rb +3 -2
  8. data/lib/inspec/base_cli.rb +22 -2
  9. data/lib/inspec/cli.rb +15 -0
  10. data/lib/inspec/config.rb +5 -1
  11. data/lib/inspec/dependencies/requirement.rb +2 -1
  12. data/lib/inspec/dependency_installer.rb +74 -0
  13. data/lib/inspec/dependency_loader.rb +97 -0
  14. data/lib/inspec/dsl.rb +11 -2
  15. data/lib/inspec/errors.rb +7 -0
  16. data/lib/inspec/formatters/base.rb +31 -6
  17. data/lib/inspec/library_eval_context.rb +2 -0
  18. data/lib/inspec/metadata.rb +36 -0
  19. data/lib/inspec/plugin/v1/registry.rb +1 -1
  20. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +53 -0
  21. data/lib/inspec/profile.rb +63 -0
  22. data/lib/inspec/profile_context.rb +1 -6
  23. data/lib/inspec/reporters/automate.rb +1 -1
  24. data/lib/inspec/reporters/cli.rb +1 -1
  25. data/lib/inspec/reporters/json.rb +31 -11
  26. data/lib/inspec/resource.rb +6 -0
  27. data/lib/inspec/resources/auditd.rb +5 -4
  28. data/lib/inspec/resources/bash.rb +2 -0
  29. data/lib/inspec/resources/cron.rb +49 -0
  30. data/lib/inspec/resources/file.rb +38 -0
  31. data/lib/inspec/resources/firewalld.rb +83 -9
  32. data/lib/inspec/resources/grub_conf.rb +1 -1
  33. data/lib/inspec/resources/http.rb +31 -2
  34. data/lib/inspec/resources/ibmdb2_session.rb +2 -2
  35. data/lib/inspec/resources/ipfilter.rb +59 -0
  36. data/lib/inspec/resources/ipnat.rb +58 -0
  37. data/lib/inspec/resources/iptables.rb +18 -2
  38. data/lib/inspec/resources/kernel_parameters.rb +58 -0
  39. data/lib/inspec/resources/mssql_session.rb +11 -3
  40. data/lib/inspec/resources/oracledb_session.rb +3 -1
  41. data/lib/inspec/resources/package.rb +74 -1
  42. data/lib/inspec/resources/packages.rb +21 -0
  43. data/lib/inspec/resources/registry_key.rb +30 -0
  44. data/lib/inspec/resources/selinux.rb +6 -1
  45. data/lib/inspec/resources/service.rb +58 -9
  46. data/lib/inspec/resources/ssl.rb +7 -0
  47. data/lib/inspec/resources/timezone.rb +65 -0
  48. data/lib/inspec/resources.rb +5 -16
  49. data/lib/inspec/runner.rb +18 -1
  50. data/lib/inspec/runner_rspec.rb +45 -0
  51. data/lib/inspec/schema/exec_json.rb +59 -58
  52. data/lib/inspec/schema/exec_json_min.rb +16 -16
  53. data/lib/inspec/schema/primitives.rb +68 -51
  54. data/lib/inspec/schema/profile_json.rb +27 -27
  55. data/lib/inspec/schema.rb +1 -0
  56. data/lib/inspec/ui.rb +1 -0
  57. data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
  58. data/lib/inspec/utils/filter.rb +46 -2
  59. data/lib/inspec/utils/run_data_filters.rb +1 -1
  60. data/lib/inspec/version.rb +1 -1
  61. data/lib/inspec.rb +3 -0
  62. data/lib/plugins/inspec-compliance/lib/inspec-compliance/api.rb +1 -1
  63. data/lib/plugins/inspec-compliance/lib/inspec-compliance/cli.rb +4 -3
  64. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
  65. data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
  66. data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
  67. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
  68. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
  69. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
  70. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
  71. data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
  72. data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
  73. data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
  74. data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
  75. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
  76. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
  77. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
  78. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
  79. data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
  80. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
  81. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
  82. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
  83. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
  84. metadata +25 -5
@@ -121,6 +121,10 @@ module Inspec::Resources
121
121
  def max_redirects
122
122
  opts.fetch(:max_redirects, nil)
123
123
  end
124
+
125
+ def proxy
126
+ opts.fetch(:proxy, nil)
127
+ end
124
128
  end
125
129
 
126
130
  class Local < Base
@@ -141,12 +145,18 @@ module Inspec::Resources
141
145
  def response
142
146
  return @response if @response
143
147
 
148
+ Faraday.ignore_env_proxy = true if proxy == "disable"
149
+
144
150
  conn = Faraday.new(url: url, headers: request_headers, params: params, ssl: { verify: ssl_verify? }) do |builder|
145
151
  builder.request :url_encoded
146
152
  builder.use FaradayMiddleware::FollowRedirects, limit: max_redirects unless max_redirects.nil?
147
153
  builder.adapter Faraday.default_adapter
148
154
  end
149
155
 
156
+ unless proxy == "disable" || proxy.nil?
157
+ conn.proxy = proxy
158
+ end
159
+
150
160
  # set basic authentication
151
161
  conn.basic_auth username, password unless username.nil? || password.nil?
152
162
 
@@ -252,6 +262,14 @@ module Inspec::Resources
252
262
  cmd << "-X #{http_method}"
253
263
  end
254
264
 
265
+ cmd << "--noproxy '*'" if proxy == "disable"
266
+ unless proxy == "disable" || proxy.nil?
267
+ if proxy.is_a?(Hash)
268
+ cmd << "--proxy #{proxy[:uri]} --proxy-user #{proxy[:user]}:#{proxy[:password]}"
269
+ else
270
+ cmd << "--proxy #{proxy}"
271
+ end
272
+ end
255
273
  cmd << "--connect-timeout #{open_timeout}"
256
274
  cmd << "--max-time #{open_timeout + read_timeout}"
257
275
  cmd << "--user \'#{username}:#{password}\'" unless username.nil? || password.nil?
@@ -292,6 +310,17 @@ module Inspec::Resources
292
310
  else
293
311
  cmd << "'#{url}?#{params.map { |e| e.join("=") }.join("&")}'"
294
312
  end
313
+
314
+ proxy_script = ""
315
+ unless proxy == "disable" || proxy.nil?
316
+ cmd << "-Proxy #{proxy[:uri]}"
317
+ cmd << "-ProxyCredential $proxyCreds"
318
+ proxy_script = <<-EOH
319
+ $secPasswd = ConvertTo-SecureString "#{proxy[:password]}" -AsPlainText -Force
320
+ $proxyCreds = New-Object System.Management.Automation.PSCredential -ArgumentList "#{proxy[:user]}",$secPasswd
321
+ EOH
322
+ end
323
+
295
324
  command = cmd.join(" ")
296
325
  body = "\'#{request_body}\'"
297
326
  script = <<-EOH
@@ -302,10 +331,10 @@ module Inspec::Resources
302
331
  foreach ($property in $Body.PSObject.Properties) {
303
332
  $HashTable[$property.Name] = $property.Value
304
333
  }
305
- $response = #{command} -Body $HashTable
334
+ $response = #{command} -Body $HashTable -UseBasicParsing
306
335
  $response | Select-Object -Property * | ConvertTo-json # We use `Select-Object -Property * ` to get around an odd PowerShell error
307
336
  EOH
308
- script.strip
337
+ proxy_script.strip + "\n" + script.strip
309
338
  end
310
339
  end
311
340
  end
@@ -46,12 +46,12 @@ module Inspec::Resources
46
46
 
47
47
  # check if following specific error is there. Sourcing the db2profile to resolve the error.
48
48
  if cmd.exit_status != 0 && out =~ /SQL10007N Message "-1390" could not be retrieved. Reason code: "3"/
49
- cmd = inspec.command(". ~/sqllib/db2profile\; #{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} connect to #{@db_name}\; #{@db2_executable_file_path} #{q}\;")
49
+ cmd = inspec.command(". ~/sqllib/db2profile\; #{@db2_executable_file_path} attach to #{@db_instance}\; #{@db2_executable_file_path} connect to #{@db_name}\; #{@db2_executable_file_path} \"#{q}\"\;")
50
50
  out = cmd.stdout + "\n" + cmd.stderr
51
51
  end
52
52
  elsif inspec.os.platform?("windows")
53
53
  # set-item command set the powershell to run the db2 commands.
54
- cmd = inspec.command("set-item -path env:DB2CLP -value \"**$$**\"\; db2 connect to #{@db_name}\; db2 #{q}\;")
54
+ cmd = inspec.command("set-item -path env:DB2CLP -value \"**$$**\"\; db2 connect to #{@db_name}\; db2 \"#{q}\"\;")
55
55
  out = cmd.stdout + "\n" + cmd.stderr
56
56
  end
57
57
 
@@ -0,0 +1,59 @@
1
+ require "inspec/resources/command"
2
+ module Inspec::Resources
3
+ class IpFilter < Inspec.resource(1)
4
+ name "ipfilter"
5
+ supports platform: "bsd"
6
+ supports platform: "solaris"
7
+ desc "Use the ipfilter InSpec audit resource to test rules that are defined for ipfilter, which maintains the IP rule set"
8
+ example <<~EXAMPLE
9
+ describe ipfilter do
10
+ it { should have_rule("pass in quick on lo0 all") }
11
+ end
12
+ EXAMPLE
13
+
14
+ def initialize
15
+ # checks if the instance is either bsd or solaris
16
+ return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
17
+
18
+ # ensures, all calls are aborted for non-supported os
19
+ @ipfilter_cache = []
20
+ skip_resource "The `ipfilter` resource is not supported on your OS yet."
21
+ end
22
+
23
+ def has_rule?(rule = nil)
24
+ # checks if the rule is part of the ruleset
25
+ retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
26
+ end
27
+
28
+ def retrieve_rules
29
+ # this would be true if the OS family was not bsd/solaris when checked in initliaze
30
+ return @ipfilter_cache if defined?(@ipfilter_cache)
31
+
32
+ # construct ipfstat command to read all rules
33
+ bin = find_ipfstat_or_error
34
+ ipfstat_cmd = "#{bin} -io"
35
+ cmd = inspec.command(ipfstat_cmd)
36
+
37
+ # Return empty array when command is not executed successfully
38
+ # or there is no output since no rules are active
39
+ return [] if cmd.exit_status.to_i != 0 || cmd.stdout == ""
40
+
41
+ # split rules, returns array or rules
42
+ @ipfilter_cache = cmd.stdout.split("\n").map(&:strip)
43
+ end
44
+
45
+ def to_s
46
+ "Ipfilter"
47
+ end
48
+
49
+ private
50
+
51
+ def find_ipfstat_or_error
52
+ %w{/usr/sbin/ipfstat /sbin/ipfstat ipfstat}.each do |cmd|
53
+ return cmd if inspec.command(cmd).exist?
54
+ end
55
+
56
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `ipfstat`"
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,58 @@
1
+ require "inspec/resources/command"
2
+ module Inspec::Resources
3
+ class IpNat < Inspec.resource(1)
4
+ name "ipnat"
5
+ supports platform: "bsd"
6
+ supports platform: "solaris"
7
+ desc "Use the ipnat InSpec audit resource to test rules that are defined for IP NAT"
8
+ example <<~EXAMPLE
9
+ describe ipnat do
10
+ it { should have_rule("map net1 192.168.0.0/24 -> 0/32") }
11
+ end
12
+ EXAMPLE
13
+
14
+ def initialize
15
+ # checks if the instance is either bsd or solaris
16
+ return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
17
+
18
+ # ensures, all calls are aborted for non-supported os
19
+ @ipnat_cache = []
20
+ skip_resource "The `ipnat` resource is not supported on your OS yet."
21
+ end
22
+
23
+ def has_rule?(rule = nil)
24
+ # checks if the rule is part of the ruleset
25
+ retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
26
+ end
27
+
28
+ def retrieve_rules
29
+ # this would be true if the OS family was not bsd/solaris when checked in initliaze
30
+ return @ipnat_cache if defined?(@ipnat_cache)
31
+
32
+ # construct ipnat command to show the list of current IP NAT table entry mappings
33
+ bin = find_ipnat_or_error
34
+ ipnat_cmd = "#{bin} -l"
35
+ cmd = inspec.command(ipnat_cmd)
36
+
37
+ # Return empty array when command is not executed successfully
38
+ return [] if cmd.exit_status.to_i != 0
39
+
40
+ # split rules, returns array or rules
41
+ @ipnat_cache = cmd.stdout.split("\n").map(&:strip)
42
+ end
43
+
44
+ def to_s
45
+ "Ipnat"
46
+ end
47
+
48
+ private
49
+
50
+ def find_ipnat_or_error
51
+ %w{/usr/sbin/ipnat /sbin/ipnat ipnat}.each do |cmd|
52
+ return cmd if inspec.command(cmd).exist?
53
+ end
54
+
55
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `ipnat`"
56
+ end
57
+ end
58
+ end
@@ -33,6 +33,7 @@ module Inspec::Resources
33
33
  def initialize(params = {})
34
34
  @table = params[:table]
35
35
  @chain = params[:chain]
36
+ @ignore_comments = params[:ignore_comments] || false
36
37
 
37
38
  # we're done if we are on linux
38
39
  return if inspec.os.linux?
@@ -59,8 +60,13 @@ module Inspec::Resources
59
60
  cmd = inspec.command(iptables_cmd)
60
61
  return [] if cmd.exit_status.to_i != 0
61
62
 
62
- # split rules, returns array or rules
63
- @iptables_cache = cmd.stdout.split("\n").map(&:strip)
63
+ if @ignore_comments
64
+ # split rules, returns array or rules without any comment
65
+ @iptables_cache = remove_comments_from_rules(cmd.stdout.split("\n"))
66
+ else
67
+ # split rules, returns array or rules
68
+ @iptables_cache = cmd.stdout.split("\n").map(&:strip)
69
+ end
64
70
  end
65
71
 
66
72
  def to_s
@@ -69,6 +75,16 @@ module Inspec::Resources
69
75
 
70
76
  private
71
77
 
78
+ def remove_comments_from_rules(rules)
79
+ rules.each do |rule|
80
+ next if rule.nil?
81
+
82
+ rule.gsub!(/ -m comment --comment "([^"]*)"/, "")
83
+ rule.strip
84
+ end
85
+ rules
86
+ end
87
+
72
88
  def find_iptables_or_error
73
89
  %w{/usr/sbin/iptables /sbin/iptables iptables}.each do |cmd|
74
90
  return cmd if inspec.command(cmd).exist?
@@ -0,0 +1,58 @@
1
+ module Inspec::Resources
2
+ class KernelParameters < Inspec.resource(1)
3
+ name "kernel_parameters"
4
+ supports platform: "unix"
5
+ desc "Use the kernel_parameters InSpec audit resource to test kernel parameters on Linux platforms."
6
+ example <<~EXAMPLE
7
+ describe kernel_parameters.where(parameter: /^net./ ) do
8
+ its('parameters') { should include 'net.ipv4.conf.all.forwarding' }
9
+ end
10
+
11
+ describe kernel_parameters.where(parameter: "net.ipv4.conf.all.forwarding") do
12
+ its('values') { should eq [0] }
13
+ end
14
+
15
+ describe kernel_parameters do
16
+ its('parameters') { should include 'net.ipv4.conf.all.forwarding' }
17
+ its('values') { should include 0 }
18
+ end
19
+ EXAMPLE
20
+
21
+ filter = FilterTable.create
22
+ filter.register_custom_matcher(:exists?) { |x| !x.entries.empty? }
23
+ filter.register_column(:parameters, field: "parameter")
24
+ .register_column(:values, field: "value")
25
+ filter.install_filter_methods_on_resource(self, :params)
26
+
27
+ def initialize
28
+ # this resource is only supported on Linux
29
+ return skip_resource "The `kernel_parameters` resource is not supported on your OS." unless inspec.os.linux?
30
+ end
31
+
32
+ def to_s
33
+ "Kernel Parameters"
34
+ end
35
+
36
+ private
37
+
38
+ def params
39
+ cmd = inspec.command("/sbin/sysctl -a")
40
+ cmd.exit_status != 0 ? [] : parse_kernel_paramater(cmd.stdout)
41
+ end
42
+
43
+ def parse_kernel_paramater(stdout)
44
+ result = []
45
+ stdout.split("\n").each do |out|
46
+ splitted_output = out.split("=").map(&:strip)
47
+ result.push(
48
+ {
49
+ "parameter" => splitted_output[0],
50
+ "value" => splitted_output[1].to_i,
51
+ }
52
+ )
53
+ end
54
+ result
55
+ end
56
+
57
+ end
58
+ end
@@ -76,7 +76,7 @@ module Inspec::Resources
76
76
  if cmd.exit_status != 0 || out =~ /Sqlcmd: Error/
77
77
  raise Inspec::Exceptions::ResourceFailed, "Could not execute the sql query #{out}"
78
78
  else
79
- DatabaseHelper::SQLQueryResult.new(cmd, parse_csv_result(cmd))
79
+ DatabaseHelper::SQLQueryResult.new(cmd, parse_csv_result(cmd.stdout))
80
80
  end
81
81
  end
82
82
 
@@ -94,9 +94,17 @@ module Inspec::Resources
94
94
  !query("select getdate()").empty?
95
95
  end
96
96
 
97
- def parse_csv_result(cmd)
97
+ def parse_csv_result(stdout)
98
98
  require "csv" unless defined?(CSV)
99
- table = CSV.parse(cmd.stdout, headers: true)
99
+
100
+ # replaces \n with \r since multiline data in older versions of database returns faulty
101
+ # formatted multiline data, example name\r\n----\r\nThis is\na multiline field\r\n
102
+ out = stdout.gsub("\n", "\r")
103
+ out = out.gsub("\r\r", "\r")
104
+
105
+ # row separator used since row delimiters \n (in linux) or \r\n (in windows)
106
+ # are converted to \r for consistency and handling faulty formatted multiline data
107
+ table = CSV.parse(out, headers: true, row_sep: "\r")
100
108
 
101
109
  # remove first row, since it will be a seperator line
102
110
  table.delete(0)
@@ -118,7 +118,9 @@ module Inspec::Resources
118
118
  output = output.sub(/\r/, "").strip.gsub(",", "comma_query_sub")
119
119
  converter = ->(header) { header.downcase }
120
120
  CSV.parse(output, headers: true, header_converters: converter).map do |row|
121
- revised_row = row.entries.flatten.map { |entry| entry.gsub("comma_query_sub", ",") }
121
+ next if row.entries.flatten.empty?
122
+
123
+ revised_row = row.entries.flatten.map { |entry| entry&.gsub("comma_query_sub", ",") }
122
124
  Hashie::Mash.new([revised_row].to_h)
123
125
  end
124
126
  end
@@ -26,6 +26,7 @@ module Inspec::Resources
26
26
  @cache = nil
27
27
  # select package manager
28
28
  @pkgman = nil
29
+ @latest_version = nil
29
30
 
30
31
  os = inspec.os
31
32
  if os.debian?
@@ -60,6 +61,15 @@ module Inspec::Resources
60
61
  info[:installed] == true
61
62
  end
62
63
 
64
+ def latest?(_provider = nil, _version = nil)
65
+ os = inspec.os
66
+ if os.solaris? || (%w{hpux aix}.include? os[:family])
67
+ raise Inspec::Exceptions::ResourceSkipped, "The `be_latest` matcher is not supported on your OS yet."
68
+ end
69
+
70
+ (!info[:only_version_no].nil? && !latest_version.nil?) && (info[:only_version_no] == latest_version)
71
+ end
72
+
63
73
  # returns true it the package is held (if the OS supports it)
64
74
  def held?(_provider = nil, _version = nil)
65
75
  info[:held] == true
@@ -82,6 +92,10 @@ module Inspec::Resources
82
92
  info[:version]
83
93
  end
84
94
 
95
+ def latest_version
96
+ @latest_version ||= ( @pkgman.latest_version(@package_name) || info[:latest_version] )
97
+ end
98
+
85
99
  def to_s
86
100
  "System Package #{@package_name}"
87
101
  end
@@ -107,6 +121,21 @@ module Inspec::Resources
107
121
  # combined into a `ResourceSkipped` exception message.
108
122
  []
109
123
  end
124
+
125
+ private
126
+
127
+ def fetch_latest_version(cmd_string)
128
+ cmd = inspec.command(cmd_string)
129
+ if cmd.exit_status != 0
130
+ raise Inspec::Exceptions::ResourceFailed, "Failed to fetch latest version. Error: #{cmd.stderr}"
131
+ else
132
+ fetch_version_no(cmd.stdout)
133
+ end
134
+ end
135
+
136
+ def fetch_version_no(output)
137
+ output.scan(/(?:(?:\d+)[.]){2,}(?:\d+)/).max_by { |s| Gem::Version.new(s) } unless output.nil?
138
+ end
110
139
  end
111
140
 
112
141
  # Debian / Ubuntu
@@ -124,14 +153,21 @@ module Inspec::Resources
124
153
  # If the package is installed and marked hold, Status is "hold ok installed"
125
154
  # If the package is removed and not purged, Status is "deinstall ok config-files" with exit_status 0
126
155
  # If the package is purged cmd fails with non-zero exit status
156
+
127
157
  {
128
158
  name: params["Package"],
129
159
  installed: params["Status"].split(" ")[2] == "installed",
130
160
  held: params["Status"].split(" ")[0] == "hold",
131
161
  version: params["Version"],
132
162
  type: "deb",
163
+ only_version_no: fetch_version_no(params["Version"]),
133
164
  }
134
165
  end
166
+
167
+ def latest_version(package_name)
168
+ cmd_string = "apt list #{package_name} -a"
169
+ fetch_latest_version(cmd_string)
170
+ end
135
171
  end
136
172
 
137
173
  # RHEL family
@@ -181,9 +217,15 @@ module Inspec::Resources
181
217
  installed: true,
182
218
  version: "#{v}-#{r}",
183
219
  type: "rpm",
220
+ only_version_no: "#{v}",
184
221
  }
185
222
  end
186
223
 
224
+ def latest_version(package_name)
225
+ cmd_string = "yum list #{package_name}"
226
+ fetch_latest_version(cmd_string)
227
+ end
228
+
187
229
  private
188
230
 
189
231
  def rpm_command(package_name)
@@ -216,11 +258,17 @@ module Inspec::Resources
216
258
  installed: true,
217
259
  version: pkg["installed"][0]["version"],
218
260
  type: "brew",
261
+ latest_version: pkg["versions"]["stable"],
262
+ only_version_no: pkg["installed"][0]["version"],
219
263
  }
220
264
  rescue JSON::ParserError => e
221
265
  raise Inspec::Exceptions::ResourceFailed,
222
266
  "Failed to parse JSON from `brew` command. Error: #{e}"
223
267
  end
268
+
269
+ def latest_version(package_name)
270
+ nil
271
+ end
224
272
  end
225
273
 
226
274
  # Arch Linux
@@ -240,8 +288,14 @@ module Inspec::Resources
240
288
  installed: true,
241
289
  version: params["Version"],
242
290
  type: "pacman",
291
+ only_version_no: fetch_version_no(params["Version"]),
243
292
  }
244
293
  end
294
+
295
+ def latest_version(package_name)
296
+ cmd_string = "pacman -Ss #{package_name} | grep #{package_name} | grep installed"
297
+ fetch_latest_version(cmd_string)
298
+ end
245
299
  end
246
300
 
247
301
  class HpuxPkg < PkgManagement
@@ -267,13 +321,20 @@ module Inspec::Resources
267
321
  pkg_info = cmd.stdout.split("\n").delete_if { |e| e =~ /^WARNING/i }
268
322
  pkg = pkg_info[0].split(" - ")[0]
269
323
 
324
+ version = pkg.partition("-")[2]
270
325
  {
271
326
  name: pkg.partition("-")[0],
272
327
  installed: true,
273
- version: pkg.partition("-")[2],
328
+ version: version,
274
329
  type: "pkg",
330
+ only_version_no: fetch_version_no(version),
275
331
  }
276
332
  end
333
+
334
+ def latest_version(package_name)
335
+ cmd_string = "apk info #{package_name}"
336
+ fetch_latest_version(cmd_string)
337
+ end
277
338
  end
278
339
 
279
340
  class FreebsdPkg < PkgManagement
@@ -292,8 +353,14 @@ module Inspec::Resources
292
353
  installed: true,
293
354
  version: params["Version"],
294
355
  type: "pkg",
356
+ only_version_no: params["Version"],
295
357
  }
296
358
  end
359
+
360
+ def latest_version(package_name)
361
+ cmd_string = "pkg version -v | grep #{package_name}"
362
+ fetch_latest_version(cmd_string)
363
+ end
297
364
  end
298
365
 
299
366
  # Determines the installed packages on Windows using the Windows package registry entries.
@@ -339,8 +406,14 @@ module Inspec::Resources
339
406
  installed: true,
340
407
  version: package["DisplayVersion"],
341
408
  type: "windows",
409
+ only_version_no: package["DisplayVersion"],
342
410
  }
343
411
  end
412
+
413
+ def latest_version(package_name)
414
+ cmd_string = "Get-Package #{package_name} -AllVersions"
415
+ fetch_latest_version(cmd_string)
416
+ end
344
417
  end
345
418
 
346
419
  # AIX
@@ -26,6 +26,8 @@ module Inspec::Resources
26
26
  @pkgs = Debs.new(inspec)
27
27
  elsif os.redhat? || %w{suse amazon fedora}.include?(os[:family])
28
28
  @pkgs = Rpms.new(inspec)
29
+ elsif ["alpine"].include?(os[:name])
30
+ @pkgs = AlpinePkgs.new(inspec)
29
31
  else
30
32
  return skip_resource "The packages resource is not yet supported on OS #{inspec.os.name}"
31
33
  end
@@ -108,4 +110,23 @@ module Inspec::Resources
108
110
  end
109
111
  end
110
112
  end
113
+
114
+ # RedHat family
115
+ class AlpinePkgs < PkgsManagement
116
+ def build_package_list
117
+ command = "apk list --no-network --installed"
118
+ cmd = inspec.command(command)
119
+ all = cmd.stdout.split("\n")
120
+ return [] if all.nil? || cmd.exit_status.to_i != 0
121
+
122
+ all.map do |m|
123
+ next if m =~ /^WARNING/i
124
+
125
+ a = m.split(" ")
126
+ version = a[0].split("-")[-2]
127
+ name = a[2].gsub(/[{}^]*/, "")
128
+ PackageStruct.new("installed", name, version, a[1])
129
+ end
130
+ end
131
+ end
111
132
  end
@@ -105,6 +105,21 @@ module Inspec::Resources
105
105
  children_keys(@options[:path], filter)
106
106
  end
107
107
 
108
+ # returns hash containing users / groups and their permission
109
+ def user_permissions
110
+ return {} unless exists?
111
+
112
+ get_permissions(@options[:path])
113
+ end
114
+
115
+ # returns true if inheritance is enabled for registry key.
116
+ def inherited?
117
+ return false unless exists?
118
+
119
+ cmd = inspec.command("(Get-Acl -Path 'Registry::#{@options[:path]}').access| Where-Object {$_.IsInherited -eq $true} | measure | % { $_.Count }")
120
+ cmd.stdout.chomp == "0" ? false : true
121
+ end
122
+
108
123
  # returns nil, if not existent or value
109
124
  def method_missing(*keys)
110
125
  # allow the use of array syntax in an `its` block so that users
@@ -283,6 +298,21 @@ module Inspec::Resources
283
298
 
284
299
  key.start_with?("\\") ? key : "\\#{key}"
285
300
  end
301
+
302
+ def get_permissions(path)
303
+ script = <<~EOH
304
+ $path = '#{path}'
305
+ $Acl = Get-Acl -Path ('Registry::' + $path)
306
+ $Result = foreach ($Access in $acl.Access) {
307
+ [PSCustomObject]@{
308
+ $Access.IdentityReference = $Access.RegistryRights.ToString()
309
+ }
310
+ }
311
+ $Result | ConvertTo-Json
312
+ EOH
313
+ result = inspec.powershell(script)
314
+ JSON.load(result.stdout).inject(&:merge) unless result.stdout.empty?
315
+ end
286
316
  end
287
317
 
288
318
  class WindowsRegistryKey < RegistryKey
@@ -84,8 +84,13 @@ module Inspec::Resources
84
84
 
85
85
  def initialize(selinux_path = "/etc/selinux/config")
86
86
  @path = selinux_path
87
- cmd = inspec.command("sestatus")
87
+ if inspec.os.redhat? && inspec.os.name == "amazon"
88
+ lcmd = "/usr/sbin/sestatus"
89
+ else
90
+ lcmd = "sestatus"
91
+ end
88
92
 
93
+ cmd = inspec.command(lcmd)
89
94
  if cmd.exit_status != 0
90
95
  # `sestatus` command not found error message comes in stdout so handling both here
91
96
  out = cmd.stdout + "\n" + cmd.stderr