inspec-core 4.56.58 → 5.7.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|