diff --git a/README.md b/README.md index 43b0878f..70fc1242 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,13 @@ This method is sending the report using the `data_collector.server_url` and `dat If you are using a self-signed certificate, please also read [how to add the Chef Automate certificate to the trusted_certs directory](https://docs.chef.io/setup_visibility_chef_automate.html#add-chef-automate-certificate-to-trusted-certs-directory) +Version compatibility matrix: + +| Automate version | InSpec version | Audit Cookbook version | +|--------------------|------------------|--------------------------| +| < 0.8.0 | ≤ 1.23.0 | ≤ 3.1.0 | +| ≥ 0.8.0 | ≥ 1.24.0 | ≥ 4.0.0 | + ## Profile Upload to Compliance Server In order to support build cookbook mode, the `compliance_profile` resource has an `upload` action that allows uploading a compressed @@ -464,11 +471,11 @@ Please note that all dependencies to the `inspec` gem must also be hosted in thi Using the `inspec_version` attribute, please use the following `InSpec` version based on your Chef Compliance version: -| Chef Compliance version | InSpec version | Audit Cookbook version | -|----------------------------|----------------------------|----------------------------| -| Less or equal to 1.1.23 | 0.20.1 | 0.7.0 | -| Greater than 1.1.23 | Greater or equal to 0.22.1 | 0.8.0 | -| Greater or equal to 1.6.8 | Greater or equal to 1.2.0 | 1.0.2 | +| Chef Compliance version | InSpec version | Audit Cookbook version | +|----------------------------|-------------------|---------------------------| +| ≤ 1.1.23 | = 0.20.1 | = 0.7.0 | +| > 1.1.23 | ≥ 0.22.1 | = 0.8.0 | +| ≥ 1.6.8 | ≥ 1.2.0 | = 1.0.2 | You can see all publicly available InSpec versions [here](https://rubygems.org/gems/inspec/versions) diff --git a/files/default/handler/audit_report.rb b/files/default/handler/audit_report.rb index 9aa97d0c..809a0c49 100644 --- a/files/default/handler/audit_report.rb +++ b/files/default/handler/audit_report.rb @@ -138,20 +138,6 @@ def call(opts, profiles) Chef::Log.info "Summary: #{passed_controls} successful, #{failed_controls} failures, #{skipped_controls} skipped in #{time} s" end - if !r.nil? && 'json' == opts['format'] - # ensure controls are never stored or shipped, since this was an accidential - # addition in InSpec and will be remove in our next major release - r.delete(:controls) - - # calculate statistics - stats = count_controls(r[:profiles]) - - time = 0 - time = r[:statistics][:duration] unless r[:statistics].nil? - - # count controls - Chef::Log.info "Summary #{stats[:total]} controls: #{stats[:passed][:total]} successful, #{stats[:failed][:total]} failures, #{stats[:skipped][:total]} skipped in #{time} s" - end Chef::Log.debug "Audit Report #{r}" r else diff --git a/libraries/helper.rb b/libraries/helper.rb index ca568078..798e5db3 100644 --- a/libraries/helper.rb +++ b/libraries/helper.rb @@ -134,89 +134,6 @@ def get_reporters(audit) handle_reporters(audit['reporter']) end - # Returns a hash with the counted controls based on their status and criticality - # This working on full-json reports - # total: count for all controls in the report, e.g. 100 - # successful: count for all controls that executed successfully, e.g. 40 - # skipped: count for all skipped controls, e.g. 10 - # failed: count for all failed controls, e.g. 50 - # minor, major, critical: split the failed count in 3 buckets based on the criticality, - # e.g. minor: 10, major: 15, critical: 25 - def count_controls(profiles) - count = { - total: 0, - passed: { - total: 0, - }, - skipped: { - total: 0, - }, - failed: { - total: 0, - minor: 0, - major: 0, - critical: 0, - }, - } - return count unless profiles.is_a?(Array) - - profiles.each do |profile| - next unless profile && profile[:controls].is_a?(Array) - profile[:controls].each do |control| - count[:total] += 1 - # ensure all impacts are float - control[:impact] = control[:impact].to_f - case control_status(control[:results]) - when 'passed' - count[:passed][:total] += 1 - when 'skipped' - count[:skipped][:total] += 1 - when 'failed' - count[:failed][:total] += 1 - criticality = impact_to_s(control[:impact]) - count[:failed][criticality.to_sym] += 1 unless criticality.nil? - end - end - end - count - end - - # Returns a complince status string based on the passed/failed/skipped controls - def compliance_status(counts) - return 'unknown' unless counts.is_a?(Hash) && - counts[:failed].is_a?(Hash) && - counts[:skipped].is_a?(Hash) - if counts[:failed][:total] > 0 - 'failed' - elsif counts[:total] == counts[:skipped][:total] - 'skipped' - else - 'passed' - end - end - - # Returns a string with the control criticality based on the impact value - def impact_to_s(impact) - if impact < 0.4 - 'minor' - elsif impact < 0.7 - 'major' - else - 'critical' - end - end - - # A control can have multiple tests. Returns 'passed' unless any - # of the results has a status different than 'passed' - def control_status(results) - return unless results.is_a?(Array) - status = 'passed' - results.each do |result| - return 'failed' if result[:status] == 'failed' - status = 'skipped' if result[:status] == 'skipped' - end - status - end end ::Chef::Recipe.send(:include, ReportHelpers) diff --git a/libraries/reporters/automate.rb b/libraries/reporters/automate.rb index 15faffd0..4f8655eb 100644 --- a/libraries/reporters/automate.rb +++ b/libraries/reporters/automate.rb @@ -13,6 +13,7 @@ def initialize(opts) @entity_uuid = opts[:entity_uuid] @run_id = opts[:run_id] @node_name = opts[:node_info][:node] + @environment = opts[:node_info][:environment] @insecure = opts[:insecure] if defined?(Chef) && @@ -59,6 +60,7 @@ def send_report(report) begin Chef::Log.warn "Report to Chef Automate: #{@url}" + Chef::Log.debug "Audit Report: #{json_report}" http = Chef::HTTP.new(@url) http.post(nil, json_report, headers) return true @@ -106,33 +108,26 @@ def typed_attributes(profiles) # revamp of the Automate expected input. # *************************************************************************************** - def enriched_report(content) - return nil unless content.is_a?(Hash) - final_report = {} - total_duration = content[:statistics][:duration] - inspec_version = content[:version] + def enriched_report(final_report) + return nil unless final_report.is_a?(Hash) - # strip the report to leave only the profiles - final_report[:profiles] = content[:profiles] - - # remove nil profiles if any + # Remove nil profiles if any final_report[:profiles].select! { |p| p } - # set types for profile attributes + # Set types for profile attributes final_report[:profiles] = typed_attributes(final_report[:profiles]) - # add some additional fields to ease report parsing - final_report[:event_type] = 'inspec' - final_report[:event_action] = 'exec' - final_report[:compliance_summary] = count_controls(final_report[:profiles]) - final_report[:compliance_summary][:status] = compliance_status(final_report[:compliance_summary]) - final_report[:compliance_summary][:node_name] = @node_name - final_report[:compliance_summary][:end_time] = DateTime.now.iso8601 - final_report[:compliance_summary][:duration] = total_duration - final_report[:compliance_summary][:inspec_version] = inspec_version - final_report[:entity_uuid] = @entity_uuid - final_report[:run_id] = @run_id - Chef::Log.info "Compliance Summary #{final_report[:compliance_summary]}" + # Label this content as an inspec_report + final_report[:type] = 'inspec_report' + + # Ensure controls are never stored or shipped, since this was an accidential + # addition in InSpec and will be remove in the next inspec major release + final_report.delete(:controls) + final_report[:node_name] = @node_name + final_report[:end_time] = DateTime.now.iso8601 + final_report[:node_uuid] = @entity_uuid + final_report[:environment] = @environment + final_report[:report_uuid] = @run_id final_report end end diff --git a/metadata.rb b/metadata.rb index 52eedb7d..815a03ae 100644 --- a/metadata.rb +++ b/metadata.rb @@ -5,7 +5,7 @@ license 'Apache-2.0' description 'Allows for fetching and executing compliance profiles, and reporting its results' long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '3.1.0' +version '4.0.0' source_url 'https://github.com/chef-cookbooks/audit' issues_url 'https://github.com/chef-cookbooks/audit/issues'