inspec-core 5.7.9 → 5.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/etc/deprecations.json +0 -5
  3. data/lib/inspec/cli.rb +2 -0
  4. data/lib/inspec/plugin/v2/installer.rb +9 -2
  5. data/lib/inspec/plugin/v2/loader.rb +13 -0
  6. data/lib/inspec/plugin/v2/status.rb +2 -1
  7. data/lib/inspec/profile.rb +7 -5
  8. data/lib/inspec/resources/apt.rb +12 -6
  9. data/lib/inspec/resources/cgroup.rb +101 -0
  10. data/lib/inspec/resources/default_gateway.rb +61 -0
  11. data/lib/inspec/resources/docker_container.rb +21 -0
  12. data/lib/inspec/resources/docker_image.rb +53 -0
  13. data/lib/inspec/resources/file.rb +91 -0
  14. data/lib/inspec/resources/groups.rb +5 -0
  15. data/lib/inspec/resources/linux_audit_system.rb +81 -0
  16. data/lib/inspec/resources/lxc.rb +57 -0
  17. data/lib/inspec/resources/mail_alias.rb +46 -0
  18. data/lib/inspec/resources/oracledb_session.rb +7 -3
  19. data/lib/inspec/resources/postgres_session.rb +4 -2
  20. data/lib/inspec/resources/routing_table.rb +137 -0
  21. data/lib/inspec/resources/service.rb +87 -1
  22. data/lib/inspec/resources/user.rb +12 -0
  23. data/lib/inspec/resources/users.rb +79 -14
  24. data/lib/inspec/resources/virtualization.rb +9 -3
  25. data/lib/inspec/ui.rb +9 -0
  26. data/lib/inspec/version.rb +1 -1
  27. data/lib/plugins/inspec-artifact/inspec-artifact.gemspec +9 -0
  28. data/lib/plugins/inspec-compliance/inspec-compliance.gemspec +9 -0
  29. data/lib/plugins/inspec-habitat/inspec-habitat.gemspec +9 -0
  30. data/lib/plugins/inspec-init/inspec-init.gemspec +9 -0
  31. data/lib/plugins/inspec-plugin-manager-cli/inspec-plugin-manager-cli.gemspec +10 -0
  32. data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +15 -11
  33. data/lib/plugins/inspec-reporter-html2/inspec-reporter-html2.gemspec +9 -0
  34. data/lib/plugins/inspec-reporter-json-min/inspec-reporter-json-min.gemspec +9 -0
  35. data/lib/plugins/inspec-reporter-junit/inspec-reporter-junit.gemspec +9 -0
  36. data/lib/plugins/inspec-streaming-reporter-progress-bar/inspec-streaming-reporter-progress-bar.gemspec +9 -0
  37. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +32 -21
  38. metadata +17 -2
@@ -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
@@ -0,0 +1,46 @@
1
+ require "inspec/resources/command"
2
+ module Inspec::Resources
3
+ class Mailalias < Inspec.resource(1)
4
+ # resource internal name.
5
+ name "mail_alias"
6
+
7
+ # Restrict to only run on the below platforms (if none were given,
8
+ # all OS's and cloud API's supported)
9
+ supports platform: "unix"
10
+
11
+ desc "Use the mail_alias InSpec audit resource to test mail alias present in the aliases file"
12
+
13
+ example <<~EXAMPLE
14
+ describe mail_alias("toor") do
15
+ it { should be_aliased_to "root" }
16
+ end
17
+ EXAMPLE
18
+
19
+ def initialize(alias_key)
20
+ skip_resource "The `mail_alias` resource is not yet available on your OS." unless inspec.os.unix?
21
+ @alias_key = alias_key
22
+ end
23
+
24
+ # resource_id is used in reporting engines to uniquely identify the individual resource.
25
+ def resource_id
26
+ "#{@alias_key}"
27
+ end
28
+
29
+ # resource appearance in test reports.
30
+ def to_s
31
+ "mail_alias #{resource_id}"
32
+ end
33
+
34
+ # aliased_to matcher checks if the given alias_value is set to the initialized alias_key
35
+ def aliased_to?(alias_value)
36
+ # /etc/aliases if the file where the alias and its value(s) are stored
37
+ cmd = inspec.command("cat /etc/aliases | grep '^#{@alias_key}:'")
38
+ raise Inspec::Exceptions::ResourceFailed, "#{@alias_key} is not a valid key in the aliases" if cmd.exit_status.to_i != 0
39
+
40
+ # in general aliases file contains : separated values like alias_key : alias_value1, alias_value2
41
+ alias_values_combined = cmd.stdout.split(":").map(&:strip)[1]
42
+ alias_values_splitted = alias_values_combined.split(",").map(&:strip)
43
+ alias_values_splitted.include?(alias_value)
44
+ end
45
+ end
46
+ 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
@@ -0,0 +1,137 @@
1
+ require "inspec/resources/command"
2
+
3
+ module Inspec::Resources
4
+ class Routingtable < Inspec.resource(1)
5
+ # resource internal name.
6
+ name "routing_table"
7
+
8
+ # Restrict to only run on the below platforms (if none were given,
9
+ # all OS's and cloud API's supported)
10
+ supports platform: "unix"
11
+ supports platform: "windows"
12
+
13
+ desc "Use the `routing_table` Chef InSpec audit resource to test the routing information parameters(destination, gateway and interface) present in the routing table."
14
+
15
+ example <<~EXAMPLE
16
+ describe routing_table do
17
+ it do
18
+ should have_entry(
19
+ :destination => '192.168.43.1/32',
20
+ :interface => 'lxdbr0',
21
+ :gateway => '172.31.80.1',
22
+ )
23
+ end
24
+ end
25
+
26
+ describe routing_table do
27
+ it { should have_entry(destination: '0.0.0.0', interface: 'eth0', gateway: '172.31.80.1') }
28
+ end
29
+ EXAMPLE
30
+
31
+ def initialize
32
+ skip_resource "The `routing_table` resource is not yet available on your OS." unless inspec.os.unix? || inspec.os.windows?
33
+ # fetch the routing information and store it in @routing_info (could be hash, tbd)
34
+ @routing_info = {}
35
+ fetch_routing_information
36
+ end
37
+
38
+ # resource appearance in test reports.
39
+ def to_s
40
+ "routing_table"
41
+ end
42
+
43
+ def has_entry?(input_route)
44
+ # check if the destination, gateway, interface exists as part of the routing_info
45
+ if input_route.key?(:destination) && input_route.key?(:gateway) && input_route.key?(:interface)
46
+ # check if there is key with destination's value in hash;
47
+ # if yes, check if destination and gateway is present else return false
48
+ @routing_info.key?(input_route[:destination]) ? @routing_info[input_route[:destination]].include?([input_route[:gateway], input_route[:interface]]) : false
49
+ else
50
+ raise Inspec::Exceptions::ResourceSkipped, "One or more missing key, have_entry? matcher expects a hash with 3 keys: destination, gateway and interface"
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # fetches the routing information for the system
57
+ def fetch_routing_information
58
+ # check if netstat is available on the system
59
+ utility = find_netstat_or_error
60
+
61
+ # the command to fetch the routing information
62
+ fetch_route_cmd = "#{utility} -rn"
63
+
64
+ # execute the above netstat command
65
+ cmd = inspec.command(fetch_route_cmd)
66
+
67
+ # raise error if the exit status is not zero;
68
+ raise Inspec::Exceptions::ResourceFailed, "Executing netstat failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
69
+
70
+ # Todo:
71
+ # Improve logic to fetch destination, gateway & interface efficiently.
72
+ # The below logic assumes the following:
73
+ # 1. destination, gateway & interface header is present as Destination, Gateway & (Iface or Netif or Interface) respectively.
74
+ # (Netif on BSD, Darwin,Iface on linux & Interface on Windows)
75
+ # 2. there is no blank data for any columns or the blank data are present after the interface column.
76
+
77
+ # cmd.stdout is the standard out of netstat -rn; split on new line to get the rows
78
+ raw_route_info = cmd.stdout.split("\n")
79
+
80
+ # since raw_route_info contains some row before the header (i.e. Destination Gateway ...); remove those rows
81
+ raw_route_info.shift until raw_route_info[0] =~ /Destination/i
82
+
83
+ # split each rows based on space to get the individual columns
84
+ # raw_route_info is now array of arrays with the routing information
85
+ raw_route_info.map! { |info| info.strip.split }
86
+
87
+ # these variables will store the indices where destination, gateway and interface are present
88
+ destination_index, gateway_index, interface_index = -1, -1, -1
89
+
90
+ # The headers in windows are as:
91
+ # Network Destination Netmask Gateway Interface Metric
92
+ # Splitting on space makes "Network Destination" to be two separate values as "Network" & "Destination"
93
+ # Remove "Network" value to apply the logic of finding index
94
+ raw_route_info[0].shift if inspec.os.windows?
95
+
96
+ # find the indices of destination, gateway and interface;
97
+ # because the position of gateway & interface varies with operating system
98
+ raw_route_info[0].each_with_index do |header, index|
99
+ if header =~ /Destination/i
100
+ destination_index = index
101
+ elsif header =~ /Gateway/i
102
+ gateway_index = index
103
+ elsif header =~ /Iface|Netif|Interface/i
104
+ interface_index = index
105
+ end
106
+ end
107
+
108
+ # remove the initial header consisting of Destination, Gateway, Mask, ... since this is of no use
109
+ raw_route_info.shift
110
+
111
+ # check the indices are assigned with some index and not -1
112
+ if destination_index != -1 && gateway_index != -1 && interface_index != -1
113
+ # iterate through the route_info; and find destination, gateway and interface from each row
114
+ raw_route_info.each do |info|
115
+ # if value exists at the destination_index, gateway_index, and interface_index; store the value in @routing_info
116
+ if !info[destination_index].nil? && !info[gateway_index].nil? && !info[interface_index].nil?
117
+ # if the destination_key is already present, append the gateway & interface; else create new array and add them
118
+ if @routing_info.key?(info[destination_index])
119
+ @routing_info[info[destination_index]] << [info[gateway_index], info[interface_index]]
120
+ else
121
+ @routing_info[info[destination_index]] = [[info[gateway_index], info[interface_index]]]
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ # check if netstat is available on the system
129
+ def find_netstat_or_error
130
+ %w{/usr/sbin/netstat /sbin/netstat /usr/bin/netstat /bin/netstat netstat}.each do |cmd|
131
+ return cmd if inspec.command(cmd).exist?
132
+ end
133
+
134
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `netstat` utility to view routing table information"
135
+ end
136
+ end
137
+ end
@@ -271,6 +271,30 @@ module Inspec::Resources
271
271
  info[:startname]
272
272
  end
273
273
 
274
+ # matcher equivalent to startmode property; compares start-up mode
275
+ # supported only on windows.
276
+ def has_start_mode?(mode)
277
+ raise Inspec::Exceptions::ResourceSkipped, "The `has_start_mode` matcher is not supported on your OS yet." unless inspec.os.windows?
278
+
279
+ mode == startmode
280
+ end
281
+
282
+ # matcher to check if the service is monitored by the given monitoring tool/software
283
+ def monitored_by?(monitoring_tool)
284
+ # Currently supported monitoring tools are: monit & god
285
+ # To add support for new monitoring tools, extend the case statement with additional monitoring tool and
286
+ # add the definition and logic in a new class (inheriting the base class MonitoringTool: optional)
287
+ case monitoring_tool
288
+ when "monit"
289
+ current_monitoring_tool = Monit.new(inspec, @service_name)
290
+ when "god"
291
+ current_monitoring_tool = God.new(inspec, @service_name)
292
+ else
293
+ puts "The monitoring tool #{monitoring_tool} is not yet supported by InSpec."
294
+ end
295
+ current_monitoring_tool.is_service_monitored?
296
+ end
297
+
274
298
  def to_s
275
299
  "Service #{@service_name}"
276
300
  end
@@ -537,9 +561,22 @@ module Inspec::Resources
537
561
  end
538
562
 
539
563
  def info(service_name)
564
+ # `service -l` lists all files in /etc/rc.d and the local startup directories
565
+ # % service -l
566
+ # accounting
567
+ # addswap
568
+ # adjkerntz
569
+ # apm
570
+ # archdep
571
+ cmd = inspec.command("#{service_ctl} -l")
572
+ return nil if cmd.exit_status != 0
573
+
574
+ # search for the service
575
+ srv = /^#{service_name}$/.match(cmd.stdout)
576
+ return nil if srv.nil? || srv[0].nil?
577
+
540
578
  # check if service is enabled
541
579
  cmd = inspec.command("#{service_ctl} #{service_name} enabled")
542
-
543
580
  enabled = cmd.exit_status == 0
544
581
 
545
582
  # check if the service is running
@@ -880,4 +917,53 @@ module Inspec::Resources
880
917
  Runit.new(inspec, service_ctl)
881
918
  end
882
919
  end
920
+
921
+ # Helper class for monitored_by matcher
922
+ class MonitoringTool
923
+ attr_reader :inspec, :service_name
924
+ def initialize(inspec, service_name)
925
+ @inspec = inspec
926
+ @service_name ||= service_name
927
+ end
928
+
929
+ def find_utility_or_error(utility_name)
930
+ [ "/usr/sbin/#{utility_name}" , "/sbin/#{utility_name}" , "/usr/bin/#{utility_name}" , "/bin/#{utility_name}" , "#{utility_name}" ].each do |cmd|
931
+ return cmd if inspec.command(cmd).exist?
932
+ end
933
+
934
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `#{utility_name}`"
935
+ end
936
+ end
937
+
938
+ class Monit < MonitoringTool
939
+ def is_service_monitored?
940
+ utility = find_utility_or_error("monit")
941
+ utility_cmd = inspec.command("#{utility} summary")
942
+
943
+ raise Inspec::Exceptions::ResourceFailed, "Executing #{utility} summary failed: #{utility_cmd.stderr}" if utility_cmd.exit_status.to_i != 0
944
+
945
+ monitoring_info = utility_cmd.stdout.split("\n")
946
+ monitoring_info.map! { |info| info.strip.squeeze(" ") }
947
+ is_monitored = false
948
+ monitoring_info.each do |info|
949
+ if info =~ /^#{service_name} OK.*/
950
+ is_monitored = true
951
+ break
952
+ end
953
+ end
954
+ is_monitored
955
+ end
956
+ end
957
+
958
+ class God < MonitoringTool
959
+ def is_service_monitored?
960
+ utility = find_utility_or_error("god")
961
+ utility_cmd = inspec.command("#{utility} status #{service_name}")
962
+
963
+ raise Inspec::Exceptions::ResourceFailed, "Executing #{utility} status #{service_name} failed: #{utility_cmd.stderr}" if utility_cmd.exit_status.to_i != 0
964
+
965
+ monitoring_info = utility_cmd.stdout.strip
966
+ monitoring_info =~ /^#{service_name}: up/
967
+ end
968
+ end
883
969
  end
@@ -1 +1,13 @@
1
1
  require "inspec/resources/users"
2
+ # user resource belong_to matcher for serverspec compatibility
3
+ RSpec::Matchers.define :belong_to_primary_group do |group|
4
+ match do |user|
5
+ user.belongs_to_primary_group?(group)
6
+ end
7
+ end
8
+
9
+ RSpec::Matchers.define :belong_to_group do |group|
10
+ match do |user|
11
+ user.belongs_to_group?(group)
12
+ end
13
+ end
@@ -137,20 +137,17 @@ module Inspec::Resources
137
137
  # its('badpasswordattempts') { should eq 0 }
138
138
  # end
139
139
  #
140
- # The following Serverspec matchers are deprecated in favor for direct value access
140
+ # The following Serverspec matchers were deprecated in favor for direct value access
141
+ # but are made available as part of Serverspec compatibility in March, 2022.
141
142
  #
142
143
  # describe user('root') do
143
144
  # it { should belong_to_group 'root' }
145
+ # it { should belong_to_primary_group 'root' }
144
146
  # it { should have_uid 0 }
145
147
  # it { should have_home_directory '/root' }
146
148
  # it { should have_login_shell '/bin/bash' }
147
149
  # its('minimum_days_between_password_change') { should eq 0 }
148
150
  # its('maximum_days_between_password_change') { should eq 99 }
149
- # end
150
- #
151
- # ServerSpec tests that are not supported:
152
- #
153
- # describe user('root') do
154
151
  # it { should have_authorized_key 'ssh-rsa ADg54...3434 user@example.local' }
155
152
  # its(:encrypted_password) { should eq 1234 }
156
153
  # end
@@ -258,36 +255,56 @@ module Inspec::Resources
258
255
 
259
256
  # implement 'mindays' method to be compatible with serverspec
260
257
  def minimum_days_between_password_change
261
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `minimum_days_between_password_change` property is deprecated. Please use `mindays`.")
262
258
  mindays
263
259
  end
264
260
 
265
261
  # implement 'maxdays' method to be compatible with serverspec
266
262
  def maximum_days_between_password_change
267
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `maximum_days_between_password_change` property is deprecated. Please use `maxdays`.")
268
263
  maxdays
269
264
  end
270
265
 
271
266
  # implements rspec has matcher, to be compatible with serverspec
272
267
  # @see: https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/matchers/built_in/has.rb
268
+ # has_uid matcher: compatibility with serverspec
273
269
  def has_uid?(compare_uid)
274
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `has_uid?` matcher is deprecated.")
275
270
  uid == compare_uid
276
271
  end
277
272
 
273
+ # has_home_directory matcher: compatibility with serverspec
278
274
  def has_home_directory?(compare_home)
279
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `has_home_directory?` matcher is deprecated. Please use `its('home')`.")
280
275
  home == compare_home
281
276
  end
282
277
 
278
+ # has_login_shell matcher: compatibility with serverspec
283
279
  def has_login_shell?(compare_shell)
284
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `has_login_shell?` matcher is deprecated. Please use `its('shell')`.")
285
280
  shell == compare_shell
286
281
  end
287
282
 
288
- def has_authorized_key?(_compare_key)
289
- Inspec.deprecate(:resource_user_serverspec_compat, "The user resource `has_authorized_key?` matcher is deprecated. There is no currently implemented alternative")
290
- raise NotImplementedError
283
+ # has_authorized_key matcher: compatibility with serverspec
284
+ def has_authorized_key?(compare_key)
285
+ # get_authorized_keys returns the list of key, check if given key is included.
286
+ get_authorized_keys.include?(compare_key)
287
+ end
288
+
289
+ # belongs_to_primary_group matcher: compatibility with serverspec
290
+ def belongs_to_primary_group?(group_name)
291
+ groupname == group_name
292
+ end
293
+
294
+ # belongs_to_group matcher: compatibility with serverspec
295
+ def belongs_to_group?(group_name)
296
+ groups.include?(group_name)
297
+ end
298
+
299
+ # encrypted_password property: compatibility with serverspec
300
+ # it allows to run test against the hashed passwords of the given user
301
+ # applicable for unix/linux systems with getent utility.
302
+ def encrypted_password
303
+ raise Inspec::Exceptions::ResourceSkipped, "encrypted_password property is not applicable for your system" if inspec.os.windows? || inspec.os.darwin?
304
+
305
+ # shadow_information returns array of the information from the shadow file
306
+ # the value at 1st index is the encrypted_password information
307
+ shadow_information[1]
291
308
  end
292
309
 
293
310
  def to_s
@@ -314,6 +331,54 @@ module Inspec::Resources
314
331
 
315
332
  @cred_cache = @user_provider.credentials(@username) unless @user_provider.nil?
316
333
  end
334
+
335
+ # helper method for has_authorized_key matcher
336
+ # get_authorized_keys return the key/keys stored in the authorized_keys path
337
+ def get_authorized_keys
338
+ # cat is used in unix system to display content of file; similarly type is used for windows
339
+ bin = inspec.os.windows? ? "type" : "cat"
340
+
341
+ # auth_path gets assigned with the valid path for authorized_keys
342
+ auth_path = ""
343
+
344
+ # possible paths where authorized_keys are stored
345
+ # inspec.command is used over inspec.file because inspec.file requires absolute path
346
+ %w{~/.ssh/authorized_keys ~/.ssh/authorized_keys2}.each do |path|
347
+ if inspec.command("#{bin} #{path}").exit_status == 0
348
+ auth_path = path
349
+ break
350
+ end
351
+ end
352
+
353
+ # if auth_path is empty, no valid path was found, hence raise exception
354
+ raise Inspec::Exceptions::ResourceSkipped, "Can't find any valid path for authorized_keys" if auth_path.empty?
355
+
356
+ # authorized_keys are obtained in the standard output;
357
+ # split keys on newline if more than one keys are part of authorized_keys
358
+ inspec.command("#{bin} #{auth_path}").stdout.split("\n").map(&:strip)
359
+ end
360
+
361
+ # Helper method for encrypted_password property
362
+ def shadow_information
363
+ # check if getent is available on the system
364
+ bin = find_getent_utility
365
+
366
+ # fetch details of the passwd file for the current user using getent
367
+ cmd = inspec.command("#{bin} shadow #{@username}")
368
+ raise Inspec::Exceptions::ResourceFailed, "Executing #{bin} shadow #{@username} failed: #{cmd.stderr}" if cmd.exit_status.to_i != 0
369
+
370
+ # shadow information are : separated values, split and return
371
+ cmd.stdout.split(":").map(&:strip)
372
+ end
373
+
374
+ # check if getent exist in the system
375
+ def find_getent_utility
376
+ %w{/usr/bin/getent /bin/getent getent}.each do |cmd|
377
+ return cmd if inspec.command(cmd).exist?
378
+ end
379
+
380
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `getent` on your system."
381
+ end
317
382
  end
318
383
 
319
384
  # Class defined to compare for groups without case-sensitivity
@@ -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
data/lib/inspec/ui.rb CHANGED
@@ -140,6 +140,15 @@ module Inspec
140
140
  print_or_return(result, opts[:print])
141
141
  end
142
142
 
143
+ def line_with_width(width = 80, opts = { print: true } )
144
+ if color?
145
+ result = ANSI_CODES[:bold] + GLYPHS[:heavy_dash] * width + ANSI_CODES[:reset] + "\n"
146
+ else
147
+ result = "-" * width + "\n"
148
+ end
149
+ print_or_return(result, opts[:print])
150
+ end
151
+
143
152
  # Makes a bullet point.
144
153
  def list_item(str, opts = { print: true })
145
154
  bullet = color? ? ANSI_CODES[:bold] + ANSI_CODES[:color][:white] + GLYPHS[:bullet] + ANSI_CODES[:reset] : "*"
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "5.7.9".freeze
2
+ VERSION = "5.14.0".freeze
3
3
  end
@@ -0,0 +1,9 @@
1
+ # .gemspec file is added to add plugin details
2
+ # These specs are used in plugin list and search command
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "inspec-artifact"
6
+ spec.summary = ""
7
+ spec.description = "Plugin to generate asymmetrical keys that you can use to encrypt profiles"
8
+ spec.license = "Apache-2.0"
9
+ end
@@ -0,0 +1,9 @@
1
+ # .gemspec file is added to add plugin details
2
+ # These specs are used in plugin list and search command
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "inspec-compliance"
6
+ spec.summary = "Plugin to perform operations with Chef Automate"
7
+ spec.description = "This extensions will allow you to interact with Chef Automate"
8
+ spec.license = "Apache-2.0"
9
+ end
@@ -0,0 +1,9 @@
1
+ # .gemspec file is added to add plugin details
2
+ # These specs are used in plugin list and search command
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "inspec-habitat"
6
+ spec.summary = "Plugin to create/upload habitat package"
7
+ spec.description = "This extensions will allow you to create/upload habitat package from an inspec profile."
8
+ spec.license = "Apache-2.0"
9
+ end
@@ -0,0 +1,9 @@
1
+ # .gemspec file is added to add plugin details
2
+ # These specs are used in plugin list and search command
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "inspec-init"
6
+ spec.summary = "Plugin for scaffolding profile, plugin or a resource"
7
+ spec.description = "This extensions helps you to easily create a new profile, plugin or a resource."
8
+ spec.license = "Apache-2.0"
9
+ end
@@ -0,0 +1,10 @@
1
+ # .gemspec file is added to add plugin details
2
+ # These specs are used in plugin list and search command
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "inspec-plugin-manager-cli"
6
+ spec.summary = "CLI plugin for InSpec"
7
+ spec.description = "This is a CLI plugin for InSpec. It uses the Plugins API v2 to create a
8
+ series of commands to manage plugins."
9
+ spec.license = "Apache-2.0"
10
+ end