diff options
author | Pete Higgins <pete@peterhiggins.org> | 2020-11-03 12:49:46 -0800 |
---|---|---|
committer | Pete Higgins <pete@peterhiggins.org> | 2020-12-01 16:05:17 -0800 |
commit | 7928c40c15e2405c62de4c91a733f37dd2d39b1b (patch) | |
tree | 10c5b89af1713ca19afa3ba2fe65a377cceeddf0 | |
parent | 56e71819d0aed3dae8d3ff2655b61fa1fc89071f (diff) | |
download | chef-7928c40c15e2405c62de4c91a733f37dd2d39b1b.tar.gz |
Fix chefstyle violations.
Signed-off-by: Pete Higgins <pete@peterhiggins.org>
-rw-r--r-- | lib/chef/audit/default_attributes.rb | 50 | ||||
-rw-r--r-- | lib/chef/audit/fetcher/automate.rb | 30 | ||||
-rw-r--r-- | lib/chef/audit/fetcher/chef_server.rb | 26 | ||||
-rw-r--r-- | lib/chef/audit/reporter/audit_enforcer.rb | 4 | ||||
-rw-r--r-- | lib/chef/audit/reporter/automate.rb | 33 | ||||
-rw-r--r-- | lib/chef/audit/reporter/chef_server_automate.rb | 18 | ||||
-rw-r--r-- | lib/chef/audit/reporter/json_file.rb | 2 | ||||
-rw-r--r-- | lib/chef/audit/runner.rb | 90 | ||||
-rw-r--r-- | lib/chef/client.rb | 2 | ||||
-rw-r--r-- | spec/unit/audit/fetcher/automate_spec.rb | 76 | ||||
-rw-r--r-- | spec/unit/audit/fetcher/chef_server_spec.rb | 48 | ||||
-rw-r--r-- | spec/unit/audit/reporter/audit_enforcer_spec.rb | 24 | ||||
-rw-r--r-- | spec/unit/audit/reporter/automate_spec.rb | 260 | ||||
-rw-r--r-- | spec/unit/audit/reporter/chef_server_automate_spec.rb | 196 | ||||
-rw-r--r-- | spec/unit/audit/runner_spec.rb | 2 |
15 files changed, 431 insertions, 430 deletions
diff --git a/lib/chef/audit/default_attributes.rb b/lib/chef/audit/default_attributes.rb index b45789f154..05333316b7 100644 --- a/lib/chef/audit/default_attributes.rb +++ b/lib/chef/audit/default_attributes.rb @@ -19,16 +19,16 @@ class Chef DEFAULTS = { # Controls the inspec gem version to install and execution. Example values: '1.1.0', 'latest' # Starting with Chef Infra Client 15, only the embedded InSpec gem can be used and this attribute will be ignored - 'inspec_version' => nil, + "inspec_version" => nil, # sets URI to alternate gem source # example values: nil, 'https://mygem.server.com' # notes: the root of the URL must host the *specs.4.8.gz source index - 'inspec_gem_source' => nil, + "inspec_gem_source" => nil, # If enabled, a cache is built for all backend calls. This should only be # disabled if you are expecting unique results from the same backend call. - 'inspec_backend_cache' => true, + "inspec_backend_cache" => true, # controls where inspec scan reports are sent # possible values: 'chef-server-automate', 'chef-automate', 'json-file' @@ -36,88 +36,88 @@ class Chef # deprecated: 'chef-visibility' is replaced with 'chef-automate' # deprecated: 'chef-compliance' is replaced with 'chef-automate' # deprecated: 'chef-server-visibility' is replaced with 'chef-server-automate' - 'reporter' => 'json-file', + "reporter" => "json-file", # controls where inspec profiles are fetched from, Chef Automate or via Chef Server # possible values: nil, 'chef-server', 'chef-automate' - 'fetcher' => nil, + "fetcher" => nil, # allow for connections to HTTPS endpoints using self-signed ssl certificates - 'insecure' => nil, + "insecure" => nil, # Optional for 'chef-server-automate' reporter # defaults to Chef Server org if not defined - 'owner' => nil, + "owner" => nil, # raise exception if Automate API endpoint is unreachable # while fetching profiles or posting a report - 'raise_if_unreachable' => true, + "raise_if_unreachable" => true, # fail converge if downloaded profile is not present # https://github.com/chef-cookbooks/audit/issues/166 - 'fail_if_not_present' => false, + "fail_if_not_present" => false, - 'interval' => { + "interval" => { # control how often inspec scans are run, if not on every node converge # notes: false value will result in running inspec scan every converge - 'enabled' => false, + "enabled" => false, # controls how often inspec scans are run (in minutes) # notes: only used if interval is enabled above - 'time' => 1440, + "time" => 1440, }, # controls verbosity of inspec runner - 'quiet' => true, + "quiet" => true, # Chef Inspec Compliance profiles to be used for scan of node # See README.md for details - 'profiles' => {}, + "profiles" => {}, # Attributes used to run the given profiles - 'attributes' => {}, + "attributes" => {}, # Set this to false if you don't want ['audit']['attributes'] to be saved in the node object and stored in Chef Server or Automate. Useful if you are passing sensitive data to the inspec profile via the attributes. - 'attributes_save' => true, + "attributes_save" => true, # If enabled, a hash of the Chef "node" object will be sent to InSpec in an attribute # named `chef_node` - 'chef_node_attribute_enabled' => false, + "chef_node_attribute_enabled" => false, # Set this to the path of a YAML waiver file you wish to apply # See https://www.inspec.io/docs/reference/waivers/ - 'waiver_file' => nil, + "waiver_file" => nil, - 'json_file' => { + "json_file" => { # The location of the json-file output: # <chef_cache_path>/cookbooks/audit/inspec-<YYYYMMDDHHMMSS>.json # TODO: ^^ comment is wrong # TODO: Does this path work? - 'location' => File.expand_path(Time.now.utc.strftime('../../../inspec-%Y%m%d%H%M%S.json'), __dir__) + "location" => File.expand_path(Time.now.utc.strftime("../../../inspec-%Y%m%d%H%M%S.json"), __dir__), }, # Control results that have a `run_time` below this limit will # be stripped of the `start_time` and `run_time` fields to # reduce the size of the reports being sent to Automate - 'run_time_limit' => 1.0, + "run_time_limit" => 1.0, # A control result message that exceeds this character limit will be truncated. # This helps keep reports to a reasonable size. On rare occasions, we've seen messages exceeding 9 MB in size, # causing the report to not be ingested in the backend because of the 4 MB report size rpc limitation. # InSpec will append this text at the end of any truncated messages: `[Truncated to 10000 characters]` # Requires InSpec 4.18.114 or newer (bundled with Chef Infra Client starting with version 16.0.303) - 'result_message_limit' => 10000, + "result_message_limit" => 10000, # When an InSpec resource throws an exception (e.g. permission denied), results will contain a short error message and a # detailed ruby stacktrace of the error. This attribute instructs InSpec not to include the detailed stacktrace in order # to keep the overall report to a manageable size. # Requires InSpec 4.18.114 or newer (bundled with Chef Infra Client starting with version 16.0.303) - 'result_include_backtrace' => false, + "result_include_backtrace" => false, # The array of results per control will be truncated at this limit to avoid large reports that cannot be # processed by Automate. A summary of removed results will be sent with each impacted control. - 'control_results_limit' => 50, - } + "control_results_limit" => 50, + }.freeze end end end diff --git a/lib/chef/audit/fetcher/automate.rb b/lib/chef/audit/fetcher/automate.rb index e28d8ea026..856bc8e409 100644 --- a/lib/chef/audit/fetcher/automate.rb +++ b/lib/chef/audit/fetcher/automate.rb @@ -1,25 +1,25 @@ -require "uri" +require "uri" unless defined?(URI) require "plugins/inspec-compliance/lib/inspec-compliance" class Chef module Audit module Fetcher class Automate < ::InspecPlugins::Compliance::Fetcher - name 'chef-automate' + name "chef-automate" # it positions itself before `compliance` fetcher # only load it, if you want to use audit cookbook in Chef Solo with Chef Automate priority 502 CONFIG = { - 'insecure' => true, - 'token' => nil, - 'server_type' => 'automate', - 'automate' => { - 'ent' => 'default', - 'token_type' => 'dctoken', + "insecure" => true, + "token" => nil, + "server_type" => "automate", + "automate" => { + "ent" => "default", + "token_type" => "dctoken", }, - } + }.freeze def self.resolve(target) uri = get_target_uri(target) @@ -45,13 +45,13 @@ class Chef url.path = profile_path profile_fetch_url = url.to_s - config['token'] = dc['token'] + config["token"] = dc["token"] - if config['token'].nil? - raise 'No data-collector token set, which is required by the chef-automate fetcher. ' \ - 'Set the `data_collector.token` configuration parameter in your client.rb ' \ + if config["token"].nil? + raise "No data-collector token set, which is required by the chef-automate fetcher. " \ + "Set the `data_collector.token` configuration parameter in your client.rb " \ 'or use the "chef-server-automate" reporter which does not require any ' \ - 'data-collector settings and uses Chef Server to fetch profiles.' + "data-collector settings and uses Chef Server to fetch profiles." end end @@ -61,7 +61,7 @@ class Chef end def to_s - 'Chef Automate for Chef Solo Fetcher' + "Chef Automate for Chef Solo Fetcher" end end end diff --git a/lib/chef/audit/fetcher/chef_server.rb b/lib/chef/audit/fetcher/chef_server.rb index 656dcaa1f6..ccadefb6fb 100644 --- a/lib/chef/audit/fetcher/chef_server.rb +++ b/lib/chef/audit/fetcher/chef_server.rb @@ -1,4 +1,4 @@ -require 'uri' +require "uri" unless defined?(URI) require "plugins/inspec-compliance/lib/inspec-compliance" # This class implements an InSpec fetcher for for Chef Server. The implementation @@ -12,13 +12,13 @@ class Chef module Audit module Fetcher class ChefServer < ::InspecPlugins::Compliance::Fetcher - name 'chef-server' + name "chef-server" # it positions itself before `compliance` fetcher # only load it, if the Chef Server is integrated with Chef Compliance priority 501 - CONFIG = { 'insecure' => true } + CONFIG = { "insecure" => true }.freeze # Accepts URLs to compliance profiles in one of two forms: # * a String URL with a compliance scheme, like "compliance://namespace/profile_name" @@ -27,7 +27,7 @@ class Chef profile_uri = get_target_uri(target) return nil if profile_uri.nil? - organization = Chef::Config[:chef_server_url].split('/').last + organization = Chef::Config[:chef_server_url].split("/").last owner = profile_uri.user ? "#{profile_uri.user}@#{profile_uri.host}" : profile_uri.host version = target[:version] if target.respond_to?(:key?) @@ -69,7 +69,7 @@ class Chef archive = with_http_rescue do rest.streaming_request(@target) end - @archive_type = '.tar.gz' + @archive_type = ".tar.gz" if archive.nil? path = @target.respond_to?(:path) ? @target.path : path @@ -95,11 +95,11 @@ class Chef def handle_http_error_code(code) case code when /401|403/ - Chef::Log.error 'Auth issue: see audit cookbook TROUBLESHOOTING.md' + Chef::Log.error "Auth issue: see audit cookbook TROUBLESHOOTING.md" when /404/ - Chef::Log.error 'Object does not exist on remote server.' + Chef::Log.error "Object does not exist on remote server." when /413/ - Chef::Log.error 'You most likely hit the erchef request size in Chef Server that defaults to ~2MB. To increase this limit see audit cookbook TROUBLESHOOTING.md OR https://docs.chef.io/config_rb_server.html' + Chef::Log.error "You most likely hit the erchef request size in Chef Server that defaults to ~2MB. To increase this limit see audit cookbook TROUBLESHOOTING.md OR https://docs.chef.io/config_rb_server.html" when /429/ Chef::Log.error "This error typically means the data sent was larger than Automate's limit (4 MB). Run InSpec locally to identify any controls producing large diffs." end @@ -109,17 +109,17 @@ class Chef end def to_s - 'Chef Server/Compliance Profile Loader' + "Chef Server/Compliance Profile Loader" end - CHEF_SERVER_REPORTERS = %w(chef-server chef-server-compliance chef-server-visibility chef-server-automate) + CHEF_SERVER_REPORTERS = %w{chef-server chef-server-compliance chef-server-visibility chef-server-automate}.freeze def self.chef_server_reporter? - (Array(Chef.node.attributes['audit']['reporter']) & CHEF_SERVER_REPORTERS).any? + (Array(Chef.node.attributes["audit"]["reporter"]) & CHEF_SERVER_REPORTERS).any? end - CHEF_SERVER_FETCHERS = %w(chef-server chef-server-compliance chef-server-visibility chef-server-automate) + CHEF_SERVER_FETCHERS = %w{chef-server chef-server-compliance chef-server-visibility chef-server-automate}.freeze def self.chef_server_fetcher? - CHEF_SERVER_FETCHERS.include?(Chef.node.attributes['audit']['fetcher']) + CHEF_SERVER_FETCHERS.include?(Chef.node.attributes["audit"]["fetcher"]) end private diff --git a/lib/chef/audit/reporter/audit_enforcer.rb b/lib/chef/audit/reporter/audit_enforcer.rb index 4db2d4cd64..2ee5e3b1f3 100644 --- a/lib/chef/audit/reporter/audit_enforcer.rb +++ b/lib/chef/audit/reporter/audit_enforcer.rb @@ -1,5 +1,3 @@ -# encoding: utf-8 - class Chef module Audit module Reporter @@ -10,7 +8,7 @@ class Chef report.fetch(:profiles, []).each do |profile| profile.fetch(:controls, []).each do |control| control.fetch(:results, []).each do |result| - raise ControlFailure, "Audit #{control[:id]} has failed. Aborting chef-client run." if result[:status] == 'failed' + raise ControlFailure, "Audit #{control[:id]} has failed. Aborting chef-client run." if result[:status] == "failed" end end end diff --git a/lib/chef/audit/reporter/automate.rb b/lib/chef/audit/reporter/automate.rb index 7c7f3658b6..c6a5c0c3fb 100644 --- a/lib/chef/audit/reporter/automate.rb +++ b/lib/chef/audit/reporter/automate.rb @@ -37,15 +37,15 @@ class Chef end unless @url && @token - Chef::Log.warn 'data_collector.token and data_collector.server_url must be defined in client.rb!' - Chef::Log.warn 'Further information: https://github.com/chef-cookbooks/audit#direct-reporting-to-chef-automate' + Chef::Log.warn "data_collector.token and data_collector.server_url must be defined in client.rb!" + Chef::Log.warn "Further information: https://github.com/chef-cookbooks/audit#direct-reporting-to-chef-automate" return false end headers = { - 'Content-Type' => 'application/json', - 'x-data-collector-auth' => 'version=1.0', - 'x-data-collector-token' => @token, + "Content-Type" => "application/json", + "x-data-collector-auth" => "version=1.0", + "x-data-collector-token" => @token, } all_report_shas = report.fetch(:profiles, []).map { |p| p[:sha256] } @@ -62,11 +62,11 @@ class Chef # https://github.com/chef/automate/issues/1417#issuecomment-541908157 if report_size > 4 * 1024 * 1024 Chef::Log.warn "Compliance report size is #{(report_size / (1024 * 1024.0)).round(2)} MB." - Chef::Log.warn 'Automate has an internal 4MB limit that is not currently configurable.' + Chef::Log.warn "Automate has an internal 4MB limit that is not currently configurable." end unless json_report - Chef::Log.warn 'Something went wrong, report can\'t be nil' + Chef::Log.warn "Something went wrong, report can't be nil" return false end @@ -81,7 +81,7 @@ class Chef end end - def http_client(url=@url) + def http_client(url = @url) if @insecure Chef::HTTP.new(url, ssl_verify_mode: :verify_none) else @@ -99,13 +99,13 @@ class Chef final_report[:profiles].select! { |p| p } # Label this content as an inspec_report - final_report[:type] = '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] = @timestamp.utc.strftime('%FT%TZ') + final_report[:end_time] = @timestamp.utc.strftime("%FT%TZ") final_report[:node_uuid] = @entity_uuid final_report[:environment] = @environment final_report[:roles] = @roles @@ -122,7 +122,7 @@ class Chef final_report end - CONTROL_RESULT_SORT_ORDER = %w{ failed skipped passed } + CONTROL_RESULT_SORT_ORDER = %w{ failed skipped passed }.freeze # Truncates the number of results per control in the report when they exceed max_results. # The truncation prioritizes failed and skipped results over passed ones. @@ -135,6 +135,7 @@ class Chef profile.fetch(:controls, []).each do |control| # Only bother with truncation if the number of results exceed max_results next unless control[:results].length > max_results + res = control[:results] res.sort_by! { |r| CONTROL_RESULT_SORT_ORDER.index(r[:status]) } @@ -142,11 +143,11 @@ class Chef truncated = { failed: 0, skipped: 0, passed: 0 } (max_results..res.length - 1).each do |i| case res[i][:status] - when 'failed' + when "failed" truncated[:failed] += 1 - when 'skipped' + when "skipped" truncated[:skipped] += 1 - when 'passed' + when "passed" truncated[:passed] += 1 end end @@ -163,9 +164,9 @@ class Chef def missing_automate_profiles(headers, report_shas) Chef::Log.debug "Checking the Automate profiles metadata for: #{report_shas}" meta_url = URI(@url) - meta_url.path = '/compliance/profiles/metasearch' + meta_url.path = "/compliance/profiles/metasearch" response_str = http_client(meta_url.to_s).post(nil, "{\"sha256\": #{report_shas}}", headers) - missing_shas = JSON.parse(response_str)['missing_sha256'] + missing_shas = JSON.parse(response_str)["missing_sha256"] unless missing_shas.empty? Chef::Log.info "Automate is missing metadata for the following profile ids: #{missing_shas}" end diff --git a/lib/chef/audit/reporter/chef_server_automate.rb b/lib/chef/audit/reporter/chef_server_automate.rb index 99a5177418..84b9fb9d62 100644 --- a/lib/chef/audit/reporter/chef_server_automate.rb +++ b/lib/chef/audit/reporter/chef_server_automate.rb @@ -1,4 +1,4 @@ -require_relative 'automate' +require_relative "automate" class Chef module Audit @@ -39,7 +39,7 @@ class Chef # this is set to slightly less than the oc_erchef limit if report_size > 900 * 1024 Chef::Log.warn "Compliance report size is #{(report_size / (1024 * 1024.0)).round(2)} MB." - Chef::Log.warn 'Infra Server < 13.0 defaults to a limit of ~1MB, 13.0+ defaults to a limit of ~2MB.' + Chef::Log.warn "Infra Server < 13.0 defaults to a limit of ~1MB, 13.0+ defaults to a limit of ~2MB." end Chef::Log.info "Report to Chef Automate via Chef Server: #{@url}" @@ -52,10 +52,10 @@ class Chef def http_client config = if @insecure - Chef::Config.merge(ssl_verify_mode: :verify_none) - else - Chef::Config - end + Chef::Config.merge(ssl_verify_mode: :verify_none) + else + Chef::Config + end Chef::ServerAPI.new(@url, config) end @@ -75,11 +75,11 @@ class Chef def handle_http_error_code(code) case code when /401|403/ - Chef::Log.error 'Auth issue: see audit cookbook TROUBLESHOOTING.md' + Chef::Log.error "Auth issue: see audit cookbook TROUBLESHOOTING.md" when /404/ - Chef::Log.error 'Object does not exist on remote server.' + Chef::Log.error "Object does not exist on remote server." when /413/ - Chef::Log.error 'You most likely hit the erchef request size in Chef Server that defaults to ~2MB. To increase this limit see audit cookbook TROUBLESHOOTING.md OR https://docs.chef.io/config_rb_server.html' + Chef::Log.error "You most likely hit the erchef request size in Chef Server that defaults to ~2MB. To increase this limit see audit cookbook TROUBLESHOOTING.md OR https://docs.chef.io/config_rb_server.html" when /429/ Chef::Log.error "This error typically means the data sent was larger than Automate's limit (4 MB). Run InSpec locally to identify any controls producing large diffs." end diff --git a/lib/chef/audit/reporter/json_file.rb b/lib/chef/audit/reporter/json_file.rb index d3ac1d3d2f..3734bf1a77 100644 --- a/lib/chef/audit/reporter/json_file.rb +++ b/lib/chef/audit/reporter/json_file.rb @@ -1,4 +1,4 @@ -autoload :JSON, 'json' +autoload :JSON, "json" class Chef module Audit diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb index bbe2b8ae88..9e8b6f9fef 100644 --- a/lib/chef/audit/runner.rb +++ b/lib/chef/audit/runner.rb @@ -1,12 +1,12 @@ -autoload :Inspec, 'inspec' +autoload :Inspec, "inspec" -require_relative 'default_attributes' -require_relative 'fetcher/automate' -require_relative 'fetcher/chef_server' -require_relative 'reporter/audit_enforcer' -require_relative 'reporter/automate' -require_relative 'reporter/chef_server_automate' -require_relative 'reporter/json_file' +require_relative "default_attributes" +require_relative "fetcher/automate" +require_relative "fetcher/chef_server" +require_relative "reporter/audit_enforcer" +require_relative "reporter/automate" +require_relative "reporter/chef_server_automate" +require_relative "reporter/json_file" class Chef module Audit @@ -36,7 +36,7 @@ class Chef report end - # TODO: handle error reports +# TODO: handle error reports =begin # Called at the end of a failed Chef run. def run_failed(exception, run_status); end @@ -49,44 +49,45 @@ class Chef ### Below code adapted from audit cookbook's files/default/handler/audit_report.rb - def report(report=generate_report) + def report(report = generate_report) if report.empty? - Chef::Log.error 'Audit report was not generated properly, skipped reporting' + Chef::Log.error "Audit report was not generated properly, skipped reporting" return end - Array(audit_attributes['reporter']).each do |reporter| + Array(audit_attributes["reporter"]).each do |reporter| send_report(reporter, report) end end def inspec_opts - waivers = Array(audit_attributes['waiver_file']).select do |file| + waivers = Array(audit_attributes["waiver_file"]).select do |file| return true if File.exist?(file) + Chef::Log.error "The specified InSpec waiver file #{file} is missing, skipping it..." false end { - 'report' => true, - 'format' => 'json-automate', # TODO: Remove this? Deprecation notice in audit cookbook - 'reporter' => ['json-automate'], - 'output' => audit_attributes['quiet'] ? ::File::NULL : STDOUT, - 'logger' => Chef::Log, - backend_cache: audit_attributes['inspec_backend_cache'], - attributes: audit_attributes['attributes'], + "report" => true, + "format" => "json-automate", # TODO: Remove this? Deprecation notice in audit cookbook + "reporter" => ["json-automate"], + "output" => audit_attributes["quiet"] ? ::File::NULL : STDOUT, + "logger" => Chef::Log, + backend_cache: audit_attributes["inspec_backend_cache"], + attributes: audit_attributes["attributes"], waiver_file: waivers, - reporter_message_truncation: audit_attributes['result_message_limit'], - reporter_backtrace_inclusion: audit_attributes['result_include_backtrace'], + reporter_message_truncation: audit_attributes["result_message_limit"], + reporter_backtrace_inclusion: audit_attributes["result_include_backtrace"], } end def audit_attributes - @audit_attributes ||= Chef::Audit::DefaultAttributes::DEFAULTS.merge(node['audit']) + @audit_attributes ||= Chef::Audit::DefaultAttributes::DEFAULTS.merge(node["audit"]) end def inspec_profiles - audit_attributes['profiles'].map do |name, profile| + audit_attributes["profiles"].map do |name, profile| profile.transform_keys(&:to_sym).update(name: name) end end @@ -96,7 +97,7 @@ class Chef runner = ::Inspec::Runner.new(opts) if profiles.empty? - failed_report('No audit profiles are defined.') + failed_report("No audit profiles are defined.") return end @@ -124,15 +125,15 @@ class Chef { "platform": { "name": "unknown", - "release": "unknown" + "release": "unknown", }, "profiles": [], "statistics": { - "duration": 0.0000001 + "duration": 0.0000001, }, "version": "4.22.0", "status": "failed", - "status_message": err + "status_message": err, } end @@ -143,19 +144,19 @@ class Chef { node: node.name, os: { - release: node['platform_version'], - family: node['platform'], + release: node["platform_version"], + family: node["platform"], }, environment: node.environment, roles: runlist_roles, recipes: runlist_recipes, - policy_name: node.policy_name || '', - policy_group: node.policy_group || '', + policy_name: node.policy_name || "", + policy_group: node.policy_group || "", chef_tags: node.tags, - organization_name: chef_server_uri.path.split('/').last || '', - source_fqdn: chef_server_uri.host || '', - ipaddress: node['ipaddress'], - fqdn: node['fqdn'], + organization_name: chef_server_uri.path.split("/").last || "", + source_fqdn: chef_server_uri.host || "", + ipaddress: node["ipaddress"], + fqdn: node["fqdn"], } end @@ -210,16 +211,16 @@ class Chef def send_report(reporter, report) Chef::Log.info "Reporting to #{reporter}" - insecure = audit_attributes['insecure'] - run_time_limit = audit_attributes['run_time_limit'] - control_results_limit = audit_attributes['control_results_limit'] + insecure = audit_attributes["insecure"] + run_time_limit = audit_attributes["run_time_limit"] + control_results_limit = audit_attributes["control_results_limit"] case reporter - when 'json-file' - path = audit_attributes['json_file']['location'] + when "json-file" + path = audit_attributes["json_file"]["location"] Chef::Log.info "Writing report to #{path}" Chef::Audit::Reporter::JsonFile.new(file: path).send_report(report) - when 'audit-enforcer' + when "audit-enforcer" Chef::Audit::Reporter::AuditEnforcer.new.send_report(report) else Chef::Log.warn "#{reporter} is not a supported InSpec report collector" @@ -228,8 +229,9 @@ class Chef def run_id return unless run_context && - run_context.events && - run_context.events.subscribers.is_a?(Array) + run_context.events && + run_context.events.subscribers.is_a?(Array) + run_context.events.subscribers.each do |sub| if sub.class == Chef::ResourceReporter && defined?(sub.run_id) return sub.run_id diff --git a/lib/chef/client.rb b/lib/chef/client.rb index f2f9b7c6af..8b2d3e8a30 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -57,7 +57,7 @@ require "ohai" unless defined?(Ohai::System) require "rbconfig" unless defined?(RbConfig) require "forwardable" unless defined?(Forwardable) -require_relative 'audit/runner' +require_relative "audit/runner" class Chef # == Chef::Client diff --git a/spec/unit/audit/fetcher/automate_spec.rb b/spec/unit/audit/fetcher/automate_spec.rb index df0225ed9e..ea471a1a22 100644 --- a/spec/unit/audit/fetcher/automate_spec.rb +++ b/spec/unit/audit/fetcher/automate_spec.rb @@ -1,59 +1,59 @@ -require 'spec_helper' +require "spec_helper" require "chef/audit/fetcher/automate" describe Chef::Audit::Fetcher::Automate do describe ".resolve" do before do Chef::Config[:data_collector] = { - server_url: 'https://automate.test/data_collector', + server_url: "https://automate.test/data_collector", token: token, } end let(:token) { "fake_token" } - context 'when target is a string' do - it 'should resolve a compliance URL' do - res = Chef::Audit::Fetcher::Automate.resolve('compliance://namespace/profile_name') + context "when target is a string" do + it "should resolve a compliance URL" do + res = Chef::Audit::Fetcher::Automate.resolve("compliance://namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar" expect(res.target).to eq(expected) end - it 'raises an exception with no data collector token' do + it "raises an exception with no data collector token" do Chef::Config[:data_collector].delete(:token) expect { - Chef::Audit::Fetcher::Automate.resolve('compliance://namespace/profile_name') + Chef::Audit::Fetcher::Automate.resolve("compliance://namespace/profile_name") }.to raise_error(/No data-collector token set/) end - it 'includes the data collector token' do + it "includes the data collector token" do expect(Chef::Audit::Fetcher::Automate).to receive(:new).with( "https://automate.test/compliance/profiles/namespace/profile_name/tar", - hash_including('token' => token), + hash_including("token" => token) ).and_call_original - res = Chef::Audit::Fetcher::Automate.resolve('compliance://namespace/profile_name') + res = Chef::Audit::Fetcher::Automate.resolve("compliance://namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar" expect(res.target).to eq(expected) end - it 'returns nil with a non-compliance URL' do - res = Chef::Audit::Fetcher::Automate.resolve('http://github.com/chef-cookbooks/audit') + it "returns nil with a non-compliance URL" do + res = Chef::Audit::Fetcher::Automate.resolve("http://github.com/chef-cookbooks/audit") expect(res).to eq(nil) end end - context 'when target is a hash' do - it 'should resolve a target with a version' do + context "when target is a hash" do + it "should resolve a target with a version" do res = Chef::Audit::Fetcher::Automate.resolve( - compliance: 'namespace/profile_name', - version: '1.2.3', + compliance: "namespace/profile_name", + version: "1.2.3" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) @@ -61,9 +61,9 @@ describe Chef::Audit::Fetcher::Automate do expect(res.target).to eq(expected) end - it 'should resolve a target without a version' do + it "should resolve a target without a version" do res = Chef::Audit::Fetcher::Automate.resolve( - compliance: 'namespace/profile_name', + compliance: "namespace/profile_name" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) @@ -71,60 +71,60 @@ describe Chef::Audit::Fetcher::Automate do expect(res.target).to eq(expected) end - it 'uses url key when present' do + it "uses url key when present" do res = Chef::Audit::Fetcher::Automate.resolve( - compliance: 'namespace/profile_name', - version: '1.2.3', - url: 'https://profile.server.test/profiles/profile_name/1.2.3' + compliance: "namespace/profile_name", + version: "1.2.3", + url: "https://profile.server.test/profiles/profile_name/1.2.3" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) - expected = 'https://profile.server.test/profiles/profile_name/1.2.3' + expected = "https://profile.server.test/profiles/profile_name/1.2.3" expect(res.target).to eq(expected) end - it 'does not include token in the config when url key is present' do + it "does not include token in the config when url key is present" do expect(Chef::Audit::Fetcher::Automate).to receive(:new).with( - 'https://profile.server.test/profiles/profile_name/1.2.3', - hash_including('token' => nil), + "https://profile.server.test/profiles/profile_name/1.2.3", + hash_including("token" => nil) ).and_call_original res = Chef::Audit::Fetcher::Automate.resolve( - compliance: 'namespace/profile_name', - version: '1.2.3', - url: 'https://profile.server.test/profiles/profile_name/1.2.3' + compliance: "namespace/profile_name", + version: "1.2.3", + url: "https://profile.server.test/profiles/profile_name/1.2.3" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) - expected = 'https://profile.server.test/profiles/profile_name/1.2.3' + expected = "https://profile.server.test/profiles/profile_name/1.2.3" expect(res.target).to eq(expected) end - it 'raises an exception with no data collector token' do + it "raises an exception with no data collector token" do Chef::Config[:data_collector].delete(:token) expect { - Chef::Audit::Fetcher::Automate.resolve(compliance: 'namespace/profile_name') + Chef::Audit::Fetcher::Automate.resolve(compliance: "namespace/profile_name") }.to raise_error(/No data-collector token set/) end - it 'includes the data collector token' do + it "includes the data collector token" do expect(Chef::Audit::Fetcher::Automate).to receive(:new).with( "https://automate.test/compliance/profiles/namespace/profile_name/tar", - hash_including('token' => token), + hash_including("token" => token) ).and_call_original - res = Chef::Audit::Fetcher::Automate.resolve(compliance: 'namespace/profile_name') + res = Chef::Audit::Fetcher::Automate.resolve(compliance: "namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::Automate) expected = "https://automate.test/compliance/profiles/namespace/profile_name/tar" expect(res.target).to eq(expected) end - it 'returns nil with a non-profile Hash' do + it "returns nil with a non-profile Hash" do res = Chef::Audit::Fetcher::Automate.resolve( - profile: 'namespace/profile_name', - version: '1.2.3' + profile: "namespace/profile_name", + version: "1.2.3" ) expect(res).to eq(nil) diff --git a/spec/unit/audit/fetcher/chef_server_spec.rb b/spec/unit/audit/fetcher/chef_server_spec.rb index 1781d048d4..dd00efd567 100644 --- a/spec/unit/audit/fetcher/chef_server_spec.rb +++ b/spec/unit/audit/fetcher/chef_server_spec.rb @@ -1,58 +1,58 @@ -require 'spec_helper' +require "spec_helper" require "chef/audit/fetcher/chef_server" describe Chef::Audit::Fetcher::ChefServer do let(:node) do Chef::Node.new.tap do |n| - n.default['audit'] = {} + n.default["audit"] = {} end end before :each do allow(Chef).to receive(:node).and_return(node) - Chef::Config[:chef_server_url] = 'http://127.0.0.1:8889/organizations/my_org' + Chef::Config[:chef_server_url] = "http://127.0.0.1:8889/organizations/my_org" end describe ".resolve" do - context 'when target is a string' do - it 'should resolve a compliance URL' do - res = Chef::Audit::Fetcher::ChefServer.resolve('compliance://namespace/profile_name') + context "when target is a string" do + it "should resolve a compliance URL" do + res = Chef::Audit::Fetcher::ChefServer.resolve("compliance://namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) expected = "http://127.0.0.1:8889/organizations/my_org/owners/namespace/compliance/profile_name/tar" expect(res.target).to eq(expected) end - it 'should add /compliance URL prefix if needed' do - node.default['audit']['fetcher'] = 'chef-server' - res = Chef::Audit::Fetcher::ChefServer.resolve('compliance://namespace/profile_name') + it "should add /compliance URL prefix if needed" do + node.default["audit"]["fetcher"] = "chef-server" + res = Chef::Audit::Fetcher::ChefServer.resolve("compliance://namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) expected = "http://127.0.0.1:8889/compliance/organizations/my_org/owners/namespace/compliance/profile_name/tar" expect(res.target).to eq(expected) end - it 'includes user in the URL if present' do - res = Chef::Audit::Fetcher::ChefServer.resolve('compliance://username@namespace/profile_name') + it "includes user in the URL if present" do + res = Chef::Audit::Fetcher::ChefServer.resolve("compliance://username@namespace/profile_name") expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) expected = "http://127.0.0.1:8889/organizations/my_org/owners/username@namespace/compliance/profile_name/tar" expect(res.target).to eq(expected) end - it 'returns nil with a non-compliance URL' do - res = Chef::Audit::Fetcher::ChefServer.resolve('http://github.com/chef-cookbooks/audit') + it "returns nil with a non-compliance URL" do + res = Chef::Audit::Fetcher::ChefServer.resolve("http://github.com/chef-cookbooks/audit") expect(res).to eq(nil) end end - context 'when target is a hash' do - it 'should resolve a target with a version' do + context "when target is a hash" do + it "should resolve a target with a version" do res = Chef::Audit::Fetcher::ChefServer.resolve( - compliance: 'namespace/profile_name', - version: '1.2.3', + compliance: "namespace/profile_name", + version: "1.2.3" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) @@ -60,9 +60,9 @@ describe Chef::Audit::Fetcher::ChefServer do expect(res.target).to eq(expected) end - it 'should resolve a target without a version' do + it "should resolve a target without a version" do res = Chef::Audit::Fetcher::ChefServer.resolve( - compliance: 'namespace/profile_name', + compliance: "namespace/profile_name" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) @@ -70,9 +70,9 @@ describe Chef::Audit::Fetcher::ChefServer do expect(res.target).to eq(expected) end - it 'includes user in the URL if present' do + it "includes user in the URL if present" do res = Chef::Audit::Fetcher::ChefServer.resolve( - compliance: 'username@namespace/profile_name', + compliance: "username@namespace/profile_name" ) expect(res).to be_kind_of(Chef::Audit::Fetcher::ChefServer) @@ -80,10 +80,10 @@ describe Chef::Audit::Fetcher::ChefServer do expect(res.target).to eq(expected) end - it 'returns nil with a non-profile Hash' do + it "returns nil with a non-profile Hash" do res = Chef::Audit::Fetcher::ChefServer.resolve( - profile: 'namespace/profile_name', - version: '1.2.3' + profile: "namespace/profile_name", + version: "1.2.3" ) expect(res).to eq(nil) diff --git a/spec/unit/audit/reporter/audit_enforcer_spec.rb b/spec/unit/audit/reporter/audit_enforcer_spec.rb index ef3cb5c43a..c29cb4a946 100644 --- a/spec/unit/audit/reporter/audit_enforcer_spec.rb +++ b/spec/unit/audit/reporter/audit_enforcer_spec.rb @@ -1,15 +1,15 @@ -require 'spec_helper' +require "spec_helper" describe Chef::Audit::Reporter::AuditEnforcer do let(:reporter) { Chef::Audit::Reporter::AuditEnforcer.new } - it 'does not raise error for a successful InSpec report' do + it "does not raise error for a successful InSpec report" do report = { "profiles": [ { "controls": [ - { "id": 'c1', "results": [{ "status": 'passed' }] }, - { "id": 'c2', "results": [{ "status": 'passed' }] }, + { "id": "c1", "results": [{ "status": "passed" }] }, + { "id": "c2", "results": [{ "status": "passed" }] }, ], }, ], @@ -18,24 +18,24 @@ describe Chef::Audit::Reporter::AuditEnforcer do expect(reporter.send_report(report)).to eq(true) end - it 'does not raise error for an InSpec report with no controls' do - report = { "profiles": [{ "name": 'empty' }] } + it "does not raise error for an InSpec report with no controls" do + report = { "profiles": [{ "name": "empty" }] } expect(reporter.send_report(report)).to eq(true) end - it 'does not raise error for an InSpec report with controls but no results' do - report = { "profiles": [{ "controls": [{ "id": 'empty' }] }] } + it "does not raise error for an InSpec report with controls but no results" do + report = { "profiles": [{ "controls": [{ "id": "empty" }] }] } expect(reporter.send_report(report)).to eq(true) end - it 'raises an error for a failed InSpec report' do + it "raises an error for a failed InSpec report" do report = { "profiles": [ { "controls": [ - { "id": 'c1', "results": [{ "status": 'passed' }] }, - { "id": 'c2', "results": [{ "status": 'failed' }] }, + { "id": "c1", "results": [{ "status": "passed" }] }, + { "id": "c2", "results": [{ "status": "failed" }] }, ], }, ], @@ -43,6 +43,6 @@ describe Chef::Audit::Reporter::AuditEnforcer do expect { reporter.send_report(report) - }.to raise_error(Chef::Audit::Reporter::AuditEnforcer::ControlFailure, 'Audit c2 has failed. Aborting chef-client run.') + }.to raise_error(Chef::Audit::Reporter::AuditEnforcer::ControlFailure, "Audit c2 has failed. Aborting chef-client run.") end end diff --git a/spec/unit/audit/reporter/automate_spec.rb b/spec/unit/audit/reporter/automate_spec.rb index 18e37aed8f..7f3e35a357 100644 --- a/spec/unit/audit/reporter/automate_spec.rb +++ b/spec/unit/audit/reporter/automate_spec.rb @@ -1,11 +1,11 @@ -require 'spec_helper' -require 'json' # For .to_json +require "spec_helper" +require "json" # For .to_json describe Chef::Audit::Reporter::Automate do before :each do WebMock.disable_net_connect! - Chef::Config[:data_collector] = { token: token, server_url: 'https://automate.test/data_collector' } + Chef::Config[:data_collector] = { token: token, server_url: "https://automate.test/data_collector" } end let(:token) { "fake_token" } @@ -14,173 +14,173 @@ describe Chef::Audit::Reporter::Automate do let(:opts) do { - entity_uuid: 'aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz', - run_id: '3f0536f7-3361-4bca-ae53-b45118dceb5d', + entity_uuid: "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz", + run_id: "3f0536f7-3361-4bca-ae53-b45118dceb5d", node_info: { - node: 'chef-client.solo', - environment: 'My Prod Env', - roles: %w(base_linux apache_linux), - recipes: ['some_cookbook::some_recipe', 'some_cookbook'], - policy_name: 'test_policy_name', - policy_group: 'test_policy_group', - chef_tags: ['mylinux', 'my.tag', 'some=tag'], - organization_name: 'test_org', - source_fqdn: 'api.chef.io', - ipaddress: '192.168.56.33', - fqdn: 'lb1.prod.example.com', + node: "chef-client.solo", + environment: "My Prod Env", + roles: %w{base_linux apache_linux}, + recipes: ["some_cookbook::some_recipe", "some_cookbook"], + policy_name: "test_policy_name", + policy_group: "test_policy_group", + chef_tags: ["mylinux", "my.tag", "some=tag"], + organization_name: "test_org", + source_fqdn: "api.chef.io", + ipaddress: "192.168.56.33", + fqdn: "lb1.prod.example.com", }, run_time_limit: 1.0, control_results_limit: 2, - timestamp: Time.parse('2016-07-19T19:19:19+01:00'), + timestamp: Time.parse("2016-07-19T19:19:19+01:00"), } end let(:inspec_report) do { - "version": '1.2.1', + "version": "1.2.1", "profiles": - [{ "name": 'tmp_compliance_profile', - "title": '/tmp Compliance Profile', - "summary": 'An Example Compliance Profile', - "sha256": '7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd', - "version": '0.1.1', - "maintainer": 'Nathen Harvey <nharvey@chef.io>', - "license": 'Apache 2.0 License', - "copyright": 'Nathen Harvey <nharvey@chef.io>', + [{ "name": "tmp_compliance_profile", + "title": "/tmp Compliance Profile", + "summary": "An Example Compliance Profile", + "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd", + "version": "0.1.1", + "maintainer": "Nathen Harvey <nharvey@chef.io>", + "license": "Apache 2.0 License", + "copyright": "Nathen Harvey <nharvey@chef.io>", "supports": [], "controls": - [{ "title": 'A /tmp directory must exist', - "desc": 'A /tmp directory must exist', + [{ "title": "A /tmp directory must exist", + "desc": "A /tmp directory must exist", "impact": 0.3, "refs": [], "tags": {}, "code": "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 3 }, - "id": 'tmp-1.0', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 }, + "id": "tmp-1.0", "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be directory', "run_time": 0.002312, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }, ], }, - { "title": '/tmp directory is owned by the root user', - "desc": 'The /tmp directory must be owned by the root user', + { "title": "/tmp directory is owned by the root user", + "desc": "The /tmp directory must be owned by the root user", "impact": 0.3, - "refs": [{ "url": 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf', "ref": 'Compliance Whitepaper' }], - "tags": { "production": nil, "development": nil, "identifier": 'value', "remediation": 'https://github.com/chef-cookbooks/audit' }, + "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }], + "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" }, "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 12 }, - "id": 'tmp-1.1', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 }, + "id": "tmp-1.1", "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'skipped', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'failed', "code_desc": 'File /etc/hosts is expected to be directory', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400', "message": 'expected `File /etc/hosts.directory?` to return true, got false' }, + { "status": "passed", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" }, ], }, ], - "groups": [{ "title": '/tmp Compliance Profile', "controls": ['tmp-1.0', 'tmp-1.1'], "id": 'controls/tmp.rb' }], - "attributes": [{ "name": 'syslog_pkg', "options": { "default": 'rsyslog', "description": 'syslog package...' } }] }], + "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }], + "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }] }], "other_checks": [], - "statistics": { "duration": 0.032332 } + "statistics": { "duration": 0.032332 }, } end let(:enriched_report) do { - "version": '1.2.1', + "version": "1.2.1", "profiles": [ { - "name": 'tmp_compliance_profile', - "title": '/tmp Compliance Profile', - "summary": 'An Example Compliance Profile', - "sha256": '7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd', - "version": '0.1.1', - "maintainer": 'Nathen Harvey <nharvey@chef.io>', - "license": 'Apache 2.0 License', - "copyright": 'Nathen Harvey <nharvey@chef.io>', + "name": "tmp_compliance_profile", + "title": "/tmp Compliance Profile", + "summary": "An Example Compliance Profile", + "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd", + "version": "0.1.1", + "maintainer": "Nathen Harvey <nharvey@chef.io>", + "license": "Apache 2.0 License", + "copyright": "Nathen Harvey <nharvey@chef.io>", "supports": [], "controls": [ { - "title": 'A /tmp directory must exist', - "desc": 'A /tmp directory must exist', + "title": "A /tmp directory must exist", + "desc": "A /tmp directory must exist", "impact": 0.3, "refs": [], "tags": {}, "code": "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 3 }, - "id": 'tmp-1.0', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 }, + "id": "tmp-1.0", "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be directory', "run_time": 0.002312, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }, ], }, { - "title": '/tmp directory is owned by the root user', - "desc": 'The /tmp directory must be owned by the root user', + "title": "/tmp directory is owned by the root user", + "desc": "The /tmp directory must be owned by the root user", "impact": 0.3, "refs": [ - { "url": 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf', "ref": 'Compliance Whitepaper' }, + { "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }, ], - "tags": { "production": nil, "development": nil, "identifier": 'value', "remediation": 'https://github.com/chef-cookbooks/audit' }, + "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" }, "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 12 }, - "id": 'tmp-1.1', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 }, + "id": "tmp-1.1", "results": [ - { "status": 'failed', "code_desc": 'File /etc/hosts is expected to be directory', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400', "message": 'expected `File /etc/hosts.directory?` to return true, got false' }, - { "status": 'skipped', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" }, + { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, ], "removed_results_counts": { "failed": 0, "skipped": 0, "passed": 1 }, }, ], "groups": [ - { "title": '/tmp Compliance Profile', "controls": ['tmp-1.0', 'tmp-1.1'], "id": 'controls/tmp.rb' }, + { "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }, ], "attributes": [ - { "name": 'syslog_pkg', "options": { "default": 'rsyslog', "description": 'syslog package...' } }, + { "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }, ], }, ], "other_checks": [], "statistics": { "duration": 0.032332 }, - "type": 'inspec_report', - "node_name": 'chef-client.solo', - "end_time": '2016-07-19T18:19:19Z', - "node_uuid": 'aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz', - "environment": 'My Prod Env', - "roles": %w(base_linux apache_linux), - "recipes": ['some_cookbook::some_recipe', 'some_cookbook'], - "report_uuid": '3f0536f7-3361-4bca-ae53-b45118dceb5d', - "source_fqdn": 'api.chef.io', - "organization_name": 'test_org', - "policy_group": 'test_policy_group', - "policy_name": 'test_policy_name', - "chef_tags": ['mylinux', 'my.tag', 'some=tag'], - "ipaddress": '192.168.56.33', - "fqdn": 'lb1.prod.example.com', + "type": "inspec_report", + "node_name": "chef-client.solo", + "end_time": "2016-07-19T18:19:19Z", + "node_uuid": "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz", + "environment": "My Prod Env", + "roles": %w{base_linux apache_linux}, + "recipes": ["some_cookbook::some_recipe", "some_cookbook"], + "report_uuid": "3f0536f7-3361-4bca-ae53-b45118dceb5d", + "source_fqdn": "api.chef.io", + "organization_name": "test_org", + "policy_group": "test_policy_group", + "policy_name": "test_policy_name", + "chef_tags": ["mylinux", "my.tag", "some=tag"], + "ipaddress": "192.168.56.33", + "fqdn": "lb1.prod.example.com", } end describe "#send_report" do - it 'sends report successfully to ChefAutomate' do - metasearch_stub = stub_request(:post, 'https://automate.test/compliance/profiles/metasearch') + it "sends report successfully to ChefAutomate" do + metasearch_stub = stub_request(:post, "https://automate.test/compliance/profiles/metasearch") .with( body: '{"sha256": ["7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd"]}', headers: { - 'Accept-Encoding' => 'identity', - 'X-Chef-Version' => Chef::VERSION, - 'X-Data-Collector-Auth' => 'version=1.0', - 'X-Data-Collector-Token' => token + "Accept-Encoding" => "identity", + "X-Chef-Version" => Chef::VERSION, + "X-Data-Collector-Auth" => "version=1.0", + "X-Data-Collector-Token" => token, } ).to_return( status: 200, body: '{"missing_sha256": ["7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd"]}' ) - report_stub = stub_request(:post, 'https://automate.test/data_collector') + report_stub = stub_request(:post, "https://automate.test/data_collector") .with( body: enriched_report, headers: { - 'Accept-Encoding' => 'identity', - 'X-Chef-Version' => Chef::VERSION, - 'X-Data-Collector-Auth' => 'version=1.0', - 'X-Data-Collector-Token' => token + "Accept-Encoding" => "identity", + "X-Chef-Version" => Chef::VERSION, + "X-Data-Collector-Auth" => "version=1.0", + "X-Data-Collector-Token" => token, } ).to_return(status: 200) @@ -190,7 +190,7 @@ describe Chef::Audit::Reporter::Automate do expect(report_stub).to have_been_requested end - it 'does not send report when entity_uuid is missing' do + it "does not send report when entity_uuid is missing" do opts.delete(:entity_uuid) reporter = Chef::Audit::Reporter::Automate.new(opts) expect(reporter.send_report(inspec_report)).to eq(false) @@ -200,64 +200,64 @@ describe Chef::Audit::Reporter::Automate do describe "#truncate_controls_results" do let(:report) do { - "version": '1.2.1', + "version": "1.2.1", "profiles": - [{ "name": 'tmp_compliance_profile', - "title": '/tmp Compliance Profile', - "summary": 'An Example Compliance Profile', - "sha256": '7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215ff', - "version": '0.1.1', - "maintainer": 'Nathen Harvey <nharvey@chef.io>', - "license": 'Apache 2.0 License', - "copyright": 'Nathen Harvey <nharvey@chef.io>', + [{ "name": "tmp_compliance_profile", + "title": "/tmp Compliance Profile", + "summary": "An Example Compliance Profile", + "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215ff", + "version": "0.1.1", + "maintainer": "Nathen Harvey <nharvey@chef.io>", + "license": "Apache 2.0 License", + "copyright": "Nathen Harvey <nharvey@chef.io>", "supports": [], "controls": - [{ "id": 'tmp-2.0', - "title": 'A bunch of directories must exist', - "desc": 'A bunch of directories must exist for testing', + [{ "id": "tmp-2.0", + "title": "A bunch of directories must exist", + "desc": "A bunch of directories must exist for testing", "impact": 0.3, "refs": [], "tags": {}, "code": "control 'tmp-2.0' do\n impact 0.3\n title 'A bunch of directories must exist'\n desc 'A bunch of directories must exist for testing'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 3 }, + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 }, "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be directory', "run_time": 0.002312, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'passed', "code_desc": 'File /etc should be directory', "run_time": 0.002314, "start_time": '2016-10-19 11:09:45 -0400' }, - { "status": 'passed', "code_desc": 'File /opt should be directory', "run_time": 0.002315, "start_time": '2016-10-19 11:09:46 -0400' }, - { "status": 'skipped', "code_desc": 'No-op', "run_time": 0.002316, "start_time": '2016-10-19 11:09:44 -0400', "skip_message": '4 testing' }, - { "status": 'skipped', "code_desc": 'No-op', "run_time": 0.002317, "start_time": '2016-10-19 11:09:44 -0400', "skip_message": '4 testing' }, - { "status": 'skipped', "code_desc": 'No-op', "run_time": 0.002318, "start_time": '2016-10-19 11:09:44 -0400', "skip_message": '4 testing' }, - { "status": 'failed', "code_desc": 'File /etc/passwd should be directory', "run_time": 0.002313, "start_time": '2016-10-19 11:09:44 -0400' }, - { "status": 'failed', "code_desc": 'File /etc/passwd should be directory', "run_time": 0.002313, "start_time": '2016-10-19 11:09:44 -0400' }, - { "status": 'failed', "code_desc": 'File /etc/passwd should be directory', "run_time": 0.002313, "start_time": '2016-10-19 11:09:44 -0400' }, + { "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "passed", "code_desc": "File /etc should be directory", "run_time": 0.002314, "start_time": "2016-10-19 11:09:45 -0400" }, + { "status": "passed", "code_desc": "File /opt should be directory", "run_time": 0.002315, "start_time": "2016-10-19 11:09:46 -0400" }, + { "status": "skipped", "code_desc": "No-op", "run_time": 0.002316, "start_time": "2016-10-19 11:09:44 -0400", "skip_message": "4 testing" }, + { "status": "skipped", "code_desc": "No-op", "run_time": 0.002317, "start_time": "2016-10-19 11:09:44 -0400", "skip_message": "4 testing" }, + { "status": "skipped", "code_desc": "No-op", "run_time": 0.002318, "start_time": "2016-10-19 11:09:44 -0400", "skip_message": "4 testing" }, + { "status": "failed", "code_desc": "File /etc/passwd should be directory", "run_time": 0.002313, "start_time": "2016-10-19 11:09:44 -0400" }, + { "status": "failed", "code_desc": "File /etc/passwd should be directory", "run_time": 0.002313, "start_time": "2016-10-19 11:09:44 -0400" }, + { "status": "failed", "code_desc": "File /etc/passwd should be directory", "run_time": 0.002313, "start_time": "2016-10-19 11:09:44 -0400" }, ], }, - { "id": 'tmp-2.1', - "title": '/tmp directory is owned by the root user', - "desc": 'The /tmp directory must be owned by the root user', + { "id": "tmp-2.1", + "title": "/tmp directory is owned by the root user", + "desc": "The /tmp directory must be owned by the root user", "impact": 0.3, - "refs": [{ "url": 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf', "ref": 'Compliance Whitepaper' }], - "tags": { "production": nil, "development": nil, "identifier": 'value', "remediation": 'https://github.com/chef-cookbooks/audit' }, + "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }], + "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" }, "code": "control 'tmp-2.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 12 }, + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 }, "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'passed', "code_desc": 'File /etc should be owned by "root"', "run_time": 1.238845, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "passed", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "passed", "code_desc": 'File /etc should be owned by "root"', "run_time": 1.238845, "start_time": "2016-10-19 11:09:43 -0400" }, ], }, ], - "groups": [{ "title": '/tmp Compliance Profile', "controls": ['tmp-1.0', 'tmp-1.1'], "id": 'controls/tmp.rb' }], - "attributes": [{ "name": 'syslog_pkg', "options": { "default": 'rsyslog', "description": 'syslog package...' } }] }], + "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }], + "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }] }], "other_checks": [], - "statistics": { "duration": 0.032332 } + "statistics": { "duration": 0.032332 }, } end - it 'truncates controls results 1' do + it "truncates controls results 1" do truncated_report = reporter.truncate_controls_results(report, 5) expect(truncated_report[:profiles][0][:controls][0][:results].length).to eq(5) statuses = truncated_report[:profiles][0][:controls][0][:results].map { |r| r[:status] } - expect(statuses).to eq(%w(failed failed failed skipped skipped)) + expect(statuses).to eq(%w{failed failed failed skipped skipped}) expect(truncated_report[:profiles][0][:controls][0][:removed_results_counts]).to eq(failed: 0, skipped: 1, passed: 3) end @@ -265,7 +265,7 @@ describe Chef::Audit::Reporter::Automate do truncated_report = reporter.truncate_controls_results(report, 5) expect(truncated_report[:profiles][0][:controls][1][:results].length).to eq(2) statuses = truncated_report[:profiles][0][:controls][1][:results].map { |r| r[:status] } - expect(statuses).to eq(%w(passed passed)) + expect(statuses).to eq(%w{passed passed}) expect(truncated_report[:profiles][0][:controls][1][:removed_results_counts]).to eq(nil) end diff --git a/spec/unit/audit/reporter/chef_server_automate_spec.rb b/spec/unit/audit/reporter/chef_server_automate_spec.rb index e715dcf588..46dacd812d 100644 --- a/spec/unit/audit/reporter/chef_server_automate_spec.rb +++ b/spec/unit/audit/reporter/chef_server_automate_spec.rb @@ -1,172 +1,172 @@ -require 'spec_helper' +require "spec_helper" describe Chef::Audit::Reporter::ChefServerAutomate do before do WebMock.disable_net_connect! - Chef::Config[:client_key] = File.expand_path('../../../data/ssl/private_key.pem', __dir__) - Chef::Config[:node_name] = 'spec-node' + Chef::Config[:client_key] = File.expand_path("../../../data/ssl/private_key.pem", __dir__) + Chef::Config[:node_name] = "spec-node" end let(:reporter) { Chef::Audit::Reporter::ChefServerAutomate.new(opts) } let(:opts) do { - entity_uuid: 'aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz', - run_id: '3f0536f7-3361-4bca-ae53-b45118dceb5d', + entity_uuid: "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz", + run_id: "3f0536f7-3361-4bca-ae53-b45118dceb5d", node_info: { - node: 'chef-client.solo', - environment: 'My Prod Env', - roles: %w(base_linux apache_linux), - recipes: ['some_cookbook::some_recipe', 'some_cookbook'], - policy_name: 'test_policy_name', - policy_group: 'test_policy_group', - chef_tags: ['mylinux', 'my.tag', 'some=tag'], - organization_name: 'test_org', - source_fqdn: 'api.chef.io', - ipaddress: '192.168.56.33', - fqdn: 'lb1.prod.example.com', + node: "chef-client.solo", + environment: "My Prod Env", + roles: %w{base_linux apache_linux}, + recipes: ["some_cookbook::some_recipe", "some_cookbook"], + policy_name: "test_policy_name", + policy_group: "test_policy_group", + chef_tags: ["mylinux", "my.tag", "some=tag"], + organization_name: "test_org", + source_fqdn: "api.chef.io", + ipaddress: "192.168.56.33", + fqdn: "lb1.prod.example.com", }, - url: 'https://chef.server/data_collector', + url: "https://chef.server/data_collector", control_results_limit: 2, - timestamp: Time.parse('2016-07-19T19:19:19+01:00'), + timestamp: Time.parse("2016-07-19T19:19:19+01:00"), } end let(:inspec_report) do { - "version": '1.2.1', + "version": "1.2.1", "profiles": - [{ "name": 'tmp_compliance_profile', - "title": '/tmp Compliance Profile', - "summary": 'An Example Compliance Profile', - "sha256": '7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd', - "version": '0.1.1', - "maintainer": 'Nathen Harvey <nharvey@chef.io>', - "license": 'Apache 2.0 License', - "copyright": 'Nathen Harvey <nharvey@chef.io>', + [{ "name": "tmp_compliance_profile", + "title": "/tmp Compliance Profile", + "summary": "An Example Compliance Profile", + "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd", + "version": "0.1.1", + "maintainer": "Nathen Harvey <nharvey@chef.io>", + "license": "Apache 2.0 License", + "copyright": "Nathen Harvey <nharvey@chef.io>", "supports": [], "controls": - [{ "title": 'A /tmp directory must exist', - "desc": 'A /tmp directory must exist', + [{ "title": "A /tmp directory must exist", + "desc": "A /tmp directory must exist", "impact": 0.3, "refs": [], "tags": {}, "code": "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 3 }, - "id": 'tmp-1.0', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 }, + "id": "tmp-1.0", "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be directory', "run_time": 0.002312, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }, ], }, - { "title": '/tmp directory is owned by the root user', - "desc": 'The /tmp directory must be owned by the root user', + { "title": "/tmp directory is owned by the root user", + "desc": "The /tmp directory must be owned by the root user", "impact": 0.3, - "refs": [{ "url": 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf', "ref": 'Compliance Whitepaper' }], - "tags": { "production": nil, "development": nil, "identifier": 'value', "remediation": 'https://github.com/chef-cookbooks/audit' }, + "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }], + "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" }, "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 12 }, - "id": 'tmp-1.1', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 }, + "id": "tmp-1.1", "results": [ - { "status": 'passed', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'skipped', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, - { "status": 'failed', "code_desc": 'File /etc/hosts is expected to be directory', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400', "message": 'expected `File /etc/hosts.directory?` to return true, got false' }, + { "status": "passed", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, + { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" }, ], }, ], - "groups": [{ "title": '/tmp Compliance Profile', "controls": ['tmp-1.0', 'tmp-1.1'], "id": 'controls/tmp.rb' }], - "attributes": [{ "name": 'syslog_pkg', "options": { "default": 'rsyslog', "description": 'syslog package...' } }] }], + "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }], + "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }] }], "other_checks": [], - "statistics": { "duration": 0.032332 } + "statistics": { "duration": 0.032332 }, } end let(:enriched_report) do { - "version": '1.2.1', + "version": "1.2.1", "profiles": [ { - "name": 'tmp_compliance_profile', - "title": '/tmp Compliance Profile', - "summary": 'An Example Compliance Profile', - "sha256": '7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd', - "version": '0.1.1', - "maintainer": 'Nathen Harvey <nharvey@chef.io>', - "license": 'Apache 2.0 License', - "copyright": 'Nathen Harvey <nharvey@chef.io>', + "name": "tmp_compliance_profile", + "title": "/tmp Compliance Profile", + "summary": "An Example Compliance Profile", + "sha256": "7bd598e369970002fc6f2d16d5b988027d58b044ac3fa30ae5fc1b8492e215cd", + "version": "0.1.1", + "maintainer": "Nathen Harvey <nharvey@chef.io>", + "license": "Apache 2.0 License", + "copyright": "Nathen Harvey <nharvey@chef.io>", "supports": [], "controls": [ { - "title": 'A /tmp directory must exist', - "desc": 'A /tmp directory must exist', + "title": "A /tmp directory must exist", + "desc": "A /tmp directory must exist", "impact": 0.3, "refs": [], "tags": {}, "code": "control 'tmp-1.0' do\n impact 0.3\n title 'A /tmp directory must exist'\n desc 'A /tmp directory must exist'\n describe file '/tmp' do\n it { should be_directory }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 3 }, - "id": 'tmp-1.0', - "results": [{ "status": 'passed', "code_desc": 'File /tmp should be directory', "run_time": 0.002312, "start_time": '2016-10-19 11:09:43 -0400' }], + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 3 }, + "id": "tmp-1.0", + "results": [{ "status": "passed", "code_desc": "File /tmp should be directory", "run_time": 0.002312, "start_time": "2016-10-19 11:09:43 -0400" }], }, { - "title": '/tmp directory is owned by the root user', - "desc": 'The /tmp directory must be owned by the root user', + "title": "/tmp directory is owned by the root user", + "desc": "The /tmp directory must be owned by the root user", "impact": 0.3, - "refs": [{ "url": 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf', "ref": 'Compliance Whitepaper' }], - "tags": { "production": nil, "development": nil, "identifier": 'value', "remediation": 'https://github.com/chef-cookbooks/audit' }, + "refs": [{ "url": "https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf", "ref": "Compliance Whitepaper" }], + "tags": { "production": nil, "development": nil, "identifier": "value", "remediation": "https://github.com/chef-cookbooks/audit" }, "code": "control 'tmp-1.1' do\n impact 0.3\n title '/tmp directory is owned by the root user'\n desc 'The /tmp directory must be owned by the root user'\n tag 'production','development'\n tag identifier: 'value'\n tag remediation: 'https://github.com/chef-cookbooks/audit'\n ref 'Compliance Whitepaper', url: 'https://pages.chef.io/rs/255-VFB-268/images/compliance-at-velocity2015.pdf'\n describe file '/tmp' do\n it { should be_owned_by 'root' }\n end\nend\n", - "source_location": { "ref": '/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb', "line": 12 }, - "id": 'tmp-1.1', + "source_location": { "ref": "/Users/vjeffrey/code/delivery/insights/data_generator/chef-client/cache/cookbooks/test-cookbook/recipes/../files/default/compliance_profiles/tmp_compliance_profile/controls/tmp.rb", "line": 12 }, + "id": "tmp-1.1", "results": [ - { "status": 'failed', "code_desc": 'File /etc/hosts is expected to be directory', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400', "message": 'expected `File /etc/hosts.directory?` to return true, got false' }, - { "status": 'skipped', "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": '2016-10-19 11:09:43 -0400' }, + { "status": "failed", "code_desc": "File /etc/hosts is expected to be directory", "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400", "message": "expected `File /etc/hosts.directory?` to return true, got false" }, + { "status": "skipped", "code_desc": 'File /tmp should be owned by "root"', "run_time": 1.228845, "start_time": "2016-10-19 11:09:43 -0400" }, ], "removed_results_counts": { "failed": 0, "skipped": 0, "passed": 1 }, }, ], - "groups": [{ "title": '/tmp Compliance Profile', "controls": ['tmp-1.0', 'tmp-1.1'], "id": 'controls/tmp.rb' }], - "attributes": [{ "name": 'syslog_pkg', "options": { "default": 'rsyslog', "description": 'syslog package...' } }], + "groups": [{ "title": "/tmp Compliance Profile", "controls": ["tmp-1.0", "tmp-1.1"], "id": "controls/tmp.rb" }], + "attributes": [{ "name": "syslog_pkg", "options": { "default": "rsyslog", "description": "syslog package..." } }], }, ], "other_checks": [], "statistics": { "duration": 0.032332 }, - "type": 'inspec_report', - "node_name": 'chef-client.solo', - "end_time": '2016-07-19T18:19:19Z', - "node_uuid": 'aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz', - "environment": 'My Prod Env', - "roles": %w(base_linux apache_linux), - "recipes": ['some_cookbook::some_recipe', 'some_cookbook'], - "report_uuid": '3f0536f7-3361-4bca-ae53-b45118dceb5d', - "source_fqdn": 'api.chef.io', - "organization_name": 'test_org', - "policy_group": 'test_policy_group', - "policy_name": 'test_policy_name', - "chef_tags": ['mylinux', 'my.tag', 'some=tag'], - "ipaddress": '192.168.56.33', - "fqdn": 'lb1.prod.example.com', + "type": "inspec_report", + "node_name": "chef-client.solo", + "end_time": "2016-07-19T18:19:19Z", + "node_uuid": "aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz", + "environment": "My Prod Env", + "roles": %w{base_linux apache_linux}, + "recipes": ["some_cookbook::some_recipe", "some_cookbook"], + "report_uuid": "3f0536f7-3361-4bca-ae53-b45118dceb5d", + "source_fqdn": "api.chef.io", + "organization_name": "test_org", + "policy_group": "test_policy_group", + "policy_name": "test_policy_name", + "chef_tags": ["mylinux", "my.tag", "some=tag"], + "ipaddress": "192.168.56.33", + "fqdn": "lb1.prod.example.com", } end - it 'sends report successfully' do + it "sends report successfully" do # TODO: Had to change 'X-Ops-Server-Api-Version' from 1 to 2, is that correct? - report_stub = stub_request(:post, 'https://chef.server/data_collector') + report_stub = stub_request(:post, "https://chef.server/data_collector") .with( body: enriched_report, headers: { - 'X-Chef-Version' => Chef::VERSION, - 'X-Ops-Authorization-1'=> /.+/, - 'X-Ops-Authorization-2'=> /.+/, - 'X-Ops-Authorization-3'=> /.+/, - 'X-Ops-Authorization-4'=> /.+/, - 'X-Ops-Authorization-5'=> /.+/, - 'X-Ops-Authorization-6'=> /.+/, - 'X-Ops-Content-Hash'=>'yfck5nQDcRWta06u45Q+J463LYY=', - 'X-Ops-Server-Api-Version' => '2', - 'X-Ops-Sign' => 'algorithm=sha1;version=1.1;', - 'X-Ops-Timestamp' => /.+/, - 'X-Ops-Userid' => 'spec-node', - 'X-Remote-Request-Id' => /.+/ + "X-Chef-Version" => Chef::VERSION, + "X-Ops-Authorization-1" => /.+/, + "X-Ops-Authorization-2" => /.+/, + "X-Ops-Authorization-3" => /.+/, + "X-Ops-Authorization-4" => /.+/, + "X-Ops-Authorization-5" => /.+/, + "X-Ops-Authorization-6" => /.+/, + "X-Ops-Content-Hash" => "yfck5nQDcRWta06u45Q+J463LYY=", + "X-Ops-Server-Api-Version" => "2", + "X-Ops-Sign" => "algorithm=sha1;version=1.1;", + "X-Ops-Timestamp" => /.+/, + "X-Ops-Userid" => "spec-node", + "X-Remote-Request-Id" => /.+/, } ).to_return(status: 200) diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb index d274b1937d..2b100a33a8 100644 --- a/spec/unit/audit/runner_spec.rb +++ b/spec/unit/audit/runner_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require "spec_helper" describe Chef::Audit::Runner do describe "#enabled?" do |