inspec-core 5.18.14 → 5.22.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +19 -17
  3. data/inspec-core.gemspec +22 -22
  4. data/lib/inspec/base_cli.rb +19 -17
  5. data/lib/inspec/cli.rb +27 -25
  6. data/lib/inspec/dependencies/dependency_set.rb +2 -2
  7. data/lib/inspec/dsl.rb +9 -5
  8. data/lib/inspec/enhanced_outcomes.rb +19 -0
  9. data/lib/inspec/env_printer.rb +1 -1
  10. data/lib/inspec/exceptions.rb +2 -0
  11. data/lib/inspec/formatters/base.rb +69 -16
  12. data/lib/inspec/plugin/v2/loader.rb +19 -8
  13. data/lib/inspec/plugin/v2/plugin_types/reporter.rb +1 -0
  14. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +54 -0
  15. data/lib/inspec/profile.rb +9 -8
  16. data/lib/inspec/reporters/base.rb +1 -0
  17. data/lib/inspec/reporters/cli.rb +94 -3
  18. data/lib/inspec/reporters/json.rb +3 -1
  19. data/lib/inspec/reporters/yaml.rb +3 -1
  20. data/lib/inspec/reporters.rb +2 -1
  21. data/lib/inspec/resources/file.rb +1 -1
  22. data/lib/inspec/resources/http.rb +5 -5
  23. data/lib/inspec/resources/lxc.rb +65 -9
  24. data/lib/inspec/resources/mongodb_session.rb +5 -0
  25. data/lib/inspec/resources/nftables.rb +251 -0
  26. data/lib/inspec/resources/oracledb_session.rb +13 -4
  27. data/lib/inspec/resources/podman.rb +353 -0
  28. data/lib/inspec/resources/podman_container.rb +84 -0
  29. data/lib/inspec/resources/podman_image.rb +108 -0
  30. data/lib/inspec/resources/podman_network.rb +81 -0
  31. data/lib/inspec/resources/podman_pod.rb +101 -0
  32. data/lib/inspec/resources/podman_volume.rb +87 -0
  33. data/lib/inspec/resources/postgres_session.rb +2 -1
  34. data/lib/inspec/resources/service.rb +1 -1
  35. data/lib/inspec/resources.rb +1 -0
  36. data/lib/inspec/rule.rb +54 -17
  37. data/lib/inspec/run_data/control.rb +6 -0
  38. data/lib/inspec/run_data/statistics.rb +8 -2
  39. data/lib/inspec/runner.rb +18 -8
  40. data/lib/inspec/runner_rspec.rb +3 -2
  41. data/lib/inspec/schema/exec_json.rb +78 -2
  42. data/lib/inspec/schema/output_schema.rb +4 -1
  43. data/lib/inspec/schema/profile_json.rb +46 -0
  44. data/lib/inspec/schema.rb +91 -0
  45. data/lib/inspec/utils/convert.rb +8 -0
  46. data/lib/inspec/utils/podman.rb +24 -0
  47. data/lib/inspec/utils/simpleconfig.rb +10 -2
  48. data/lib/inspec/utils/waivers/csv_file_reader.rb +34 -0
  49. data/lib/inspec/utils/waivers/excel_file_reader.rb +39 -0
  50. data/lib/inspec/utils/waivers/json_file_reader.rb +15 -0
  51. data/lib/inspec/version.rb +1 -1
  52. data/lib/inspec/waiver_file_reader.rb +61 -0
  53. data/lib/matchers/matchers.rb +15 -2
  54. data/lib/plugins/inspec-init/templates/profiles/alicloud/README.md +27 -0
  55. data/lib/plugins/inspec-init/templates/profiles/alicloud/controls/example.rb +10 -0
  56. data/lib/plugins/inspec-init/templates/profiles/alicloud/inputs.yml +1 -0
  57. data/lib/plugins/inspec-init/templates/profiles/alicloud/inspec.yml +14 -0
  58. data/lib/plugins/inspec-reporter-html2/README.md +1 -1
  59. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +7 -1
  60. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +10 -6
  61. data/lib/plugins/inspec-reporter-html2/templates/default.css +12 -0
  62. data/lib/plugins/inspec-reporter-html2/templates/selector.html.erb +7 -1
  63. data/lib/plugins/inspec-sign/lib/inspec-sign/base.rb +5 -2
  64. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +39 -13
  65. metadata +26 -9
@@ -178,7 +178,19 @@ module Inspec::Plugin::V2
178
178
  # TODO: enforce first-level version pinning
179
179
  plugin_deps = [Gem::Dependency.new(plugin_gem_name.to_s, version_constraint)]
180
180
  managed_gem_set = Gem::Resolver::VendorSet.new
181
- list_managed_gems.each { |spec| managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir) }
181
+
182
+ list_managed_gems.each do |spec|
183
+ if Gem::Specification.load spec.gem_dir
184
+ managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
185
+ else
186
+ # In case of invalid gemspec as mentioned in this PR https://github.com/brianmario/yajl-ruby/pull/223
187
+ # the add_vendor_gem breaks. So this is patch to fix the loading issue.
188
+ # Horribly, chdir to gemspec path to honor . in gemspec
189
+ Dir.chdir(spec.gem_dir) do |dir|
190
+ managed_gem_set.add_vendor_gem(spec.name, spec.gem_dir)
191
+ end
192
+ end
193
+ end
182
194
 
183
195
  # TODO: Next two lines merge our managed gems with the other gems available
184
196
  # in our "local universe" - which may be the system, or it could be in a Bundler microcosm,
@@ -278,7 +290,12 @@ module Inspec::Plugin::V2
278
290
  when :user_gem
279
291
  status.entry_point = status.name.to_s
280
292
  status.version = plugin_entry[:version]
281
- status.description = fetch_plugin_specs(status.name.to_s)&.summary
293
+ # Fetch the summary of the gem from local gemspec file instead of remote call using Gem::SpecFetcher.fetcher.
294
+ unless plugin_entry[:version].nil? # safe check very rare case.
295
+ version_string = plugin_entry[:version].gsub(/[=,~,>,<]/, "").strip
296
+ plugin_name_with_version = "#{status.name}-#{version_string}"
297
+ status.description = fetch_gemspec(File.join(plugin_gem_path, "gems", plugin_name_with_version, "/", status.name.to_s + ".gemspec"))&.summary
298
+ end
282
299
  when :path
283
300
  status.entry_point = plugin_entry[:installation_path]
284
301
  end
@@ -287,12 +304,6 @@ module Inspec::Plugin::V2
287
304
  end
288
305
  end
289
306
 
290
- def fetch_plugin_specs(plugin_name)
291
- fetcher = Gem::SpecFetcher.fetcher
292
- plugin_dependency = Gem::Dependency.new(plugin_name)
293
- fetcher.spec_for_dependency(plugin_dependency).flatten.first
294
- end
295
-
296
307
  def fixup_train_plugin_status(status)
297
308
  status.api_generation = :'train-1'
298
309
  if status.installation_type == :user_gem
@@ -7,6 +7,7 @@ module Inspec::Plugin::V2::PluginType
7
7
  include Inspec::Utils::RunDataFilters
8
8
 
9
9
  attr_reader :run_data
10
+ attr_accessor :enhanced_outcomes
10
11
 
11
12
  def initialize(config)
12
13
  @config = config
@@ -11,6 +11,7 @@ module Inspec::Plugin::V2::PluginType
11
11
  @running_controls_list = []
12
12
  @control_checks_count_map = {}
13
13
  @controls_count = nil
14
+ @notifications = {}
14
15
  end
15
16
 
16
17
  private
@@ -49,5 +50,58 @@ module Inspec::Plugin::V2::PluginType
49
50
  @control_checks_count_map = RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.get_control_checks_count_map
50
51
  end
51
52
  end
53
+
54
+ def enhanced_outcomes
55
+ @enhanced_outcomes ||= RSpec.configuration.formatters.grep(Inspec::Formatters::Base).first.enhanced_outcomes
56
+ end
57
+
58
+ def add_enhanced_outcomes(control_id)
59
+ if control_has_error(@notifications[control_id])
60
+ "error"
61
+ elsif control_has_impact_zero(@notifications[control_id])
62
+ "not_applicable"
63
+ elsif control_has_all_tests_skipped(@notifications[control_id])
64
+ "not_reviewed"
65
+ elsif control_has_any_tests_failed(@notifications[control_id])
66
+ "failed"
67
+ else
68
+ "passed"
69
+ end
70
+ end
71
+
72
+ def control_has_error(notifications)
73
+ notifications.any? do |notification_data|
74
+ notification, _status = notification_data
75
+ !notification.example.exception.nil? && !(notification.example.exception.is_a? RSpec::Expectations::ExpectationNotMetError) && !notification.example.exception.backtrace.nil? && (!notification.description.include? "No-op") # No-op exception occurs in case of not_applicable_if
76
+ end
77
+ end
78
+
79
+ def control_has_all_tests_skipped(notifications)
80
+ notifications.all? do |notification_data|
81
+ _notification, status = notification_data
82
+ status == "skipped"
83
+ end
84
+ end
85
+
86
+ def control_has_any_tests_failed(notifications)
87
+ notifications.any? do |notification_data|
88
+ _notification, status = notification_data
89
+ status == "failed"
90
+ end
91
+ end
92
+
93
+ def control_has_impact_zero(notifications)
94
+ notification_data = notifications.first
95
+ notification_impact = notification_data.first.example.metadata[:impact]
96
+ notification_data && !notification_impact.nil? && notification_impact.to_f == 0.0
97
+ end
98
+
99
+ def collect_notifications(notification, control_id, status)
100
+ if @notifications[control_id].nil?
101
+ @notifications[control_id] = [[notification, status]]
102
+ else
103
+ @notifications[control_id].push([notification, status])
104
+ end
105
+ end
52
106
  end
53
107
  end
@@ -383,24 +383,25 @@ module Inspec
383
383
  @runner_context
384
384
  end
385
385
 
386
- def collect_gem_dependencies(profile_context)
386
+ # This collects the gem dependencies data from parent and its dependent profiles
387
+ def collect_gem_dependencies
387
388
  gem_dependencies = []
388
- all_profiles = []
389
- profile_context.dependencies.list.values.each do |requirement|
390
- all_profiles << requirement.profile
391
- end
392
- all_profiles << self
393
- all_profiles.each do |profile|
389
+ # This collects the dependent profiles gem dependencies if any
390
+ locked_dependencies.dep_list.each do |_name, dep|
391
+ profile = dep.profile
394
392
  gem_dependencies << profile.metadata.gem_dependencies unless profile.metadata.gem_dependencies.empty?
395
393
  end
394
+ # Appends the parent profile gem dependencies which are available through metadata
395
+ gem_dependencies << metadata.gem_dependencies unless metadata.gem_dependencies.empty?
396
396
  gem_dependencies.flatten.uniq
397
397
  end
398
398
 
399
399
  # Loads the required gems specified in the Profile's metadata file from default inspec gems path i.e. ~/.inspec/gems
400
400
  # else installs and loads them.
401
401
  def load_gem_dependencies
402
- gem_dependencies = collect_gem_dependencies(load_libraries)
402
+ gem_dependencies = collect_gem_dependencies
403
403
  gem_dependencies.each do |gem_data|
404
+
404
405
  dependency_loader = DependencyLoader.new
405
406
  if dependency_loader.gem_version_installed?(gem_data[:name], gem_data[:version]) ||
406
407
  dependency_loader.gem_installed?(gem_data[:name])
@@ -5,6 +5,7 @@ module Inspec::Reporters
5
5
  include Inspec::Utils::RunDataFilters
6
6
 
7
7
  attr_reader :run_data
8
+ attr_accessor :enhanced_outcomes
8
9
 
9
10
  def initialize(config)
10
11
  @config = config
@@ -9,6 +9,9 @@ module Inspec::Reporters
9
9
  "passed" => "\033[0;1;32m",
10
10
  "skipped" => "\033[0;37m",
11
11
  "reset" => "\033[0m",
12
+ "error" => "\033[34m",
13
+ "not_applicable" => "\033[36m",
14
+ "not_reviewed" => "\033[33m",
12
15
  }.freeze
13
16
 
14
17
  # Most currently available Windows terminals have poor support
@@ -18,6 +21,9 @@ module Inspec::Reporters
18
21
  "skipped" => "[SKIP]",
19
22
  "passed" => "[PASS]",
20
23
  "unknown" => "[UNKN]",
24
+ "error" => "[ERR]",
25
+ "not_applicable" => "[N/A]",
26
+ "not_reviewed" => "[N/R]",
21
27
  }.freeze
22
28
  else
23
29
  # Extended colors for everyone else
@@ -26,6 +32,9 @@ module Inspec::Reporters
26
32
  "passed" => "\033[38;5;41m",
27
33
  "skipped" => "\033[38;5;247m",
28
34
  "reset" => "\033[0m",
35
+ "error" => "\033[0;38;5;21m",
36
+ "not_applicable" => "\033[0;38;5;117m",
37
+ "not_reviewed" => "\033[0;38;5;214m",
29
38
  }.freeze
30
39
 
31
40
  # Groovy UTF-8 characters for everyone else...
@@ -35,6 +44,9 @@ module Inspec::Reporters
35
44
  "skipped" => "↺",
36
45
  "passed" => "✔",
37
46
  "unknown" => "?",
47
+ "error" => "ERR",
48
+ "not_applicable" => "N/A",
49
+ "not_reviewed" => "N/R",
38
50
  }.freeze
39
51
  end
40
52
 
@@ -63,7 +75,11 @@ module Inspec::Reporters
63
75
  end
64
76
 
65
77
  output("")
66
- print_profile_summary
78
+ if enhanced_outcomes
79
+ print_control_outcomes_summary
80
+ else
81
+ print_profile_summary
82
+ end
67
83
  print_tests_summary
68
84
  end
69
85
 
@@ -88,6 +104,7 @@ module Inspec::Reporters
88
104
  def print_standard_control_results(profile)
89
105
  standard_controls_from_profile(profile).each do |control_from_profile|
90
106
  control = Control.new(control_from_profile)
107
+ control.enhanced_outcomes = enhanced_outcomes
91
108
  next if control.results.nil?
92
109
 
93
110
  output(format_control_header(control))
@@ -122,7 +139,7 @@ module Inspec::Reporters
122
139
  end
123
140
 
124
141
  def format_control_header(control)
125
- impact = control.impact_string
142
+ impact = enhanced_outcomes ? control.impact_string_for_enhanced_outcomes : control.impact_string
126
143
  format_message(
127
144
  color: impact,
128
145
  indicator: impact,
@@ -292,6 +309,68 @@ module Inspec::Reporters
292
309
  }
293
310
  end
294
311
 
312
+ def control_outcomes_summary
313
+ failed = 0
314
+ passed = 0
315
+ error = 0
316
+ not_reviewed = 0
317
+ not_applicable = 0
318
+
319
+ all_unique_controls.each do |control|
320
+ next if control[:status].empty?
321
+
322
+ if control[:status] == "failed"
323
+ failed += 1
324
+ elsif control[:status] == "error"
325
+ error += 1
326
+ elsif control[:status] == "not_reviewed"
327
+ not_reviewed += 1
328
+ elsif control[:status] == "not_applicable"
329
+ not_applicable += 1
330
+ else
331
+ passed += 1
332
+ end
333
+ end
334
+
335
+ total = failed + passed + error + not_reviewed + not_applicable
336
+
337
+ {
338
+ "total" => total,
339
+ "failed" => failed,
340
+ "passed" => passed,
341
+ "error" => error,
342
+ "not_reviewed" => not_reviewed,
343
+ "not_applicable" => not_applicable,
344
+ }
345
+ end
346
+
347
+ def print_control_outcomes_summary
348
+ summary = control_outcomes_summary
349
+ return unless summary["total"] > 0
350
+
351
+ success_str = summary["passed"] == 1 ? "1 successful control" : "#{summary["passed"]} successful controls"
352
+ failed_str = summary["failed"] == 1 ? "1 control failure" : "#{summary["failed"]} control failures"
353
+ error_str = summary["error"] == 1 ? "1 control has error" : "#{summary["error"]} controls have error"
354
+ not_rev_str = summary["not_reviewed"] == 1 ? "1 control not reviewed" : "#{summary["not_reviewed"]} controls not reviewed"
355
+ not_app_str = summary["not_applicable"] == 1 ? "1 control not applicable" : "#{summary["not_applicable"]} controls not applicable"
356
+
357
+ success_color = summary["passed"] > 0 ? "passed" : "no_color"
358
+ failed_color = summary["failed"] > 0 ? "failed" : "no_color"
359
+ error_color = summary["error"] > 0 ? "error" : "no_color"
360
+ not_rev_color = summary["not_reviewed"] > 0 ? "not_reviewed" : "no_color"
361
+ not_app_color = summary["not_applicable"] > 0 ? "not_applicable" : "no_color"
362
+
363
+ s = format(
364
+ "Profile Summary: %s, %s, %s, %s, %s",
365
+ format_with_color(success_color, success_str),
366
+ format_with_color(failed_color, failed_str),
367
+ format_with_color(not_rev_color, not_rev_str),
368
+ format_with_color(not_app_color, not_app_str),
369
+ format_with_color(error_color, error_str)
370
+ )
371
+ output(s) if summary["total"] > 0
372
+ end
373
+
295
374
  def print_profile_summary
296
375
  summary = profile_summary
297
376
  return unless summary["total"] > 0
@@ -350,6 +429,7 @@ module Inspec::Reporters
350
429
 
351
430
  class Control
352
431
  attr_reader :data
432
+ attr_accessor :enhanced_outcomes
353
433
 
354
434
  def initialize(control_hash)
355
435
  @data = control_hash
@@ -379,6 +459,10 @@ module Inspec::Reporters
379
459
  id.start_with?("(generated from ")
380
460
  end
381
461
 
462
+ def status
463
+ data[:status]
464
+ end
465
+
382
466
  def title_for_report
383
467
  # if this is an anonymous control, just grab the resource title from any result entry
384
468
  return results.first[:resource_title] if anonymous?
@@ -392,10 +476,17 @@ module Inspec::Reporters
392
476
  # append a failure summary if appropriate.
393
477
  title_for_report += " (#{failure_count} failed)" if failure_count > 0
394
478
  title_for_report += " (#{skipped_count} skipped)" if skipped_count > 0
395
-
396
479
  title_for_report
397
480
  end
398
481
 
482
+ def impact_string_for_enhanced_outcomes
483
+ if impact.nil?
484
+ "unknown"
485
+ else
486
+ status
487
+ end
488
+ end
489
+
399
490
  def impact_string
400
491
  if anonymous?
401
492
  nil
@@ -114,7 +114,7 @@ module Inspec::Reporters
114
114
 
115
115
  def profile_controls(profile)
116
116
  (profile[:controls] || []).map { |c|
117
- {
117
+ control_hash = {
118
118
  id: c[:id],
119
119
  title: c[:title],
120
120
  desc: c.dig(:descriptions, :default),
@@ -130,6 +130,8 @@ module Inspec::Reporters
130
130
  waiver_data: c[:waiver_data] || {},
131
131
  results: profile_results(c),
132
132
  }
133
+ control_hash.merge!({ status: c[:status] }) if enhanced_outcomes
134
+ control_hash
133
135
  }
134
136
  end
135
137
 
@@ -3,7 +3,9 @@ require "yaml"
3
3
  module Inspec::Reporters
4
4
  class Yaml < Base
5
5
  def render
6
- output(Inspec::Reporters::Json.new({ run_data: run_data }).report.to_yaml, false)
6
+ json_reporter_obj = Inspec::Reporters::Json.new({ run_data: run_data })
7
+ json_reporter_obj.enhanced_outcomes = enhanced_outcomes
8
+ output(json_reporter_obj.report.to_yaml, false)
7
9
  end
8
10
 
9
11
  def report
@@ -7,7 +7,7 @@ require "inspec/reporters/yaml"
7
7
 
8
8
  module Inspec::Reporters
9
9
  # rubocop:disable Metrics/CyclomaticComplexity
10
- def self.render(reporter, run_data)
10
+ def self.render(reporter, run_data, enhanced_outcomes = false)
11
11
  name, config = reporter.dup
12
12
  config[:run_data] = run_data
13
13
  case name
@@ -29,6 +29,7 @@ module Inspec::Reporters
29
29
  activator.activate!
30
30
  reporter = activator.implementation_class.new(config)
31
31
  end
32
+ reporter.enhanced_outcomes = enhanced_outcomes
32
33
 
33
34
  # optional send_report method on reporter
34
35
  return reporter.send_report if defined?(reporter.send_report)
@@ -66,7 +66,7 @@ module Inspec::Resources
66
66
  def user_permissions
67
67
  return {} unless exist?
68
68
 
69
- return skip_reource"`user_permissions` is not supported on your OS yet." unless inspec.os.windows?
69
+ return skip_resource "`user_permissions` is not supported on your OS yet." unless inspec.os.windows?
70
70
 
71
71
  @perms_provider.user_permissions(file)
72
72
  end
@@ -4,7 +4,7 @@
4
4
 
5
5
  require "inspec/resources/command"
6
6
  require "faraday" unless defined?(Faraday)
7
- require "faraday_middleware"
7
+ require "faraday/follow_redirects"
8
8
  require "hashie"
9
9
 
10
10
  module Inspec::Resources
@@ -153,7 +153,7 @@ module Inspec::Resources
153
153
 
154
154
  conn = Faraday.new(url: url, headers: request_headers, params: params, ssl: { verify: ssl_verify? }) do |builder|
155
155
  builder.request :url_encoded
156
- builder.use FaradayMiddleware::FollowRedirects, limit: max_redirects unless max_redirects.nil?
156
+ builder.use Faraday::FollowRedirects::Middleware, limit: max_redirects unless max_redirects.nil?
157
157
  builder.adapter Faraday.default_adapter
158
158
  end
159
159
 
@@ -304,11 +304,11 @@ module Inspec::Resources
304
304
  # Insecure not supported simply https://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error
305
305
  cmd << "-MaximumRedirection #{max_redirects}" unless max_redirects.nil?
306
306
  request_headers["Authorization"] = """ '\"Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(\"#{username}:#{password}\")) +'\"' """ unless username.nil? || password.nil?
307
- request_header_string = nil
307
+ request_header_array = []
308
308
  request_headers.each do |k, v|
309
- request_header_string << " #{k} = #{v}"
309
+ request_header_array << " '#{k}' = '#{v}'"
310
310
  end
311
- cmd << "-Headers @{#{request_header_string.join(";")}}" unless request_header_string.nil?
311
+ cmd << "-Headers @{#{request_header_array.join(";")}}" unless request_header_array.empty?
312
312
  if params.nil?
313
313
  cmd << "'#{url}'"
314
314
  else
@@ -9,14 +9,26 @@ module Inspec::Resources
9
9
  describe lxc("ubuntu-container") do
10
10
  it { should exist }
11
11
  it { should be_running }
12
+ its("name") { should eq "ubuntu-container" }
13
+ its("status") { should cmp "Running" }
14
+ its("type") { should eq "container" }
15
+ its("architecture") { should eq "x86_64" }
16
+ its("pid") { should eq 1378 }
17
+ its("created_at") { should eq "2022/08/16 12:07 UTC" }
18
+ its("last_used_at") { should eq "2022/08/17 05:06 UTC" }
19
+ its("resources") { should include "Disk usage" }
12
20
  end
13
21
  EXAMPLE
14
22
 
23
+ attr_reader :container_info, :container_name
24
+
15
25
  # Resource initialization.
16
26
  def initialize(container_name)
17
27
  @container_name = container_name
18
28
 
19
29
  raise Inspec::Exceptions::ResourceSkipped, "The `lxc` resource is not supported on your OS yet." unless inspec.os.linux?
30
+
31
+ @container_info = populate_container_info
20
32
  end
21
33
 
22
34
  def resource_id
@@ -28,17 +40,60 @@ module Inspec::Resources
28
40
  end
29
41
 
30
42
  def exists?
31
- lxc_info_cmd.exit_status.to_i == 0
43
+ !@container_info.empty?
32
44
  end
33
45
 
34
46
  def running?
35
- container_info = lxc_info_cmd.stdout.split(":").map(&:strip)
36
- container_info[0] == "Status" && container_info[1] == "Running"
47
+ @container_info.key?("Status") && @container_info["Status"].casecmp("Running") == 0
48
+ end
49
+
50
+ def name
51
+ @container_info["Name"]
52
+ end
53
+
54
+ def status
55
+ @container_info["Status"]
56
+ end
57
+
58
+ def type
59
+ @container_info["Type"]
60
+ end
61
+
62
+ def architecture
63
+ @container_info["Architecture"]
64
+ end
65
+
66
+ def pid
67
+ @container_info["PID"]
68
+ end
69
+
70
+ def created_at
71
+ @container_info["Created"]
72
+ end
73
+
74
+ def last_used_at
75
+ @container_info["Last Used"]
76
+ end
77
+
78
+ def resources
79
+ @container_info["Resources"]
37
80
  end
38
81
 
39
82
  private
40
83
 
41
- # Method to find lxc
84
+ def populate_container_info
85
+ lxc_util = find_lxc_or_error
86
+ lxc_info_cmd = inspec.command("#{lxc_util} info #{@container_name}")
87
+
88
+ if lxc_info_cmd.exit_status.to_i == 0
89
+ parse_command_output(lxc_info_cmd.stdout)
90
+ elsif lxc_info_cmd.stderr =~ /Error: Instance not found/
91
+ {}
92
+ else
93
+ raise Inspec::Exceptions::ResourceFailed, "Unable to retrieve information for #{container_name}.\n#{lxc_info_cmd.stderr}"
94
+ end
95
+ end
96
+
42
97
  def find_lxc_or_error
43
98
  %w{/usr/sbin/lxc /sbin/lxc lxc}.each do |cmd|
44
99
  return cmd if inspec.command(cmd).exist?
@@ -47,11 +102,12 @@ module Inspec::Resources
47
102
  raise Inspec::Exceptions::ResourceFailed, "Could not find `lxc`"
48
103
  end
49
104
 
50
- def lxc_info_cmd
51
- bin = find_lxc_or_error
52
- info_cmd = "info #{@container_name} | grep -i Status"
53
- lxc_cmd = format("%s %s", bin, info_cmd).strip
54
- inspec.command(lxc_cmd)
105
+ def parse_command_output(output)
106
+ require "yaml" unless defined?(YAML)
107
+ YAML.load(output)
108
+ rescue Psych::SyntaxError => e
109
+ warn "Could not parse the command output.\n#{e.message}"
110
+ {}
55
111
  end
56
112
  end
57
113
  end
@@ -84,6 +84,11 @@ module Inspec::Resources
84
84
  options[:ssl_cert] = @ssl_cert unless @ssl_cert.nil?
85
85
  options[:ssl_ca_cert] = @ssl_ca_cert unless @ssl_ca_cert.nil?
86
86
 
87
+ # Setting the logger level to INFO as mongo gem version 2.13.2 is using DEBUG as the log level Ref: https://github.com/mongodb/mongo-ruby-driver/blob/v2.13.2/lib/mongo/logger.rb#L79
88
+ # Latest version of the mongo gem don't have this issue as it set to INFO level Ref: https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/logger.rb#L82
89
+ # We pinned the version to 2.13.2 as the latest version of the mongo gem has broken symlink https://jira.mongodb.org/browse/RUBY-2546 which causes omnibus build failure.
90
+ # Once we get the latest version working we can remove logger level set here.
91
+ Mongo::Logger.logger.level = Logger::INFO
87
92
  @client = Mongo::Client.new([ "#{host}:#{port}" ], options)
88
93
 
89
94
  rescue => e