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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/etc/deprecations.json +12 -11
  3. data/inspec-core.gemspec +1 -1
  4. data/lib/inspec/base_cli.rb +14 -2
  5. data/lib/inspec/cli.rb +15 -0
  6. data/lib/inspec/dependency_installer.rb +74 -0
  7. data/lib/inspec/dependency_loader.rb +97 -0
  8. data/lib/inspec/dsl.rb +11 -2
  9. data/lib/inspec/errors.rb +7 -0
  10. data/lib/inspec/formatters/base.rb +23 -0
  11. data/lib/inspec/metadata.rb +36 -0
  12. data/lib/inspec/plugin/v2/plugin_types/streaming_reporter.rb +44 -1
  13. data/lib/inspec/profile.rb +63 -0
  14. data/lib/inspec/reporters/automate.rb +1 -1
  15. data/lib/inspec/reporters/cli.rb +1 -1
  16. data/lib/inspec/reporters/json.rb +31 -11
  17. data/lib/inspec/resource.rb +6 -0
  18. data/lib/inspec/resources/cron.rb +49 -0
  19. data/lib/inspec/resources/ipfilter.rb +59 -0
  20. data/lib/inspec/resources/ipnat.rb +58 -0
  21. data/lib/inspec/resources.rb +3 -16
  22. data/lib/inspec/runner.rb +18 -1
  23. data/lib/inspec/runner_rspec.rb +15 -0
  24. data/lib/inspec/schema/exec_json.rb +59 -58
  25. data/lib/inspec/schema/exec_json_min.rb +16 -16
  26. data/lib/inspec/schema/primitives.rb +68 -51
  27. data/lib/inspec/schema/profile_json.rb +27 -27
  28. data/lib/inspec/schema.rb +1 -0
  29. data/lib/inspec/ui.rb +1 -0
  30. data/lib/inspec/utils/deprecated_cloud_resources_list.rb +54 -0
  31. data/lib/inspec/version.rb +1 -1
  32. data/lib/inspec.rb +3 -0
  33. data/lib/plugins/inspec-init/lib/inspec-init/cli.rb +1 -0
  34. data/lib/plugins/inspec-init/lib/inspec-init/cli_plugin.rb +9 -0
  35. data/lib/plugins/inspec-init/lib/inspec-init/cli_resource.rb +126 -0
  36. data/lib/plugins/inspec-init/lib/inspec-init/renderer.rb +9 -8
  37. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/plugin.erb +16 -0
  38. data/lib/plugins/inspec-init/templates/plugins/inspec-plugin-template/lib/inspec-plugin-template/streaming_reporter.erb +31 -0
  39. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
  40. data/lib/plugins/inspec-init/templates/resources/basic/docs/resource-doc.erb +77 -0
  41. data/lib/plugins/inspec-init/templates/resources/basic/libraries/inspec-resource-template.erb +94 -0
  42. data/lib/plugins/inspec-init/templates/resources/plural/docs/resource-doc.erb +62 -0
  43. data/lib/plugins/inspec-init/templates/resources/plural/libraries/inspec-resource-template.erb +73 -0
  44. data/lib/plugins/inspec-reporter-html2/templates/body.html.erb +2 -0
  45. data/lib/plugins/inspec-reporter-html2/templates/control.html.erb +3 -0
  46. data/lib/plugins/inspec-reporter-html2/templates/profile.html.erb +1 -0
  47. data/lib/plugins/inspec-reporter-html2/templates/result.html.erb +1 -0
  48. data/lib/plugins/inspec-streaming-reporter-progress-bar/README.md +5 -0
  49. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/plugin.rb +13 -0
  50. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/streaming_reporter.rb +112 -0
  51. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar/version.rb +8 -0
  52. data/lib/plugins/inspec-streaming-reporter-progress-bar/lib/inspec-streaming-reporter-progress-bar.rb +15 -0
  53. 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] || @config["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: 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],
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 = {
@@ -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
@@ -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
- register_rule(rule) unless rule.nil?
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)
@@ -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 ID of this control"),
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
- A list of all results of the controls describe blocks.
67
-
68
- For instance, if in the controls code we had the following:
69
- describe sshd_config do
70
- its('Port') { should cmp 22 }
71
- end
72
- The result of this block as a ControlResult would be appended to the results list.
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, # If skipped or failed to load, why
107
- "skip_message" => Primitives::STRING, # Deprecated field storing reason for skipping. status_message should be used instead.
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 json-min <file>".
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
- "skip_message" => Primitives::STRING,
20
- "resource" => Primitives::STRING,
21
- "message" => Primitives::STRING,
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 output", {
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