inspec-core 4.56.17 → 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/etc/deprecations.json +12 -11
- data/inspec-core.gemspec +1 -1
- data/lib/inspec/base_cli.rb +14 -2
- data/lib/inspec/cli.rb +15 -0
- data/lib/inspec/dependency_installer.rb +74 -0
- data/lib/inspec/dependency_loader.rb +97 -0
- data/lib/inspec/dsl.rb +11 -2
- data/lib/inspec/errors.rb +7 -0
- data/lib/inspec/formatters/base.rb +23 -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 +63 -0
- 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/cron.rb +49 -0
- data/lib/inspec/resources/ipfilter.rb +59 -0
- data/lib/inspec/resources/ipnat.rb +58 -0
- data/lib/inspec/resources.rb +3 -16
- 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/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/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 +2 -0
- data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
- data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
- 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 +20 -3
@@ -29,28 +29,48 @@ module Inspec::Reporters
|
|
29
29
|
{
|
30
30
|
name: run_data[:platform][:name],
|
31
31
|
release: run_data[:platform][:release],
|
32
|
-
target_id: run_data[:platform][:target_id] ||
|
32
|
+
target_id: run_data[:platform][:target_id] || "",
|
33
33
|
}.reject { |_k, v| v.nil? }
|
34
34
|
end
|
35
35
|
|
36
36
|
def profile_results(control)
|
37
37
|
(control[:results] || []).map { |r|
|
38
38
|
{
|
39
|
-
status:
|
40
|
-
code_desc:
|
41
|
-
run_time:
|
42
|
-
start_time:
|
43
|
-
resource:
|
44
|
-
skip_message:
|
45
|
-
message:
|
46
|
-
exception:
|
47
|
-
backtrace:
|
48
|
-
resource_class:
|
39
|
+
status: r[:status],
|
40
|
+
code_desc: r[:code_desc],
|
41
|
+
run_time: r[:run_time],
|
42
|
+
start_time: r[:start_time],
|
43
|
+
resource: r[:resource],
|
44
|
+
skip_message: r[:skip_message],
|
45
|
+
message: r[:message],
|
46
|
+
exception: r[:exception],
|
47
|
+
backtrace: r[:backtrace],
|
48
|
+
resource_class: r[:resource_class],
|
49
49
|
resource_params: r[:resource_params].to_s,
|
50
|
+
resource_id: extract_resource_id(r),
|
50
51
|
}.reject { |_k, v| v.nil? }
|
51
52
|
}
|
52
53
|
end
|
53
54
|
|
55
|
+
def extract_resource_id(r)
|
56
|
+
# According to the RunData API, this is supposed to be an anonymous
|
57
|
+
# class that represents a resource, with embedded instance methods....
|
58
|
+
resource_obj = r[:resource_title]
|
59
|
+
return resource_obj.resource_id if resource_obj.respond_to?(:resource_id)
|
60
|
+
|
61
|
+
# But sometimes, it isn't, and has been collapsed into the to_s stringification of the resource.
|
62
|
+
if resource_obj.is_a?(String)
|
63
|
+
orig_str = resource_obj
|
64
|
+
# Try to trim off the resource class - eg "File /some/path" => "/some/path"
|
65
|
+
trimmed_str = orig_str.sub(/^#{r[:resource_class]}/i, "").strip
|
66
|
+
trimmed_str.empty? ? orig_str : trimmed_str
|
67
|
+
else
|
68
|
+
# Boo, InSpec is crazy, and we don't know what it possibly could be.
|
69
|
+
# Failsafe for resource_id is empty string.
|
70
|
+
""
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
54
74
|
def profiles
|
55
75
|
run_data[:profiles].map do |p|
|
56
76
|
res = {
|
data/lib/inspec/resource.rb
CHANGED
@@ -34,6 +34,12 @@ module Inspec
|
|
34
34
|
Inspec::Resource.support_registry[key].push(criteria)
|
35
35
|
end
|
36
36
|
|
37
|
+
def resource_id(value = nil)
|
38
|
+
@resource_id = value if value
|
39
|
+
@resource_id = "" if @resource_id.nil?
|
40
|
+
@resource_id
|
41
|
+
end
|
42
|
+
|
37
43
|
# TODO: this is pretty terrible and is only here to work around
|
38
44
|
# the idea that we've trained resource authors to make initialize
|
39
45
|
# methods w/o calling super.
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "inspec/resources/crontab"
|
2
|
+
|
3
|
+
module Inspec::Resources
|
4
|
+
class Cron < Crontab
|
5
|
+
name "cron"
|
6
|
+
supports platform: "unix"
|
7
|
+
desc "Use the cron InSpec audit resource to test entires in the crontab file for a given user. This also can be used as alias to crontab resource."
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe cron do
|
10
|
+
it { should have_entry '* * * * * /usr/local/bin/foo' }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe cron(user: "username") do
|
14
|
+
its(:table) { should match /you can use regexp/ }
|
15
|
+
end
|
16
|
+
EXAMPLE
|
17
|
+
|
18
|
+
def initialize(opts = nil)
|
19
|
+
super
|
20
|
+
@params = read_cron_contents
|
21
|
+
end
|
22
|
+
|
23
|
+
def read_cron_contents
|
24
|
+
result = inspec.command(crontab_cmd)
|
25
|
+
if result.exit_status == 0
|
26
|
+
result.stdout.lines.map { |l| parse_comment_line(l, comment_char: "#", standalone_comments: false)[0].strip }
|
27
|
+
else
|
28
|
+
error = result.stdout + "\n" + result.stderr
|
29
|
+
raise Inspec::Exceptions::ResourceFailed, "Error while executing #{crontab_cmd} command: #{error}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def table
|
34
|
+
@params.reject(&:empty?).join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_entry?(rule)
|
38
|
+
@params.include?(rule)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
if is_user_crontab?
|
43
|
+
"cron for user #{@user}"
|
44
|
+
else
|
45
|
+
"cron for current user"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class IpFilter < Inspec.resource(1)
|
4
|
+
name "ipfilter"
|
5
|
+
supports platform: "bsd"
|
6
|
+
supports platform: "solaris"
|
7
|
+
desc "Use the ipfilter InSpec audit resource to test rules that are defined for ipfilter, which maintains the IP rule set"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe ipfilter do
|
10
|
+
it { should have_rule("pass in quick on lo0 all") }
|
11
|
+
end
|
12
|
+
EXAMPLE
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
# checks if the instance is either bsd or solaris
|
16
|
+
return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
|
17
|
+
|
18
|
+
# ensures, all calls are aborted for non-supported os
|
19
|
+
@ipfilter_cache = []
|
20
|
+
skip_resource "The `ipfilter` resource is not supported on your OS yet."
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_rule?(rule = nil)
|
24
|
+
# checks if the rule is part of the ruleset
|
25
|
+
retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def retrieve_rules
|
29
|
+
# this would be true if the OS family was not bsd/solaris when checked in initliaze
|
30
|
+
return @ipfilter_cache if defined?(@ipfilter_cache)
|
31
|
+
|
32
|
+
# construct ipfstat command to read all rules
|
33
|
+
bin = find_ipfstat_or_error
|
34
|
+
ipfstat_cmd = "#{bin} -io"
|
35
|
+
cmd = inspec.command(ipfstat_cmd)
|
36
|
+
|
37
|
+
# Return empty array when command is not executed successfully
|
38
|
+
# or there is no output since no rules are active
|
39
|
+
return [] if cmd.exit_status.to_i != 0 || cmd.stdout == ""
|
40
|
+
|
41
|
+
# split rules, returns array or rules
|
42
|
+
@ipfilter_cache = cmd.stdout.split("\n").map(&:strip)
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"Ipfilter"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def find_ipfstat_or_error
|
52
|
+
%w{/usr/sbin/ipfstat /sbin/ipfstat ipfstat}.each do |cmd|
|
53
|
+
return cmd if inspec.command(cmd).exist?
|
54
|
+
end
|
55
|
+
|
56
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `ipfstat`"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "inspec/resources/command"
|
2
|
+
module Inspec::Resources
|
3
|
+
class IpNat < Inspec.resource(1)
|
4
|
+
name "ipnat"
|
5
|
+
supports platform: "bsd"
|
6
|
+
supports platform: "solaris"
|
7
|
+
desc "Use the ipnat InSpec audit resource to test rules that are defined for IP NAT"
|
8
|
+
example <<~EXAMPLE
|
9
|
+
describe ipnat do
|
10
|
+
it { should have_rule("map net1 192.168.0.0/24 -> 0/32") }
|
11
|
+
end
|
12
|
+
EXAMPLE
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
# checks if the instance is either bsd or solaris
|
16
|
+
return if (inspec.os.bsd? && !inspec.os.darwin?) || inspec.os.solaris?
|
17
|
+
|
18
|
+
# ensures, all calls are aborted for non-supported os
|
19
|
+
@ipnat_cache = []
|
20
|
+
skip_resource "The `ipnat` resource is not supported on your OS yet."
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_rule?(rule = nil)
|
24
|
+
# checks if the rule is part of the ruleset
|
25
|
+
retrieve_rules.any? { |line| line.casecmp(rule) == 0 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def retrieve_rules
|
29
|
+
# this would be true if the OS family was not bsd/solaris when checked in initliaze
|
30
|
+
return @ipnat_cache if defined?(@ipnat_cache)
|
31
|
+
|
32
|
+
# construct ipnat command to show the list of current IP NAT table entry mappings
|
33
|
+
bin = find_ipnat_or_error
|
34
|
+
ipnat_cmd = "#{bin} -l"
|
35
|
+
cmd = inspec.command(ipnat_cmd)
|
36
|
+
|
37
|
+
# Return empty array when command is not executed successfully
|
38
|
+
return [] if cmd.exit_status.to_i != 0
|
39
|
+
|
40
|
+
# split rules, returns array or rules
|
41
|
+
@ipnat_cache = cmd.stdout.split("\n").map(&:strip)
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"Ipnat"
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def find_ipnat_or_error
|
51
|
+
%w{/usr/sbin/ipnat /sbin/ipnat ipnat}.each do |cmd|
|
52
|
+
return cmd if inspec.command(cmd).exist?
|
53
|
+
end
|
54
|
+
|
55
|
+
raise Inspec::Exceptions::ResourceFailed, "Could not find `ipnat`"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
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/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
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require "inspec/schema/primitives"
|
2
2
|
|
3
|
-
# These type occur only when running "exec --reporter
|
3
|
+
# These type occur only when running "exec --reporter exec-jsonmin <file>".
|
4
4
|
|
5
5
|
module Inspec
|
6
6
|
module Schema
|
@@ -11,28 +11,28 @@ module Inspec
|
|
11
11
|
"additionalProperties" => true,
|
12
12
|
"required" => %w{id profile_id profile_sha256 status code_desc},
|
13
13
|
"properties" => {
|
14
|
-
"id" => Primitives::STRING,
|
15
|
-
"profile_id" => { "type" => %w{string null} },
|
16
|
-
"profile_sha256" => Primitives::STRING,
|
17
|
-
"status" => Primitives::STRING,
|
18
|
-
"code_desc" => Primitives::STRING,
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"
|
22
|
-
"exception" => Primitives::STRING,
|
23
|
-
"backtrace" => Primitives.array(Primitives::STRING),
|
14
|
+
"id" => Primitives.desc(Primitives::STRING, "The id."),
|
15
|
+
"profile_id" => Primitives.desc({ "type" => %w{string null} }, "The name of the profile that can uniquely identify it - is nullable."),
|
16
|
+
"profile_sha256" => Primitives.desc(Primitives::STRING, "The checksum of the profile."),
|
17
|
+
"status" => Primitives.desc(Primitives::STRING, "The status of the control. Example: 'failed'."),
|
18
|
+
"code_desc" => Primitives.desc(Primitives::STRING, "A description of the control. Example: 'limits.conf * is expected to include ['hard', 'maxlogins', '10']."),
|
19
|
+
"message" => Primitives.desc(Primitives::STRING, "An explanation of the control status - usually only provided when the control fails."),
|
20
|
+
"skip_message" => Primitives.desc(Primitives::STRING, "An explanation of the status if the status was 'skipped'."),
|
21
|
+
"resource" => Primitives.desc(Primitives::STRING, "The resource used in the test. Example: in Inspec, you can use the 'File' resource."),
|
22
|
+
"exception" => Primitives.desc(Primitives::STRING, "The type of exception if an exception was thrown."),
|
23
|
+
"backtrace" => Primitives.desc(Primitives.array(Primitives::STRING), "The stacktrace/backtrace of the exception if one occurred."), # shouldn't this also be an anyOf similar to the CONTROL_RESULT from exec_json?
|
24
24
|
},
|
25
|
-
}, [])
|
25
|
+
}, [], "The set of all tests within the control and their results and findings.")
|
26
26
|
|
27
27
|
# Result of exec jsonmin. Top level value
|
28
|
-
OUTPUT = Primitives::SchemaType.new("Exec JSON-MIN
|
28
|
+
OUTPUT = Primitives::SchemaType.new("Exec JSON-MIN Output", {
|
29
29
|
"type" => "object",
|
30
30
|
"additionalProperties" => true,
|
31
31
|
"required" => %w{statistics controls version},
|
32
32
|
"properties" => {
|
33
|
-
"statistics" => Primitives::STATISTICS.ref,
|
34
|
-
"version" => Primitives::STRING,
|
35
|
-
"controls" => Primitives.array(CONTROL.ref),
|
33
|
+
"statistics" => Primitives.desc(Primitives::STATISTICS.ref, "Statistics for the run(s) from the tool that generated the findings. Example: the runtime duration."),
|
34
|
+
"version" => Primitives.desc(Primitives::STRING, "Version number of the tool that generated the findings. Example: '4.18.108' is a version of Chef Inspec."),
|
35
|
+
"controls" => Primitives.desc(Primitives.array(CONTROL.ref), "The set of controls including any findings as reported by the tool."),
|
36
36
|
},
|
37
37
|
}, [Primitives::STATISTICS, CONTROL])
|
38
38
|
end
|