inspec-core 5.7.9 → 5.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/etc/deprecations.json +0 -5
- data/lib/inspec/cli.rb +2 -0
- data/lib/inspec/plugin/v2/installer.rb +9 -2
- data/lib/inspec/plugin/v2/loader.rb +13 -0
- data/lib/inspec/plugin/v2/status.rb +2 -1
- data/lib/inspec/profile.rb +7 -5
- data/lib/inspec/resources/apt.rb +12 -6
- data/lib/inspec/resources/cgroup.rb +101 -0
- data/lib/inspec/resources/default_gateway.rb +61 -0
- data/lib/inspec/resources/docker_container.rb +21 -0
- data/lib/inspec/resources/docker_image.rb +53 -0
- data/lib/inspec/resources/file.rb +91 -0
- data/lib/inspec/resources/groups.rb +5 -0
- data/lib/inspec/resources/linux_audit_system.rb +81 -0
- data/lib/inspec/resources/lxc.rb +57 -0
- data/lib/inspec/resources/mail_alias.rb +46 -0
- data/lib/inspec/resources/oracledb_session.rb +7 -3
- data/lib/inspec/resources/postgres_session.rb +4 -2
- data/lib/inspec/resources/routing_table.rb +137 -0
- data/lib/inspec/resources/service.rb +87 -1
- data/lib/inspec/resources/user.rb +12 -0
- data/lib/inspec/resources/users.rb +79 -14
- data/lib/inspec/resources/virtualization.rb +9 -3
- data/lib/inspec/ui.rb +9 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/plugins/inspec-artifact/inspec-artifact.gemspec +9 -0
- data/lib/plugins/inspec-compliance/inspec-compliance.gemspec +9 -0
- data/lib/plugins/inspec-habitat/inspec-habitat.gemspec +9 -0
- data/lib/plugins/inspec-init/inspec-init.gemspec +9 -0
- data/lib/plugins/inspec-plugin-manager-cli/inspec-plugin-manager-cli.gemspec +10 -0
- data/lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb +15 -11
- data/lib/plugins/inspec-reporter-html2/inspec-reporter-html2.gemspec +9 -0
- data/lib/plugins/inspec-reporter-json-min/inspec-reporter-json-min.gemspec +9 -0
- data/lib/plugins/inspec-reporter-junit/inspec-reporter-junit.gemspec +9 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/inspec-streaming-reporter-progress-bar.gemspec +9 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +32 -21
- 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
|
-
|
65
|
-
|
66
|
-
|
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
|
59
|
-
raise Inspec::Exceptions::ResourceFailed, "PostgreSQL
|
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
|
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
|
-
|
289
|
-
|
290
|
-
|
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
|
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
|
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] : "*"
|
data/lib/inspec/version.rb
CHANGED
@@ -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
|