inspec-core 4.56.17 → 5.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/etc/deprecations.json +12 -16
  3. data/inspec-core.gemspec +1 -1
  4. data/lib/inspec/base_cli.rb +14 -2
  5. data/lib/inspec/cli.rb +15 -0
  6. data/lib/inspec/dependency_installer.rb +74 -0
  7. data/lib/inspec/dependency_loader.rb +97 -0
  8. data/lib/inspec/dsl.rb +11 -2
  9. data/lib/inspec/errors.rb +7 -0
  10. data/lib/inspec/formatters/base.rb +23 -0
  11. data/lib/inspec/metadata.rb +36 -0
  12. data/lib/inspec/plugin/v2/installer.rb +9 -2
  13. data/lib/inspec/plugin/v2/loader.rb +13 -0
  14. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
  15. data/lib/inspec/plugin/v2/status.rb +2 -1
  16. data/lib/inspec/profile.rb +63 -0
  17. data/lib/inspec/reporters/automate.rb +1 -1
  18. data/lib/inspec/reporters/cli.rb +1 -1
  19. data/lib/inspec/reporters/json.rb +31 -11
  20. data/lib/inspec/resource.rb +6 -0
  21. data/lib/inspec/resources/apt.rb +12 -6
  22. data/lib/inspec/resources/cgroup.rb +101 -0
  23. data/lib/inspec/resources/cron.rb +49 -0
  24. data/lib/inspec/resources/ipfilter.rb +59 -0
  25. data/lib/inspec/resources/ipnat.rb +58 -0
  26. data/lib/inspec/resources/lxc.rb +57 -0
  27. data/lib/inspec/resources/oracledb_session.rb +7 -3
  28. data/lib/inspec/resources/postgres_session.rb +4 -2
  29. data/lib/inspec/resources/virtualization.rb +9 -3
  30. data/lib/inspec/resources.rb +3 -16
  31. data/lib/inspec/runner.rb +18 -1
  32. data/lib/inspec/runner_rspec.rb +15 -0
  33. data/lib/inspec/schema/exec_json.rb +59 -58
  34. data/lib/inspec/schema/exec_json_min.rb +16 -16
  35. data/lib/inspec/schema/primitives.rb +68 -51
  36. data/lib/inspec/schema/profile_json.rb +27 -27
  37. data/lib/inspec/schema.rb +1 -0
  38. data/lib/inspec/ui.rb +10 -0
  39. data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
  40. data/lib/inspec/version.rb +1 -1
  41. data/lib/inspec.rb +3 -0
  42. data/lib/plugins/inspec-artifact/inspec-artifact.gemspec +9 -0
  43. data/lib/plugins/inspec-compliance/inspec-compliance.gemspec +9 -0
  44. data/lib/plugins/inspec-habitat/inspec-habitat.gemspec +9 -0
  45. data/lib/plugins/inspec-init/inspec-init.gemspec +9 -0
  46. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
  47. data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
  48. data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
  49. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
  50. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
  51. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
  52. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
  53. data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
  54. data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
  55. data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
  56. data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
  57. data/lib/plugins/inspec-plugin-manager-cli/inspec-plugin-manager-cli.gemspec +10 -0
  58. data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +15 -11
  59. data/lib/plugins/inspec-reporter-html2/inspec-reporter-html2.gemspec +9 -0
  60. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
  61. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
  62. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
  63. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
  64. data/lib/plugins/inspec-reporter-json-min/inspec-reporter-json-min.gemspec +9 -0
  65. data/lib/plugins/inspec-reporter-junit/inspec-reporter-junit.gemspec +9 -0
  66. data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
  67. data/lib/plugins/inspec-streaming-reporter-progress-bar/inspec-streaming-reporter-progress-bar.gemspec +9 -0
  68. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
  69. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
  70. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
  71. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
  72. metadata +31 -3
@@ -13,6 +13,8 @@ require "inspec/dependencies/cache"
13
13
  require "inspec/dependencies/lockfile"
14
14
  require "inspec/dependencies/dependency_set"
15
15
  require "inspec/utils/json_profile_summary"
16
+ require "inspec/dependency_loader"
17
+ require "inspec/dependency_installer"
16
18
 
17
19
  module Inspec
18
20
  class Profile
@@ -378,6 +380,66 @@ module Inspec
378
380
  @runner_context
379
381
  end
380
382
 
383
+ def collect_gem_dependencies(profile_context)
384
+ gem_dependencies = []
385
+ all_profiles = []
386
+ profile_context.dependencies.list.values.each do |requirement|
387
+ all_profiles << requirement.profile
388
+ end
389
+ all_profiles << self
390
+ all_profiles.each do |profile|
391
+ gem_dependencies << profile.metadata.gem_dependencies unless profile.metadata.gem_dependencies.empty?
392
+ end
393
+ gem_dependencies.flatten.uniq
394
+ end
395
+
396
+ # Loads the required gems specified in the Profile's metadata file from default inspec gems path i.e. ~/.inspec/gems
397
+ # else installs and loads them.
398
+ def load_gem_dependencies
399
+ gem_dependencies = collect_gem_dependencies(load_libraries)
400
+ gem_dependencies.each do |gem_data|
401
+ dependency_loader = DependencyLoader.new
402
+ if dependency_loader.gem_version_installed?(gem_data[:name], gem_data[:version]) ||
403
+ dependency_loader.gem_installed?(gem_data[:name])
404
+ load_gem_dependency(gem_data)
405
+ else
406
+ if Inspec::Config.cached[:auto_install_gems]
407
+ install_gem_dependency(gem_data)
408
+ load_gem_dependency(gem_data)
409
+ else
410
+ ui = Inspec::UI.new
411
+ gem_dependencies.each { |gem_dependency| ui.list_item("#{gem_dependency[:name]} #{gem_dependency[:version]}") }
412
+ choice = ui.prompt.select("Would you like to install profile gem dependencies listed above?", %w{Yes No})
413
+ if choice == "Yes"
414
+ Inspec::Config.cached[:auto_install_gems] = true
415
+ load_gem_dependencies
416
+ else
417
+ ui.error "Unable to resolve above listed profile gem dependencies."
418
+ Inspec::UI.new.exit(:gem_dependency_load_error)
419
+ end
420
+ end
421
+ end
422
+ end
423
+ end
424
+
425
+ # Requires gem_data as argument.
426
+ # gem_dta example: { name: "gem_name", version: "0.0.1"}
427
+ def load_gem_dependency(gem_data)
428
+ dependency_loader = DependencyLoader.new(nil, [gem_data])
429
+ dependency_loader.load
430
+ rescue Inspec::GemDependencyLoadError => e
431
+ raise e.message
432
+ end
433
+
434
+ # Requires gem_data as argument.
435
+ # gem_dta example: { name: "gem_name", version: "0.0.1"}
436
+ def install_gem_dependency(gem_data)
437
+ gem_dependency = DependencyInstaller.new(nil, [gem_data])
438
+ gem_dependency.install
439
+ rescue Inspec::GemDependencyInstallError => e
440
+ raise e.message
441
+ end
442
+
381
443
  def to_s
382
444
  "Inspec::Profile<#{name}>"
383
445
  end
@@ -774,6 +836,7 @@ module Inspec
774
836
  end
775
837
 
776
838
  def load_checks_params(params)
839
+ load_gem_dependencies
777
840
  load_libraries
778
841
  tests = collect_tests
779
842
  params[:controls] = controls = {}
@@ -21,7 +21,7 @@ module Inspec::Reporters
21
21
  final_report[:type] = "inspec_report"
22
22
 
23
23
  final_report[:end_time] = Time.now.utc.strftime("%FT%TZ")
24
- final_report[:node_uuid] = report[:platform][:target_id] || @config["node_uuid"] || @config["target_id"]
24
+ final_report[:node_uuid] = @config["node_uuid"] || report[:platform][:target_id]
25
25
  raise Inspec::ReporterError, "Cannot find a UUID for your node. Please specify one via json-config." if final_report[:node_uuid].nil?
26
26
 
27
27
  final_report[:report_uuid] = @config["report_uuid"] || uuid_from_string(final_report[:end_time] + final_report[:node_uuid])
@@ -76,7 +76,7 @@ module Inspec::Reporters
76
76
  }
77
77
  header["Failure Message"] = profile[:status_message] if profile[:status] == "failed"
78
78
  header["Target"] = run_data[:platform][:target] unless run_data[:platform][:target].nil?
79
- header["Target ID"] = @config["target_id"] unless @config["target_id"].nil?
79
+ header["Target ID"] = run_data[:platform][:target_id] || ""
80
80
 
81
81
  pad = header.keys.max_by(&:length).length + 1
82
82
  header.each do |title, value|
@@ -29,28 +29,48 @@ module Inspec::Reporters
29
29
  {
30
30
  name: run_data[:platform][:name],
31
31
  release: run_data[:platform][:release],
32
- target_id: run_data[:platform][:target_id] || @config["target_id"],
32
+ target_id: run_data[:platform][:target_id] || "",
33
33
  }.reject { |_k, v| v.nil? }
34
34
  end
35
35
 
36
36
  def profile_results(control)
37
37
  (control[:results] || []).map { |r|
38
38
  {
39
- status: r[:status],
40
- code_desc: r[:code_desc],
41
- run_time: r[:run_time],
42
- start_time: r[:start_time],
43
- resource: r[:resource],
44
- skip_message: r[:skip_message],
45
- message: r[:message],
46
- exception: r[:exception],
47
- backtrace: r[:backtrace],
48
- resource_class: r[:resource_class],
39
+ status: r[:status],
40
+ code_desc: r[:code_desc],
41
+ run_time: r[:run_time],
42
+ start_time: r[:start_time],
43
+ resource: r[:resource],
44
+ skip_message: r[:skip_message],
45
+ message: r[:message],
46
+ exception: r[:exception],
47
+ backtrace: r[:backtrace],
48
+ resource_class: r[:resource_class],
49
49
  resource_params: r[:resource_params].to_s,
50
+ resource_id: extract_resource_id(r),
50
51
  }.reject { |_k, v| v.nil? }
51
52
  }
52
53
  end
53
54
 
55
+ def extract_resource_id(r)
56
+ # According to the RunData API, this is supposed to be an anonymous
57
+ # class that represents a resource, with embedded instance methods....
58
+ resource_obj = r[:resource_title]
59
+ return resource_obj.resource_id if resource_obj.respond_to?(:resource_id)
60
+
61
+ # But sometimes, it isn't, and has been collapsed into the to_s stringification of the resource.
62
+ if resource_obj.is_a?(String)
63
+ orig_str = resource_obj
64
+ # Try to trim off the resource class - eg "File /some/path" => "/some/path"
65
+ trimmed_str = orig_str.sub(/^#{r[:resource_class]}/i, "").strip
66
+ trimmed_str.empty? ? orig_str : trimmed_str
67
+ else
68
+ # Boo, InSpec is crazy, and we don't know what it possibly could be.
69
+ # Failsafe for resource_id is empty string.
70
+ ""
71
+ end
72
+ end
73
+
54
74
  def profiles
55
75
  run_data[:profiles].map do |p|
56
76
  res = {
@@ -34,6 +34,12 @@ module Inspec
34
34
  Inspec::Resource.support_registry[key].push(criteria)
35
35
  end
36
36
 
37
+ def resource_id(value = nil)
38
+ @resource_id = value if value
39
+ @resource_id = "" if @resource_id.nil?
40
+ @resource_id
41
+ end
42
+
37
43
  # TODO: this is pretty terrible and is only here to work around
38
44
  # the idea that we've trained resource authors to make initialize
39
45
  # methods w/o calling super.
@@ -135,19 +135,25 @@ module Inspec::Resources
135
135
 
136
136
  class PpaRepository < AptRepository
137
137
  name "ppa"
138
+ desc "Use the ppa InSpec audit resource to verify PPA repositories on the Debian-based linux platforms."
139
+ example <<~EXAMPLE
140
+ describe ppa('ubuntu-wine/ppa') do
141
+ it { should exist }
142
+ it { should be_enabled }
143
+ end
144
+
145
+ describe ppa('ppa:ubuntu-wine/ppa') do
146
+ it { should exist }
147
+ it { should be_enabled }
148
+ end
149
+ EXAMPLE
138
150
 
139
151
  def exists?
140
- deprecated
141
152
  super()
142
153
  end
143
154
 
144
155
  def enabled?
145
- deprecated
146
156
  super()
147
157
  end
148
-
149
- def deprecated
150
- Inspec.deprecate(:resource_ppa, "The `ppa` resource is deprecated. Please use `apt`")
151
- end
152
158
  end
153
159
  end
@@ -0,0 +1,101 @@
1
+ require "inspec/resources/command"
2
+ module Inspec::Resources
3
+ class Cgroup < Inspec.resource(1)
4
+ name "cgroup"
5
+ # Restrict to only run on the below platform
6
+ supports platform: "linux"
7
+ desc "Use the cgroup InSpec audit resource to test cgroup subsytem's parameters."
8
+
9
+ example <<~EXAMPLE
10
+ describe cgroup("foo") do
11
+ its("cpuset.cpus") { should eq 0 }
12
+ its("memory.limit_in_bytes") { should eq 499712 }
13
+ its("memory.limit_in_bytes") { should be <= 500000 }
14
+ its("memory.numa_stat") { should match /total=0/ }
15
+ end
16
+ EXAMPLE
17
+
18
+ # Resource initialization.
19
+ def initialize(cgroup_name)
20
+ raise Inspec::Exceptions::ResourceSkipped, "The `cgroup` resource is not supported on your OS yet." unless inspec.os.linux?
21
+
22
+ @cgroup_name = cgroup_name
23
+ @valid_queries, @valid_queries_split = [], []
24
+ find_valid_queries
25
+ # Used to track the method calls in an "its" query
26
+ @cgroup_info_query = []
27
+ end
28
+
29
+ def resource_id
30
+ @cgroup_name
31
+ end
32
+
33
+ def to_s
34
+ "cgroup #{resource_id}"
35
+ end
36
+
37
+ def method_missing(param)
38
+ # Add the latest param we've seen to the list and form the query with all the params we've seen so far.
39
+ @cgroup_info_query << param.to_s
40
+ query = @cgroup_info_query.join(".")
41
+
42
+ # The ith level param must match with atleast one row's ith column of @valid_queries_split
43
+ # Else there is no way, we would find any valid query in further iteration, so raise exception.
44
+ if @valid_queries_split.map { |e| e[@cgroup_info_query.length - 1] }.include?(param.to_s)
45
+ # If the query form so far is part of @valid_queries, we are good to trigger find_cgroup_info
46
+ # else go for next level of param
47
+ if @valid_queries.include?(query)
48
+ @cgroup_info_query = []
49
+ find_cgroup_info(query)
50
+ else
51
+ self
52
+ end
53
+ else
54
+ @cgroup_info_query = []
55
+
56
+ raise Inspec::Exceptions::ResourceFailed, "The query #{query} does not appear to be valid."
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ # Method to find cgget tool
63
+ def find_cgget_or_error
64
+ %w{/usr/sbin/cgget /sbin/cgget cgget}.each do |cmd|
65
+ return cmd if inspec.command(cmd).exist?
66
+ end
67
+
68
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `cgget`"
69
+ end
70
+
71
+ # find the cgroup info of the query which is given as input by the user
72
+ def find_cgroup_info(query)
73
+ bin = find_cgget_or_error
74
+ cgget_cmd = "#{bin} -n -r #{query} #{@cgroup_name}"
75
+ cmd = inspec.command(cgget_cmd)
76
+
77
+ raise Inspec::Exceptions::ResourceFailed, "Executing cgget failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
78
+
79
+ # For complex returns the user must use match /the_regex/
80
+ param_value = cmd.stdout.split(":")
81
+ return nil if param_value.nil? || param_value.empty?
82
+
83
+ param_value = param_value[1].strip.split("\t").join
84
+ param_value.match(/^\d+$/) ? param_value.to_i : param_value
85
+ end
86
+
87
+ # find all the information about all relevant controllers for the current cgroup
88
+ def find_valid_queries
89
+ bin = find_cgget_or_error
90
+ cgget_all_cmd = "#{bin} -n -a #{@cgroup_name}"
91
+ cmd = inspec.command(cgget_all_cmd)
92
+
93
+ raise Inspec::Exceptions::ResourceFailed, "Executing cgget failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
94
+
95
+ queries = cmd.stdout.to_s.gsub(/:.*/, "").gsub(/^\s+.*/, "").split("\n")
96
+ # store the relevant controller parameters in @valid_queries and the dot splitted paramters into @valid_queries_split
97
+ @valid_queries = queries.map { |q| q if q.length > 0 }.compact
98
+ @valid_queries_split = @valid_queries.map { |q| q.split(".") }.compact
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,49 @@
1
+ require "inspec/resources/crontab"
2
+
3
+ module Inspec::Resources
4
+ class Cron < Crontab
5
+ name "cron"
6
+ supports platform: "unix"
7
+ desc "Use the cron InSpec audit resource to test entires in the crontab file for a given user. This also can be used as alias to crontab resource."
8
+ example <<~EXAMPLE
9
+ describe cron do
10
+ it { should have_entry '* * * * * /usr/local/bin/foo' }
11
+ end
12
+
13
+ describe cron(user: "username") do
14
+ its(:table) { should match /you can use regexp/ }
15
+ end
16
+ EXAMPLE
17
+
18
+ def initialize(opts = nil)
19
+ super
20
+ @params = read_cron_contents
21
+ end
22
+
23
+ def read_cron_contents
24
+ result = inspec.command(crontab_cmd)
25
+ if result.exit_status == 0
26
+ result.stdout.lines.map { |l| parse_comment_line(l, comment_char: "#", standalone_comments: false)[0].strip }
27
+ else
28
+ error = result.stdout + "\n" + result.stderr
29
+ raise Inspec::Exceptions::ResourceFailed, "Error while executing #{crontab_cmd} command: #{error}"
30
+ end
31
+ end
32
+
33
+ def table
34
+ @params.reject(&:empty?).join("\n")
35
+ end
36
+
37
+ def has_entry?(rule)
38
+ @params.include?(rule)
39
+ end
40
+
41
+ def to_s
42
+ if is_user_crontab?
43
+ "cron for user #{@user}"
44
+ else
45
+ "cron for current user"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -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
@@ -0,0 +1,57 @@
1
+ require "inspec/resources/command"
2
+ module Inspec::Resources
3
+ class Lxc < Inspec.resource(1)
4
+ name "lxc"
5
+ # Restrict to only run on the below platforms
6
+ supports platform: "linux"
7
+ desc "Use the lxc InSpec audit resource to test if container exists and/or is running for linux container"
8
+ example <<~EXAMPLE
9
+ describe lxc("ubuntu-container") do
10
+ it { should exist }
11
+ it { should be_running }
12
+ end
13
+ EXAMPLE
14
+
15
+ # Resource initialization.
16
+ def initialize(container_name)
17
+ @container_name = container_name
18
+
19
+ raise Inspec::Exceptions::ResourceSkipped, "The `lxc` resource is not supported on your OS yet." unless inspec.os.linux?
20
+ end
21
+
22
+ def resource_id
23
+ @container_name
24
+ end
25
+
26
+ def to_s
27
+ "lxc #{resource_id}"
28
+ end
29
+
30
+ def exists?
31
+ lxc_info_cmd.exit_status.to_i == 0
32
+ end
33
+
34
+ def running?
35
+ container_info = lxc_info_cmd.stdout.split(":").map(&:strip)
36
+ container_info[0] == "Status" && container_info[1] == "Running"
37
+ end
38
+
39
+ private
40
+
41
+ # Method to find lxc
42
+ def find_lxc_or_error
43
+ %w{/usr/sbin/lxc /sbin/lxc lxc}.each do |cmd|
44
+ return cmd if inspec.command(cmd).exist?
45
+ end
46
+
47
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `lxc`"
48
+ end
49
+
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)
55
+ end
56
+ end
57
+ end
@@ -61,9 +61,13 @@ module Inspec::Resources
61
61
  raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
62
62
  else
63
63
  begin
64
- DatabaseHelper::SQLQueryResult.new(inspec_cmd, parse_csv_result(inspec_cmd.stdout))
65
- rescue
66
- raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
64
+ unless inspec_cmd.stdout.empty?
65
+ DatabaseHelper::SQLQueryResult.new(inspec_cmd, parse_csv_result(inspec_cmd.stdout))
66
+ else
67
+ inspec_cmd.stdout
68
+ end
69
+ rescue Exception => ex
70
+ raise Inspec::Exceptions::ResourceFailed, "Oracle query with exception: #{ex}"
67
71
  end
68
72
  end
69
73
  end
@@ -55,8 +55,10 @@ module Inspec::Resources
55
55
  psql_cmd = create_psql_cmd(query, db)
56
56
  cmd = inspec.command(psql_cmd, redact_regex: %r{(:\/\/[a-z]*:).*(@)})
57
57
  out = cmd.stdout + "\n" + cmd.stderr
58
- if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/
59
- raise Inspec::Exceptions::ResourceFailed, "PostgreSQL query with errors: #{out}"
58
+ if cmd.exit_status != 0 && ( out =~ /could not connect to/ || out =~ /password authentication failed/ ) && out.downcase =~ /error:/
59
+ raise Inspec::Exceptions::ResourceFailed, "PostgreSQL connection error: #{out}"
60
+ elsif cmd.exit_status != 0 && out.downcase =~ /error:/
61
+ Lines.new(out, "PostgreSQL query with error: #{query}")
60
62
  else
61
63
  Lines.new(cmd.stdout.strip, "PostgreSQL query: #{query}")
62
64
  end
@@ -190,7 +190,7 @@ module Inspec::Resources
190
190
  true
191
191
  end
192
192
 
193
- # Detect LXC/Docker
193
+ # Detect LXC/Docker/k8s/podman
194
194
  #
195
195
  # /proc/self/cgroup will look like this inside a docker container:
196
196
  # <index #>:<subsystem>:/lxc/<hexadecimal container id>
@@ -208,7 +208,7 @@ module Inspec::Resources
208
208
  #
209
209
  # Full notes, https://tickets.opscode.com/browse/OHAI-551
210
210
  # Kernel docs, https://www.kernel.org/doc/Documentation/cgroups
211
- def detect_lxc_docker
211
+ def detect_container
212
212
  return false unless inspec.file("/proc/self/cgroup").exist?
213
213
 
214
214
  cgroup_content = inspec.file("/proc/self/cgroup").content
@@ -216,6 +216,12 @@ module Inspec::Resources
216
216
  cgroup_content =~ %r{^\d+:[^:]+:/[^/]+/(lxc|docker)-.+$} # rubocop:disable Layout/MultilineOperationIndentation
217
217
  @virtualization_data[:system] = $1 # rubocop:disable Style/PerlBackrefs
218
218
  @virtualization_data[:role] = "guest"
219
+ elsif cgroup_content =~ %r{^\d+:[^:]+:/(kubepods)/.+$}
220
+ @virtualization_data[:system] = $1
221
+ @virtualization_data[:role] = "guest"
222
+ elsif /container=podman/.match?(file_read("/proc/1/environ"))
223
+ @virtualization_data[:system] = "podman"
224
+ @virtualization_data[:role] = "guest"
219
225
  elsif lxc_version_exists? && cgroup_content =~ %r{\d:[^:]+:/$}
220
226
  # lxc-version shouldn't be installed by default
221
227
  # Even so, it is likely we are on an LXC capable host that is not being used as such
@@ -297,7 +303,7 @@ module Inspec::Resources
297
303
  return if detect_docker
298
304
  return if detect_virtualbox
299
305
  return if detect_lxd
300
- return if detect_lxc_docker
306
+ return if detect_container
301
307
  return if detect_linux_vserver
302
308
  return if detect_kvm_from_cpuinfo
303
309
  return if detect_kvm_from_sys
@@ -8,21 +8,6 @@
8
8
  # glob so this remains a sort of manifest for our resources.
9
9
 
10
10
  require "inspec/resource"
11
-
12
- # Detect if we are running the stripped-down inspec-core
13
- # This relies on AWS being stripped from the inspec-core gem
14
- inspec_core_only = ENV["NO_AWS"] || !File.exist?(File.join(File.dirname(__FILE__), "..", "resource_support", "aws.rb"))
15
-
16
- # Do not attempt to load cloud resources if we are in inspec-core mode
17
- unless inspec_core_only
18
- require "resource_support/aws"
19
- require "resources/azure/azure_backend"
20
- require "resources/azure/azure_generic_resource"
21
- require "resources/azure/azure_resource_group"
22
- require "resources/azure/azure_virtual_machine"
23
- require "resources/azure/azure_virtual_machine_data_disk"
24
- end
25
-
26
11
  require "inspec/resources/aide_conf"
27
12
  require "inspec/resources/apache"
28
13
  require "inspec/resources/apache_conf"
@@ -41,6 +26,7 @@ require "inspec/resources/cassandradb_session"
41
26
  require "inspec/resources/cassandradb_conf"
42
27
  require "inspec/resources/cassandra"
43
28
  require "inspec/resources/crontab"
29
+ require "inspec/resources/cron"
44
30
  require "inspec/resources/timezone"
45
31
  require "inspec/resources/dh_params"
46
32
  require "inspec/resources/directory"
@@ -138,7 +124,8 @@ require "inspec/resources/xinetd_conf"
138
124
  require "inspec/resources/yum"
139
125
  require "inspec/resources/zfs_dataset"
140
126
  require "inspec/resources/zfs_pool"
141
-
127
+ require "inspec/resources/ipnat"
128
+ require "inspec/resources/ipfilter"
142
129
  # file formats, depend on json implementation
143
130
  require "inspec/resources/json"
144
131
  require "inspec/resources/yaml"