inspec-core 4.56.58 → 5.7.9
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/Gemfile +24 -9
- data/etc/deprecations.json +12 -11
- data/inspec-core.gemspec +3 -5
- data/lib/inspec/base_cli.rb +14 -2
- data/lib/inspec/cli.rb +16 -7
- data/lib/inspec/dependencies/dependency_set.rb +2 -6
- data/lib/inspec/dependency_installer.rb +74 -0
- data/lib/inspec/dependency_loader.rb +97 -0
- data/lib/inspec/dsl.rb +16 -23
- data/lib/inspec/env_printer.rb +1 -1
- data/lib/inspec/errors.rb +7 -0
- data/lib/inspec/fetcher/git.rb +28 -43
- data/lib/inspec/fetcher/url.rb +1 -1
- data/lib/inspec/formatters/base.rb +22 -0
- data/lib/inspec/metadata.rb +36 -0
- data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
- data/lib/inspec/profile.rb +81 -29
- data/lib/inspec/reporters/automate.rb +1 -1
- data/lib/inspec/reporters/cli.rb +1 -1
- data/lib/inspec/reporters/json.rb +31 -11
- data/lib/inspec/resource.rb +6 -0
- data/lib/inspec/resources/cassandradb_session.rb +3 -4
- data/lib/inspec/resources/cron.rb +49 -0
- data/lib/inspec/resources/file.rb +1 -1
- data/lib/inspec/resources/ibmdb2_session.rb +3 -4
- data/lib/inspec/resources/ipfilter.rb +59 -0
- data/lib/inspec/resources/ipnat.rb +58 -0
- data/lib/inspec/resources/mongodb_session.rb +1 -7
- data/lib/inspec/resources/oracledb_session.rb +7 -20
- data/lib/inspec/resources/postgres_session.rb +5 -7
- data/lib/inspec/resources/processes.rb +4 -6
- data/lib/inspec/resources/service.rb +2 -4
- data/lib/inspec/resources.rb +3 -16
- data/lib/inspec/rule.rb +1 -1
- data/lib/inspec/runner.rb +18 -1
- data/lib/inspec/runner_rspec.rb +15 -0
- data/lib/inspec/schema/exec_json.rb +59 -58
- data/lib/inspec/schema/exec_json_min.rb +16 -16
- data/lib/inspec/schema/primitives.rb +68 -51
- data/lib/inspec/schema/profile_json.rb +27 -27
- data/lib/inspec/schema.rb +1 -0
- data/lib/inspec/secrets/yaml.rb +1 -7
- data/lib/inspec/ui.rb +1 -0
- data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec.rb +3 -0
- data/lib/matchers/matchers.rb +1 -7
- data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
- data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
- data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
- data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
- data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
- data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
- data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
- data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
- data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
- data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +6 -4
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +4 -1
- data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +2 -1
- data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
- data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
- metadata +24 -7
@@ -1,11 +1,10 @@
|
|
1
1
|
module Inspec::Resources
|
2
2
|
class Lines
|
3
|
-
attr_reader :output
|
3
|
+
attr_reader :output
|
4
4
|
|
5
|
-
def initialize(raw, desc
|
5
|
+
def initialize(raw, desc)
|
6
6
|
@output = raw
|
7
7
|
@desc = desc
|
8
|
-
@exit_status = exit_status
|
9
8
|
end
|
10
9
|
|
11
10
|
def to_s
|
@@ -59,7 +58,7 @@ module Inspec::Resources
|
|
59
58
|
if cmd.exit_status != 0 || out =~ /Can't connect to IBM Db2 / || out.downcase =~ /^error:.*/
|
60
59
|
raise Inspec::Exceptions::ResourceFailed, "IBM Db2 connection error: #{out}"
|
61
60
|
else
|
62
|
-
Lines.new(cmd.stdout.strip, "IBM Db2 Query: #{q}"
|
61
|
+
Lines.new(cmd.stdout.strip, "IBM Db2 Query: #{q}")
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
@@ -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
|
@@ -4,10 +4,9 @@ module Inspec::Resources
|
|
4
4
|
class Lines
|
5
5
|
attr_reader :params
|
6
6
|
|
7
|
-
def initialize(raw, desc
|
7
|
+
def initialize(raw, desc)
|
8
8
|
@params = raw
|
9
9
|
@desc = desc
|
10
|
-
@exit_status = exit_status
|
11
10
|
end
|
12
11
|
|
13
12
|
def to_s
|
@@ -80,11 +79,6 @@ module Inspec::Resources
|
|
80
79
|
options[:ssl_cert] = @ssl_cert unless @ssl_cert.nil?
|
81
80
|
options[:ssl_ca_cert] = @ssl_ca_cert unless @ssl_ca_cert.nil?
|
82
81
|
|
83
|
-
# 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
|
84
|
-
# 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
|
85
|
-
# 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.
|
86
|
-
# Once we get the latest version working we can remove logger level set here.
|
87
|
-
Mongo::Logger.logger.level = Logger::INFO
|
88
82
|
@client = Mongo::Client.new([ "#{host}:#{port}" ], options)
|
89
83
|
|
90
84
|
rescue => e
|
@@ -61,13 +61,9 @@ module Inspec::Resources
|
|
61
61
|
raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
|
62
62
|
else
|
63
63
|
begin
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
inspec_cmd.stdout
|
68
|
-
end
|
69
|
-
rescue Exception => ex
|
70
|
-
raise Inspec::Exceptions::ResourceFailed, "Oracle query with exception: #{ex}"
|
64
|
+
DatabaseHelper::SQLQueryResult.new(inspec_cmd, parse_csv_result(inspec_cmd.stdout))
|
65
|
+
rescue
|
66
|
+
raise Inspec::Exceptions::ResourceFailed, "Oracle query with errors: #{out}"
|
71
67
|
end
|
72
68
|
end
|
73
69
|
end
|
@@ -91,31 +87,22 @@ module Inspec::Resources
|
|
91
87
|
verified_query = verify_query(escaped_query)
|
92
88
|
end
|
93
89
|
|
94
|
-
sql_prefix, sql_postfix
|
90
|
+
sql_prefix, sql_postfix = "", ""
|
95
91
|
if inspec.os.windows?
|
96
92
|
sql_prefix = %{@'\n#{format_options}\n#{verified_query}\nEXIT\n'@ | }
|
97
93
|
else
|
98
94
|
sql_postfix = %{ <<'EOC'\n#{format_options}\n#{verified_query}\nEXIT\nEOC}
|
99
|
-
# oracle_query_string is echoed to be able to extract the query output clearly
|
100
|
-
oracle_echo_str = %{echo 'oracle_query_string';}
|
101
|
-
end
|
102
|
-
|
103
|
-
# Resetting sql_postfix if system is using AIX OS and C shell installation for oracle
|
104
|
-
if inspec.os.aix?
|
105
|
-
command_to_fetch_shell = @su_user ? %{su - #{@su_user} -c "env | grep SHELL"} : %{env | grep SHELL}
|
106
|
-
shell_is_csh = inspec.command(command_to_fetch_shell).stdout&.include? "/csh"
|
107
|
-
sql_postfix = %{ <<'EOC'\n#{format_options}\n#{verified_query}\nEXIT\n'EOC'} if shell_is_csh
|
108
95
|
end
|
109
96
|
|
110
97
|
if @db_role.nil?
|
111
|
-
%{#{
|
98
|
+
%{#{sql_prefix}#{bin} #{user}/#{password}@#{host}:#{port}/#{@service}#{sql_postfix}}
|
112
99
|
elsif @su_user.nil?
|
113
|
-
%{#{
|
100
|
+
%{#{sql_prefix}#{bin} #{user}/#{password}@#{host}:#{port}/#{@service} as #{@db_role}#{sql_postfix}}
|
114
101
|
else
|
115
102
|
# oracle_query_string is echoed to be able to extract the query output clearly
|
116
103
|
# su - su_user in certain versions of oracle returns a message
|
117
104
|
# Example of msg with query output: The Oracle base remains unchanged with value /oracle\n\nVALUE\n3\n
|
118
|
-
%{su - #{@su_user} -c "
|
105
|
+
%{su - #{@su_user} -c "echo 'oracle_query_string'; env ORACLE_SID=#{@service} #{@bin} / as #{@db_role}#{sql_postfix}"}
|
119
106
|
end
|
120
107
|
end
|
121
108
|
|
@@ -4,9 +4,9 @@ require "shellwords" unless defined?(Shellwords)
|
|
4
4
|
|
5
5
|
module Inspec::Resources
|
6
6
|
class Lines
|
7
|
-
attr_reader :output
|
7
|
+
attr_reader :output
|
8
8
|
|
9
|
-
def initialize(raw, desc
|
9
|
+
def initialize(raw, desc)
|
10
10
|
@output = raw
|
11
11
|
@desc = desc
|
12
12
|
end
|
@@ -55,12 +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
|
60
|
-
elsif cmd.exit_status != 0 && out.downcase =~ /error:/
|
61
|
-
Lines.new(out, "PostgreSQL query with error: #{query}", cmd.exit_status)
|
58
|
+
if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/
|
59
|
+
raise Inspec::Exceptions::ResourceFailed, "PostgreSQL query with errors: #{out}"
|
62
60
|
else
|
63
|
-
Lines.new(cmd.stdout.strip, "PostgreSQL query: #{query}"
|
61
|
+
Lines.new(cmd.stdout.strip, "PostgreSQL query: #{query}")
|
64
62
|
end
|
65
63
|
end
|
66
64
|
|
@@ -43,7 +43,7 @@ module Inspec::Resources
|
|
43
43
|
|
44
44
|
all_cmds = ps_axo
|
45
45
|
@list = all_cmds.find_all do |hm|
|
46
|
-
hm[:command] =~ grep
|
46
|
+
hm[:command] =~ grep
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -73,7 +73,6 @@ module Inspec::Resources
|
|
73
73
|
.register_column(:time, field: "time")
|
74
74
|
.register_column(:users, field: "user")
|
75
75
|
.register_column(:commands, field: "command")
|
76
|
-
.register_column(:process_name, field: "process_name")
|
77
76
|
.install_filter_methods_on_resource(self, :filtered_processes)
|
78
77
|
|
79
78
|
private
|
@@ -88,9 +87,9 @@ module Inspec::Resources
|
|
88
87
|
if os.linux?
|
89
88
|
command, regex, field_map = ps_configuration_for_linux
|
90
89
|
elsif os.windows?
|
91
|
-
command = '$Proc = Get-Process -IncludeUserName | Select-Object PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path
|
90
|
+
command = '$Proc = Get-Process -IncludeUserName | Where-Object {$_.Path -ne $null } | Select-Object PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path | ConvertTo-Csv -NoTypeInformation;$Proc.Replace("""","").Replace("`r`n","`n")'
|
92
91
|
# Wanted to use /(?:^|,)([^,]*)/; works on rubular.com not sure why here?
|
93
|
-
regex = /^(
|
92
|
+
regex = /^(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/
|
94
93
|
field_map = {
|
95
94
|
pid: 2,
|
96
95
|
cpu: 3,
|
@@ -103,7 +102,6 @@ module Inspec::Resources
|
|
103
102
|
time: 10,
|
104
103
|
user: 11,
|
105
104
|
command: 12,
|
106
|
-
process_name: 13,
|
107
105
|
}
|
108
106
|
else
|
109
107
|
command = "ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command"
|
@@ -195,7 +193,7 @@ module Inspec::Resources
|
|
195
193
|
|
196
194
|
# build a hash of process data that we'll turn into a struct for FilterTable
|
197
195
|
process_data = {}
|
198
|
-
%i{label pid cpu mem vsz rss tty stat start time user command
|
196
|
+
%i{label pid cpu mem vsz rss tty stat start time user command}.each do |param|
|
199
197
|
# not all operating systems support all fields, so skip the field if we don't have it
|
200
198
|
process_data[param] = line[field_map[param]] if field_map.key?(param)
|
201
199
|
end
|
@@ -182,9 +182,7 @@ module Inspec::Resources
|
|
182
182
|
when "aix"
|
183
183
|
SrcMstr.new(inspec)
|
184
184
|
when "amazon"
|
185
|
-
|
186
|
-
# This way, it is not dependent on the version of Amazon Linux.
|
187
|
-
if inspec.command("initctl").exist? || inspec.command("/sbin/initctl").exist?
|
185
|
+
if os[:release] =~ /^20\d\d/
|
188
186
|
Upstart.new(inspec, service_ctl)
|
189
187
|
else
|
190
188
|
Systemd.new(inspec, service_ctl)
|
@@ -605,7 +603,7 @@ module Inspec::Resources
|
|
605
603
|
return nil if srv.nil? || srv[0].nil?
|
606
604
|
|
607
605
|
# extract values from service
|
608
|
-
parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[
|
606
|
+
parsed_srv = /^(?<pid>[0-9-]+)\t(?<exit>[0-9]+)\t(?<name>\S*)$/.match(srv[0])
|
609
607
|
enabled = !parsed_srv["name"].nil? # it's in the list
|
610
608
|
|
611
609
|
# check if the service is running
|
data/lib/inspec/resources.rb
CHANGED
@@ -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"
|
data/lib/inspec/rule.rb
CHANGED
@@ -358,7 +358,7 @@ module Inspec
|
|
358
358
|
# YAML will automagically give us a Date or a Time.
|
359
359
|
# If transcoding YAML between languages (e.g. Go) the date might have also ended up as a String.
|
360
360
|
# A string that does not represent a valid time results in the date 0000-01-01.
|
361
|
-
if [Date, Time].include?(expiry.class) || (expiry.is_a?(String) && Time.
|
361
|
+
if [Date, Time].include?(expiry.class) || (expiry.is_a?(String) && Time.new(expiry).year != 0)
|
362
362
|
expiry = expiry.to_time if expiry.is_a? Date
|
363
363
|
expiry = Time.parse(expiry) if expiry.is_a? String
|
364
364
|
if expiry < Time.now # If the waiver expired, return - no skip applied
|
data/lib/inspec/runner.rb
CHANGED
@@ -105,6 +105,7 @@ module Inspec
|
|
105
105
|
|
106
106
|
write_lockfile(profile) if @create_lockfile
|
107
107
|
profile.locked_dependencies
|
108
|
+
profile.load_gem_dependencies
|
108
109
|
profile_context = profile.load_libraries
|
109
110
|
|
110
111
|
profile_context.dependencies.list.values.each do |requirement|
|
@@ -126,9 +127,25 @@ module Inspec
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
|
130
|
+
controls_count = 0
|
131
|
+
control_checks_count_map = {}
|
132
|
+
|
129
133
|
all_controls.each do |rule|
|
130
|
-
|
134
|
+
unless rule.nil?
|
135
|
+
register_rule(rule)
|
136
|
+
checks = ::Inspec::Rule.prepare_checks(rule)
|
137
|
+
unless checks.empty?
|
138
|
+
# controls with empty tests are avoided
|
139
|
+
# checks represent tests within control
|
140
|
+
controls_count += 1
|
141
|
+
control_checks_count_map[rule.to_s] = checks.count
|
142
|
+
end
|
143
|
+
end
|
131
144
|
end
|
145
|
+
|
146
|
+
# this sets data via runner-rspec into base RSpec formatter object, which gets used up within streaming plugins
|
147
|
+
@test_collector.set_controls_count(controls_count)
|
148
|
+
@test_collector.set_control_checks_count_map(control_checks_count_map)
|
132
149
|
end
|
133
150
|
|
134
151
|
def run(with = nil)
|
data/lib/inspec/runner_rspec.rb
CHANGED
@@ -42,6 +42,21 @@ module Inspec
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
# These control count related methods are called from load logic of runner library of inspec
|
46
|
+
######### Start of control count related methods
|
47
|
+
def set_controls_count(controls_count)
|
48
|
+
formatters.each do |fmt|
|
49
|
+
fmt.set_controls_count(controls_count)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_control_checks_count_map(mapping)
|
54
|
+
formatters.each do |fmt|
|
55
|
+
fmt.set_control_checks_count_map(mapping)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
######### end of control count related methods
|
59
|
+
|
45
60
|
def backend
|
46
61
|
formatters.first.backend
|
47
62
|
end
|
@@ -11,16 +11,16 @@ module Inspec
|
|
11
11
|
"additionalProperties" => true,
|
12
12
|
"required" => %w{label data},
|
13
13
|
"properties" => {
|
14
|
-
"label" => Primitives::STRING,
|
15
|
-
"data" => Primitives::STRING,
|
14
|
+
"label" => Primitives.desc(Primitives::STRING, "The type of description. Examples: 'fix' or 'check'."),
|
15
|
+
"data" => Primitives.desc(Primitives::STRING, "The text of the description."),
|
16
16
|
},
|
17
|
-
}, [])
|
17
|
+
}, [], "A description for a control.")
|
18
18
|
|
19
19
|
# Lists the potential values for a control result
|
20
20
|
CONTROL_RESULT_STATUS = Primitives::SchemaType.new("Control Result Status", {
|
21
21
|
"type" => "string",
|
22
22
|
"enum" => %w{passed failed skipped error},
|
23
|
-
}, [])
|
23
|
+
}, [], "The status of a control. Should be one of 'passed', 'failed', 'skipped', or 'error'.")
|
24
24
|
|
25
25
|
# Represents the statistics/result of a control"s execution
|
26
26
|
CONTROL_RESULT = Primitives::SchemaType.new("Control Result", {
|
@@ -28,24 +28,26 @@ module Inspec
|
|
28
28
|
"additionalProperties" => true,
|
29
29
|
"required" => %w{code_desc run_time start_time},
|
30
30
|
"properties" => {
|
31
|
-
"status" => CONTROL_RESULT_STATUS.ref,
|
32
|
-
"code_desc" => Primitives::STRING,
|
33
|
-
"run_time" => Primitives::NUMBER,
|
34
|
-
"start_time" => Primitives::STRING,
|
31
|
+
"status" => Primitives.desc(CONTROL_RESULT_STATUS.ref, "The status of this test within the control. Example: 'failed'."),
|
32
|
+
"code_desc" => Primitives.desc(Primitives::STRING, "A description of this test. Example: 'limits.conf * is expected to include ['hard', 'maxlogins', '10']."),
|
33
|
+
"run_time" => Primitives.desc(Primitives::NUMBER, "The execution time in seconds for the test."),
|
34
|
+
"start_time" => Primitives.desc(Primitives::STRING, "The time at which the test started."),
|
35
35
|
|
36
36
|
# All optional
|
37
|
-
"resource" => Primitives::STRING,
|
38
|
-
"message" => Primitives::STRING,
|
39
|
-
"skip_message" => Primitives::STRING,
|
40
|
-
"exception" => Primitives::STRING,
|
37
|
+
"resource" => Primitives.desc(Primitives::STRING, "The resource used in the test. Example: in Inspec, you can use the 'File' resource."),
|
38
|
+
"message" => Primitives.desc(Primitives::STRING, "An explanation of the test status - usually only provided when the test fails."),
|
39
|
+
"skip_message" => Primitives.desc(Primitives::STRING, "An explanation of the test status if the status was 'skipped."),
|
40
|
+
"exception" => Primitives.desc(Primitives::STRING, "The type of exception if an exception was thrown."),
|
41
|
+
"resource_id" => Primitives.desc(Primitives::STRING, "The unique identifier of the resource."),
|
41
42
|
"backtrace" => {
|
42
43
|
"anyOf" => [
|
43
44
|
Primitives.array(Primitives::STRING),
|
44
45
|
Primitives::NULL,
|
45
46
|
],
|
47
|
+
"description" => "The stacktrace/backtrace of the exception if one occurred.",
|
46
48
|
},
|
47
49
|
},
|
48
|
-
}, [CONTROL_RESULT_STATUS])
|
50
|
+
}, [CONTROL_RESULT_STATUS], "A test within a control and its results and findings such as how long it took to run.")
|
49
51
|
|
50
52
|
# Represents a control produced
|
51
53
|
CONTROL = Primitives::SchemaType.new("Exec JSON Control", {
|
@@ -53,26 +55,25 @@ module Inspec
|
|
53
55
|
"additionalProperties" => true,
|
54
56
|
"required" => %w{id title desc impact refs tags code source_location results},
|
55
57
|
"properties" => {
|
56
|
-
"id" => Primitives.desc(Primitives::STRING, "The
|
57
|
-
"title" => { "type" => %w{string null} }, # Nullable string
|
58
|
-
"desc" => { "type" => %w{string null} },
|
59
|
-
"descriptions" => Primitives.array(CONTROL_DESCRIPTION.ref),
|
60
|
-
"impact" => Primitives::IMPACT,
|
61
|
-
"refs" => Primitives.array(Primitives::REFERENCE.ref),
|
62
|
-
"tags" => Primitives::TAGS,
|
63
|
-
"code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code"),
|
64
|
-
"source_location" => Primitives::SOURCE_LOCATION.ref,
|
65
|
-
"results" => Primitives.desc(Primitives.array(CONTROL_RESULT.ref), %q
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
}),
|
58
|
+
"id" => Primitives.desc(Primitives::STRING, "The id."),
|
59
|
+
"title" => Primitives.desc({ "type" => %w{string null} }, "The title - is nullable."), # Nullable string
|
60
|
+
"desc" => Primitives.desc({ "type" => %w{string null} }, "The description for the overarching control."),
|
61
|
+
"descriptions" => Primitives.desc(Primitives.array(CONTROL_DESCRIPTION.ref), "A set of additional descriptions. Example: the 'fix' text."),
|
62
|
+
"impact" => Primitives.desc(Primitives::IMPACT, "The impactfulness or severity."),
|
63
|
+
"refs" => Primitives.desc(Primitives.array(Primitives::REFERENCE.ref), "The set of references to external documents."),
|
64
|
+
"tags" => Primitives.desc(Primitives::TAGS, "A set of tags - usually metadata."),
|
65
|
+
"code" => Primitives.desc(Primitives::STRING, "The raw source code of the control. Note that if this is an overlay control, it does not include the underlying source code."),
|
66
|
+
"source_location" => Primitives.desc(Primitives::SOURCE_LOCATION.ref, "The explicit location of the control within the source code."),
|
67
|
+
"results" => Primitives.desc(Primitives.array(CONTROL_RESULT.ref), %q(
|
68
|
+
The set of all tests within the control and their results and findings. Example:
|
69
|
+
For Chef Inspec, if in the control's code we had the following:
|
70
|
+
describe sshd_config do
|
71
|
+
its('Port') { should cmp 22 }
|
72
|
+
end
|
73
|
+
The findings from this block would be appended to the results, as well as those of any other blocks within the control.
|
74
|
+
)),
|
74
75
|
},
|
75
|
-
}, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT])
|
76
|
+
}, [CONTROL_DESCRIPTION, Primitives::REFERENCE, Primitives::SOURCE_LOCATION, CONTROL_RESULT], "Describes a control and any findings it has.")
|
76
77
|
|
77
78
|
# Based loosely on https://docs.chef.io/inspec/profiles/ as of July 3, 2019
|
78
79
|
# However, concessions were made to the reality of current reporters, specifically
|
@@ -86,30 +87,30 @@ module Inspec
|
|
86
87
|
# sha256, status, status_message
|
87
88
|
"properties" => {
|
88
89
|
# These are provided in inspec.yml
|
89
|
-
"name" => Primitives::STRING,
|
90
|
-
"title" => Primitives::STRING,
|
91
|
-
"maintainer" => Primitives::STRING,
|
92
|
-
"copyright" => Primitives::STRING,
|
93
|
-
"copyright_email" => Primitives::STRING,
|
94
|
-
"depends" => Primitives.array(Primitives::DEPENDENCY.ref),
|
95
|
-
"parent_profile" => Primitives::STRING,
|
96
|
-
"license" => Primitives::STRING,
|
97
|
-
"summary" => Primitives::STRING,
|
98
|
-
"version" => Primitives::STRING,
|
99
|
-
"supports" => Primitives.array(Primitives::SUPPORT.ref),
|
100
|
-
"description" => Primitives::STRING,
|
101
|
-
"inspec_version" => Primitives::STRING,
|
90
|
+
"name" => Primitives.desc(Primitives::STRING, "The name - must be unique."),
|
91
|
+
"title" => Primitives.desc(Primitives::STRING, "The title - should be human readable."),
|
92
|
+
"maintainer" => Primitives.desc(Primitives::STRING, "The maintainer(s)."),
|
93
|
+
"copyright" => Primitives.desc(Primitives::STRING, "The copyright holder(s)."),
|
94
|
+
"copyright_email" => Primitives.desc(Primitives::STRING, "The email address or other contact information of the copyright holder(s)."),
|
95
|
+
"depends" => Primitives.desc(Primitives.array(Primitives::DEPENDENCY.ref), "The set of dependencies this profile depends on. Example: an overlay profile is dependent on another profile."),
|
96
|
+
"parent_profile" => Primitives.desc(Primitives::STRING, "The name of the parent profile if the profile is a dependency of another."),
|
97
|
+
"license" => Primitives.desc(Primitives::STRING, "The copyright license. Example: the full text or the name, such as 'Apache License, Version 2.0'."),
|
98
|
+
"summary" => Primitives.desc(Primitives::STRING, "The summary. Example: the Security Technical Implementation Guide (STIG) header."),
|
99
|
+
"version" => Primitives.desc(Primitives::STRING, "The version of the profile."),
|
100
|
+
"supports" => Primitives.desc(Primitives.array(Primitives::SUPPORT.ref), "The set of supported platform targets."),
|
101
|
+
"description" => Primitives.desc(Primitives::STRING, "The description - should be more detailed than the summary."),
|
102
|
+
"inspec_version" => Primitives.desc(Primitives::STRING, "The version of Inspec."),
|
102
103
|
|
103
104
|
# These are generated at runtime, and all except status_message and skip_message are guaranteed
|
104
|
-
"sha256" => Primitives::STRING,
|
105
|
-
"status" => Primitives::STRING,
|
106
|
-
"status_message" => Primitives::STRING,
|
107
|
-
"skip_message" => Primitives::STRING,
|
108
|
-
"controls" => Primitives.array(CONTROL.ref),
|
109
|
-
"groups" => Primitives.array(Primitives::CONTROL_GROUP.ref),
|
110
|
-
"attributes" => Primitives.array(Primitives::INPUT),
|
105
|
+
"sha256" => Primitives.desc(Primitives::STRING, "The checksum of the profile."),
|
106
|
+
"status" => Primitives.desc(Primitives::STRING, "The status. Example: loaded."), # enum? loaded, failed, skipped
|
107
|
+
"status_message" => Primitives.desc(Primitives::STRING, "The reason for the status. Example: why it was skipped or failed to load."),
|
108
|
+
"skip_message" => Primitives.desc(Primitives::STRING, "The reason for skipping if it was skipped."), # Deprecated field - status_message should be used instead.
|
109
|
+
"controls" => Primitives.desc(Primitives.array(CONTROL.ref), "The set of controls including any findings."),
|
110
|
+
"groups" => Primitives.desc(Primitives.array(Primitives::CONTROL_GROUP.ref), "A set of descriptions for the control groups. Example: the ids of the controls."),
|
111
|
+
"attributes" => Primitives.desc(Primitives.array(Primitives::INPUT), "The input(s) or attribute(s) used in the run."),
|
111
112
|
},
|
112
|
-
}, [CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::SUPPORT])
|
113
|
+
}, [CONTROL, Primitives::CONTROL_GROUP, Primitives::DEPENDENCY, Primitives::SUPPORT], "Information on the set of controls assessed. Example: it can include the name of the Inspec profile and any findings.")
|
113
114
|
|
114
115
|
# Result of exec json. Top level value
|
115
116
|
# TODO: Include the format of top level controls. This was omitted for lack of sufficient examples
|
@@ -118,12 +119,12 @@ module Inspec
|
|
118
119
|
"additionalProperties" => true,
|
119
120
|
"required" => %w{platform profiles statistics version},
|
120
121
|
"properties" => {
|
121
|
-
"platform" => Primitives::PLATFORM.ref,
|
122
|
-
"profiles" => Primitives.array(PROFILE.ref),
|
123
|
-
"statistics" => Primitives::STATISTICS.ref,
|
124
|
-
"version" => Primitives::STRING,
|
122
|
+
"platform" => Primitives.desc(Primitives::PLATFORM.ref, "Information on the platform the run from the tool that generated the findings was from. Example: the name of the operating system."),
|
123
|
+
"profiles" => Primitives.desc(Primitives.array(PROFILE.ref), "Information on the run(s) from the tool that generated the findings. Example: the findings."),
|
124
|
+
"statistics" => Primitives.desc(Primitives::STATISTICS.ref, "Statistics for the run(s) from the tool that generated the findings. Example: the runtime duration."),
|
125
|
+
"version" => Primitives.desc(Primitives::STRING, "Version number of the tool that generated the findings. Example: '4.18.108' is a version of Chef InSpec."),
|
125
126
|
},
|
126
|
-
}, [Primitives::PLATFORM, PROFILE, Primitives::STATISTICS])
|
127
|
+
}, [Primitives::PLATFORM, PROFILE, Primitives::STATISTICS], "The top level value containing all of the results.")
|
127
128
|
end
|
128
129
|
end
|
129
130
|
end
|