From 43845a15bd1013e0308a0fc6f84c4d7bca41da8a Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Mon, 17 Oct 2016 09:25:51 -0400 Subject: [PATCH 1/8] use chef handler to run inspec tests --- .kitchen.yml | 2 - attributes/default.rb | 16 +- examples/kitchen/.kitchen.linux.yml | 37 --- examples/kitchen/.kitchen.win.yml | 47 ---- examples/kitchen/Berksfile | 6 - examples/kitchen/Gemfile | 7 - examples/kitchen/README.md | 77 ------ examples/kitchen/cc_report.png | Bin 65522 -> 0 bytes examples/kitchen/visib_reporting.png | Bin 61339 -> 0 bytes examples/visibility_win/.kitchen.yml | 25 -- examples/visibility_win/Berksfile | 4 - examples/visibility_win/README.md | 23 -- examples/visibility_win/metadata.rb | 10 - .../recipes/chef_client_config.rb | 24 -- examples/visibility_win/recipes/default.rb | 6 - examples/visibility_win/spec/spec_helper.rb | 11 - .../unit/recipes/chef_client_config_spec.rb | 22 -- .../spec/unit/recipes/default_spec.rb | 10 - .../default/visibility_ingest.rb.erb | 15 -- .../default/serverspec/default_spec.rb | 2 - examples/wrapper_audit/.kitchen.yml | 49 ---- examples/wrapper_audit/Berksfile | 4 - examples/wrapper_audit/README.md | 26 -- examples/wrapper_audit/metadata.rb | 15 -- examples/wrapper_audit/recipes/default.rb | 15 -- examples/wrapper_audit/spec/spec_helper.rb | 4 - .../spec/unit/recipes/default_spec.rb | 10 - files/default/audit_report.rb | 39 +++ libraries/collector_classes.rb | 235 ------------------ libraries/compliance.rb | 16 -- libraries/helper.rb | 73 ------ libraries/interval.rb | 9 - libraries/matchers.rb | 27 -- libraries/server_api.rb | 40 --- metadata.rb | 1 + recipes/_inspec.rb | 26 -- recipes/default.rb | 96 +------ recipes/upload.rb | 55 ---- resources/inspec.rb | 2 +- resources/profile.rb | 217 ---------------- resources/report.rb | 126 ---------- resources/token.rb | 26 -- 42 files changed, 64 insertions(+), 1391 deletions(-) delete mode 100644 examples/kitchen/.kitchen.linux.yml delete mode 100644 examples/kitchen/.kitchen.win.yml delete mode 100644 examples/kitchen/Berksfile delete mode 100644 examples/kitchen/Gemfile delete mode 100644 examples/kitchen/README.md delete mode 100644 examples/kitchen/cc_report.png delete mode 100644 examples/kitchen/visib_reporting.png delete mode 100644 examples/visibility_win/.kitchen.yml delete mode 100644 examples/visibility_win/Berksfile delete mode 100644 examples/visibility_win/README.md delete mode 100644 examples/visibility_win/metadata.rb delete mode 100644 examples/visibility_win/recipes/chef_client_config.rb delete mode 100644 examples/visibility_win/recipes/default.rb delete mode 100644 examples/visibility_win/spec/spec_helper.rb delete mode 100644 examples/visibility_win/spec/unit/recipes/chef_client_config_spec.rb delete mode 100644 examples/visibility_win/spec/unit/recipes/default_spec.rb delete mode 100644 examples/visibility_win/templates/default/visibility_ingest.rb.erb delete mode 100644 examples/visibility_win/test/integration/default/serverspec/default_spec.rb delete mode 100644 examples/wrapper_audit/.kitchen.yml delete mode 100644 examples/wrapper_audit/Berksfile delete mode 100644 examples/wrapper_audit/README.md delete mode 100644 examples/wrapper_audit/metadata.rb delete mode 100644 examples/wrapper_audit/recipes/default.rb delete mode 100644 examples/wrapper_audit/spec/spec_helper.rb delete mode 100644 examples/wrapper_audit/spec/unit/recipes/default_spec.rb create mode 100644 files/default/audit_report.rb delete mode 100644 libraries/collector_classes.rb delete mode 100644 libraries/compliance.rb delete mode 100644 libraries/helper.rb delete mode 100644 libraries/interval.rb delete mode 100644 libraries/matchers.rb delete mode 100644 libraries/server_api.rb delete mode 100644 recipes/_inspec.rb delete mode 100644 recipes/upload.rb delete mode 100644 resources/profile.rb delete mode 100644 resources/report.rb delete mode 100644 resources/token.rb diff --git a/.kitchen.yml b/.kitchen.yml index 1b838192..a4c709ba 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -64,8 +64,6 @@ suites: attributes: audit: profiles: &profiles - base/ssh: true - base/linux: true - name: compliance # compliance direct reporting run_list: - recipe[audit::default] diff --git a/attributes/default.rb b/attributes/default.rb index ea8f64d4..fdf7de58 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -23,19 +23,19 @@ # Attributes server, insecure and token/refresh_token are only needed for the 'chef-compliance' collector # server format example: 'https://comp-server.example.com/api' default['audit']['server'] = nil + # choose between the permanent refresh_token or ephemeral token(access_token). Needed only for the 'chef-compliance' collector default['audit']['refresh_token'] = nil + # the token(access_token) expires in 12h after creation default['audit']['token'] = nil + # set this insecure attribute to true if the compliance server uses self-signed ssl certificates default['audit']['insecure'] = nil # owner needed for the 'chef-compliance' and 'chef-server' collectors default['audit']['owner'] = nil -default['audit']['quiet'] = nil -default['audit']['profiles'] = {} - # raise exception if Compliance API endpoint is unreachable # while fetching profiles or posting report default['audit']['raise_if_unreachable'] = true @@ -46,11 +46,9 @@ # fail converge after posting report if any audits have failed default['audit']['fail_if_any_audits_failed'] = false -# inspec gem version to install(e.g. '1.1.0') -default['audit']['inspec_version'] = '1.2.0' - # by default run audit every time default['audit']['interval']['enabled'] = false + # by default run compliance once a day default['audit']['interval']['time'] = 1440 @@ -59,3 +57,9 @@ # overwrite existing profile in upload mode default['audit']['overwrite'] = true + +# use json format since this is for reporting +default['audit']['format'] = "json" + +# set profiles to empty array as default +default['audit']['profiles'] = [] \ No newline at end of file diff --git a/examples/kitchen/.kitchen.linux.yml b/examples/kitchen/.kitchen.linux.yml deleted file mode 100644 index bf010077..00000000 --- a/examples/kitchen/.kitchen.linux.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -- name: bento/centos-7.2 -- name: bento/ubuntu-14.04 - -suites: - - name: default - run_list: - - recipe[os-hardening] - - recipe[ssh-hardening] - - recipe[audit::default] - attributes: - audit: - collector: 'chef-compliance' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - owner: admin - # fail converge if downloaded profile is not present - fail_if_not_present: true - # fail converge after posting report if any audits have failed - fail_if_any_audits_failed: false - profiles: - base/linux: true - brewinc/ssh-hardening: - source: supermarket://hardening/ssh-hardening diff --git a/examples/kitchen/.kitchen.win.yml b/examples/kitchen/.kitchen.win.yml deleted file mode 100644 index d0da1e5c..00000000 --- a/examples/kitchen/.kitchen.win.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -- name: windows-2012r2 - -# The following (private) boxes are shared via Atlas and are only -# available to users working for Chef. Sorry, it's about software licensing. -# -# Chef-internal users, you will need to: -# 1. Create an Atlas account: https://atlas.hashicorp.com/ -# 2. Ping #eng-services-support with your Atlas account name -# to be added to the relevant team in Atlas, -# 3. Do `vagrant login` with your Atlas creds so that you can download -# the private boxes. -<% [ '', '-i386' ].each do |win_suffix| %> -- name: windows-2012r2-standard<%= win_suffix %> - driver: - box: chef/windows-server-2012r2-standard # private -<% end %> - -suites: - - name: windows - run_list: - - recipe[audit::default] - attributes: - audit: - collector: 'chef-compliance' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - owner: admin - # fail converge if downloaded profile is not present - fail_if_not_present: true - # fail converge after posting report if any audits have failed - fail_if_any_audits_failed: false - profiles: - base/windows: true diff --git a/examples/kitchen/Berksfile b/examples/kitchen/Berksfile deleted file mode 100644 index 12e6e564..00000000 --- a/examples/kitchen/Berksfile +++ /dev/null @@ -1,6 +0,0 @@ -# encoding: utf-8 -source 'https://supermarket.chef.io' - -cookbook 'os-hardening', git: 'https://github.com/dev-sec/chef-os-hardening.git' -cookbook 'ssh-hardening', git: 'https://github.com/dev-sec/chef-ssh-hardening.git' -cookbook 'audit', path: '../../' diff --git a/examples/kitchen/Gemfile b/examples/kitchen/Gemfile deleted file mode 100644 index 8323966b..00000000 --- a/examples/kitchen/Gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# encoding: utf-8 -source 'https://rubygems.org' - -gem 'berkshelf', '~> 4.3.5' -gem 'test-kitchen', '~> 1.6' -gem 'kitchen-vagrant' -gem 'kitchen-inspec', '~> 0.9' diff --git a/examples/kitchen/README.md b/examples/kitchen/README.md deleted file mode 100644 index b681d160..00000000 --- a/examples/kitchen/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Example: Test-Kitchen - -This example demonstrates the usage of the audit cookbook with test-kitchen. In order to use it, we expect to have `COMPLIANCE_API` and `COMPLIANCE_ACCESSTOKEN` available as environment variables. - -``` -export COMPLIANCE_API='https://compliance.test/api/' -export COMPLIANCE_ACCESSTOKEN='eyJh..GTA' -``` - -If you want to use the refresh token, use the following settings: - -``` -export COMPLIANCE_API='https://compliance.test/api' -export COMPLIANCE_REFRESHTOKEN='40/YUP...mA=='' -``` - -For Windows devs, you can set these environment variables in PowerShell (recommended over user/system variables): -``` -$env:COMPLIANCE_API = "https://compliance.test/api/" -$env:COMPLIANCE_ACCESSTOKEN = "eyJh..GTA" -$env:COMPLIANCE_REFRESHTOKEN = "11/z..==" -``` - -## Converge Linux - -``` - -$ KITCHEN_YAML=.kitchen.linux.yml kitchen list -Instance Driver Provisioner Verifier Transport Last Action -default-bento-centos-72 Vagrant ChefZero Inspec Ssh -default-bento-ubuntu-1404 Vagrant ChefZero Inspec Ssh - -$ KITCHEN_YAML=.kitchen.linux.yml kitchen converge ------> Starting Kitchen (v1.8.0) ------> Converging ... - -... - ------> Converging - -... - ------> Kitchen is finished. (0m35.94s) - -# destroy the instances -$ KITCHEN_YAML=.kitchen.linux.yml kitchen destroy -``` - -## Converge Windows - -``` -$ KITCHEN_YAML=.kitchen.win.yml kitchen list -Instance Driver Provisioner Verifier Transport Last Action -windows-windows-2012r2 Vagrant ChefZero Inspec Winrm - -$ KITCHEN_YAML=.kitchen.win.yml kitchen kitchen converge ------> Starting Kitchen (v1.8.0) ------> Converging - -... - ------> Kitchen is finished. (0m35.94s) - - -# destroy the instances -$ KITCHEN_YAML=.kitchen.win.yml kitchen destroy - -``` - - -Now, the node reports are available in Chef Compliance: - -![Chef Compliance Reports](cc_report.png "Chef Compliance Reports") - -If, configured, the reports are now in Chef Visibility instead: - -![Chef Visibility Reports](visib_reporting.png "Chef Visibility Reports") diff --git a/examples/kitchen/cc_report.png b/examples/kitchen/cc_report.png deleted file mode 100644 index 4749403ed69e10eea88cd3c850c8931e889f8c8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65522 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%0D^$FWVSiGRGPqNNZDyBJ~$e83v@dIg0? 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

9VFXP)=WIn)3Q*) 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 diff --git a/examples/kitchen/visib_reporting.png b/examples/kitchen/visib_reporting.png deleted file mode 100644 index fdb9df215e7d4fdfcdb584d1f0e4ca507d48d6f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61339 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' -# Your token from setting up Visibility -data_collector.token '<%= @auth_token %>' - -# If you want to change the default SSL certificate validation -#ssl_verify_mode :verify_none -#verify_api_cert false diff --git a/examples/visibility_win/test/integration/default/serverspec/default_spec.rb b/examples/visibility_win/test/integration/default/serverspec/default_spec.rb deleted file mode 100644 index 6e0b0df3..00000000 --- a/examples/visibility_win/test/integration/default/serverspec/default_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -# encoding: utf-8 -require 'spec_helper' diff --git a/examples/wrapper_audit/.kitchen.yml b/examples/wrapper_audit/.kitchen.yml deleted file mode 100644 index 80837df9..00000000 --- a/examples/wrapper_audit/.kitchen.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -# Your vagrant box name of a windows machines you have privately sourced -- name: windows2012r2 - driver: - # Your box or box_url should also be a privately hosted NFS, or URL, - # to publish your private Windows boxes - box: /vagrant/windows2012r2 - box_url: http://boxshare.yourdomain.com/vagrant/windows2012r2 - ostype: windows - shell_type: powershell - transport: - name: winrm - -# If you need to test a Linux-based profile, call a public box, such as this one. -- name: ubuntu-14.04 - driver: - box: bento/ubuntu-14.04 - -suites: - - name: windows - run_list: - # The run_list should be the wrapper cookbook. - - recipe[wrapper_audit::default] - attributes: - audit: - collector: 'chef-visibility' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - # The owner should show up in the bottom-left of the home page of Compliance. - # If it is integrated with Chef Server, it will be the Chef Server org-name - owner: yourchef-orgname - profiles: - # Example default profile already in Compliance. - base/windows: true - # If you create and import a custom profile you wrote, you can also add it. - yourchef-orgname/customprofilename: true diff --git a/examples/wrapper_audit/Berksfile b/examples/wrapper_audit/Berksfile deleted file mode 100644 index f5f96eab..00000000 --- a/examples/wrapper_audit/Berksfile +++ /dev/null @@ -1,4 +0,0 @@ -# encoding: utf-8 -source 'https://supermarket.chef.io' - -metadata diff --git a/examples/wrapper_audit/README.md b/examples/wrapper_audit/README.md deleted file mode 100644 index 248e7a43..00000000 --- a/examples/wrapper_audit/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Example: Wrapper cookbook for `Audit` -This example cookbook demonstrates how you could wrap the audit cookbook with a customizable internal cookbook. This might be done to easily change default attributes set in the audit cookbook. The wrapper also helps you control the versioning of the audit cookbook in your environment. It can also be useful to help create roles to target where the audit cookbook applies, or even set attributes on nodes to apply Compliance profiles (if you had some you want to run on all machines). - -## Requirements - -### Platforms -- Windows Server 2008 R2 -- Windows Server 2012 -- Windows Server 2012 R2 -- Ubuntu 12.04 -- Ubuntu 14.04 - -### Chef -- Chef 12+ - -### Cookbooks -- `audit` -- `visibility_win` - -## Attributes -There are no custom attributes for this cookbook. - -## Usage -Include `wrapper_audit::default` in a node's `run_list`. This will also pull down the community audit cookbook, which is used to run Chef Compliance profiles. These profiles will create a report and send it to Chef Compliance or Visibility, depending on your [`audit`][`collector`] setting. - -This cookbook also consumes the example cookbook `visibility_win`, which demonstrates how to setup chef-client to ingest Visibility data. diff --git a/examples/wrapper_audit/metadata.rb b/examples/wrapper_audit/metadata.rb deleted file mode 100644 index 99e973e2..00000000 --- a/examples/wrapper_audit/metadata.rb +++ /dev/null @@ -1,15 +0,0 @@ -# encoding: utf-8 -name 'wrapper_audit' -maintainer 'Your Organization' -maintainer_email 'yourorganizationemail@domain.com' -license 'Proprietary - All Rights Reserved' -description 'Wrapper cookbook that runs Audit cookbook.' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '0.1.0' - -# Put whatever operating systems your company supports where you may want -# to use Compliance profiles -supports 'windows' - -depends 'audit', '>= 0.14.1' -depends 'visibility_win', '>=0.1.8' diff --git a/examples/wrapper_audit/recipes/default.rb b/examples/wrapper_audit/recipes/default.rb deleted file mode 100644 index 54e62f51..00000000 --- a/examples/wrapper_audit/recipes/default.rb +++ /dev/null @@ -1,15 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: wrapper_audit -# Recipe:: default - -# This includes statement is to include the chef_client_config recipe in the -# visibility_win cookbook, which is another sample cookbook under the -# examples directory. The visibility_win cookbook provides an example of -# how you would setup chef-client to send converge data to your -# Chef Visibility server. -include_recipe 'visibility_win::chef_client_config' -# Set the collector to chef-visibility instead of the default chef-server. -node.default['audit']['collector'] = 'chef-visibility' -# Execute the community audit cookbook with the collector set -include_recipe 'audit::default' diff --git a/examples/wrapper_audit/spec/spec_helper.rb b/examples/wrapper_audit/spec/spec_helper.rb deleted file mode 100644 index a1e2776c..00000000 --- a/examples/wrapper_audit/spec/spec_helper.rb +++ /dev/null @@ -1,4 +0,0 @@ -# encoding: utf-8 -require 'chefspec' -require 'chefspec/berkshelf' -ChefSpec::Coverage.start! diff --git a/examples/wrapper_audit/spec/unit/recipes/default_spec.rb b/examples/wrapper_audit/spec/unit/recipes/default_spec.rb deleted file mode 100644 index 38c8633a..00000000 --- a/examples/wrapper_audit/spec/unit/recipes/default_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: wrapper_audit -# Spec:: default - -require 'spec_helper' - -describe 'wrapper_audit::default' do - let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) } -end diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb new file mode 100644 index 00000000..063dab7b --- /dev/null +++ b/files/default/audit_report.rb @@ -0,0 +1,39 @@ +require 'chef/handler' + +class Chef + class Handler + # Creates a compliance audit report + class AuditReport < ::Chef::Handler + def report + load_needed_dependencies + call + end + + def load_needed_dependencies + require "inspec" + # load supermarket plugin, this is part of the inspec gem + require "bundles/inspec-supermarket/api" + require "bundles/inspec-supermarket/target" + + # load the compliance plugin + require "bundles/inspec-compliance/configuration" + require "bundles/inspec-compliance/support" + require "bundles/inspec-compliance/http" + require "bundles/inspec-compliance/api" + require "bundles/inspec-compliance/target" + end + + def call + Chef::Log.debug "Initialize InSpec" + opts = { "format" => node['audit']['format'] } + runner = ::Inspec::Runner.new(opts) + + tests = node['audit']['profiles'] + tests.each { |target| runner.add_target(target, opts) } + + Chef::Log.debug "Running tests from: #{tests.inspect}" + exit_code = runner.run + end + end + end +end \ No newline at end of file diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb deleted file mode 100644 index 5e2adfd4..00000000 --- a/libraries/collector_classes.rb +++ /dev/null @@ -1,235 +0,0 @@ -# encoding: utf-8 -require 'json' -require_relative 'helper' - -class Collector - # - # Used to send inspec reports to Chef Visibility via the data_collector service - # - class ChefVisibility - @entity_uuid = nil - @run_id = nil - @blob = [] - - def initialize(entity_uuid, run_id, blob) - @entity_uuid = entity_uuid - @run_id = run_id - @blob = blob - 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 - - # 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 - - # Returns a hash with the counted controls based on their status and criticality - # 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] += 1 unless criticality.nil? - end - end - end - count - end - - # Return a json string containing the inspec report to be sent to the data_collector - def enriched_report - return nil unless @blob.is_a?(Hash) && @blob[:reports].is_a?(Hash) - final_report = {} - node_name = @blob[:node] # ~FC001, ~FC019, ~FC039 - total_duration = 0 - inspec_version = 'unknown' - # strip the report to leave only the profiles - final_report['profiles'] = @blob[:reports].map do |_name, content| - next unless content.is_a?(Hash) - inspec_version = content['version'] - total_duration += content['statistics']['duration'] - # reports generated by this cookbook have only one profile - content['profiles'][0] if content['profiles'].is_a?(Array) - end - - # remove nil profiles if any - final_report['profiles'].select! { |p| p } - - # 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']}" - final_report.to_json - end - - # Method used in order to send the inspec report to the data_collector server - def send_report - unless @entity_uuid && @run_id - Chef::Log.warn "entity_uuid(#{@entity_uuid}) or run_id(#{@run_id}) can't be nil, not sending report..." - return false - end - json_report = enriched_report - - unless json_report - Chef::Log.warn 'Something went wrong, enriched_report can\'t be nil' - return false - end - if defined?(Chef) && - defined?(Chef::Config) && - Chef::Config[:data_collector] && - Chef::Config[:data_collector][:token] && - Chef::Config[:data_collector][:server_url] - - dc = Chef::Config[:data_collector] - headers = { 'Content-Type' => 'application/json' } - unless dc[:token].nil? - headers['x-data-collector-token'] = dc[:token] - headers['x-data-collector-auth'] = 'version=1.0' - end - - begin - Chef::Log.info "Report to Chef Visibility: #{dc[:server_url]}" - Chef::Log.debug("POSTing the following message to #{dc[:server_url]}: #{json_report}") - http = Chef::HTTP.new(dc[:server_url]) - http.post(nil, json_report, headers) - return true - rescue => e - Chef::Log.error "send_inspec_report: POSTing to #{dc[:server_url]} returned: #{e.message}" - return false - end - else - Chef::Log.warn 'data_collector.token and data_collector.server_url must be defined in client.rb!' - return false - end - end - end - - # - # Used to send inspec reports to a Chef Complinace server via Chef Server - # - class ChefServer - include ComplianceHelpers - - @url = nil - @blob = nil - - def initialize(url, blob) - @url = url - @blob = blob - end - - def send_report - Chef::Config[:verify_api_cert] = false - Chef::Config[:ssl_verify_mode] = :verify_none - Chef::Log.info "Report to Chef Server: #{@url}" - rest = Chef::ServerAPI.new(@url, Chef::Config) - with_http_rescue do - rest.post(@url, @blob) - end - end - end - - # - # Used to send inspec reports to a Chef Complinace server - # - class ChefCompliance - include ComplianceHelpers - - @url = nil - @blob = nil - - def initialize(url, blob, token, raise_if_unreachable) - @url = url - @blob = blob - @token = token - @raise_if_unreachable = raise_if_unreachable - end - - def send_report - req = Net::HTTP::Post.new(@url, { 'Authorization' => "Bearer #{@token}" }) - req.body = @blob.to_json - Chef::Log.info "Report to Chef Compliance: #{@url}" - - opts = { use_ssl: @url.scheme == 'https', - verify_mode: OpenSSL::SSL::VERIFY_NONE, # FIXME - } - Net::HTTP.start(@url.host, @url.port, opts) do |http| - with_http_rescue do - http.request(req) - end - end - end - end -end diff --git a/libraries/compliance.rb b/libraries/compliance.rb deleted file mode 100644 index b2f4e37e..00000000 --- a/libraries/compliance.rb +++ /dev/null @@ -1,16 +0,0 @@ -# encoding: utf-8 - -# exchanges a refresh token into an access token -def retrieve_access_token(server_url, refresh_token, insecure) - require 'inspec' - require 'bundles/inspec-compliance/api' - require 'bundles/inspec-compliance/http' - require 'bundles/inspec-compliance/configuration' - # get_token_via_refresh_token is provided by the inspec-compliance plugin bundled in InSpec - success, msg, access_token = Compliance::API.get_token_via_refresh_token(server_url, refresh_token, insecure) - # TODO: we return always the access token, without proper error handling - unless success - Chef::Log.error("Unable to get a Chef Compliance API access_token: #{msg}") - end - access_token -end diff --git a/libraries/helper.rb b/libraries/helper.rb deleted file mode 100644 index e7cd26a8..00000000 --- a/libraries/helper.rb +++ /dev/null @@ -1,73 +0,0 @@ -# encoding: utf-8 -require 'uri' - -# This helps to construct compliance urls -module ComplianceHelpers - # returns the base url of the chef server - # Chef::Config[:chef_server_url] may be https://chef.compliance.test/organizations/brewinc - # returns 'https://chef.compliance.test' - def base_chef_server_url - cs = URI(Chef::Config[:chef_server_url]) - cs.path = '' - cs.to_s - end - - def construct_url(server, path) - # sanitize inputs - server << '/' unless server =~ %r{/\z} - path.sub!(%r{^/}, '') - server = URI(server) - server.path = server.path + path if path - server - end - - def handle_http_error_code(code) - case code - when /401|403/ - Chef::Log.error 'Auth issue: see audit cookbook TROUBLESHOOTING.md' - when /404/ - Chef::Log.error 'Object does not exist on remote server.' - end - msg = "Received HTTP error #{code}" - Chef::Log.error msg - raise msg if @raise_if_unreachable - end - - #rubocop:disable all - def with_http_rescue(&block) - begin - response = yield - if response.respond_to?(:code) - # handle non 200 error codes, they are not raised as Net::HTTPServerException - handle_http_error_code(response.code) if response.code.to_i >= 300 - end - return response - rescue Net::HTTPServerException => e - Chef::Log.error e - handle_http_error_code(e.response.code) - end - end - - # Returns the uuid for the current converge - def run_id - return unless run_context && - 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 - end - end - return nil - end - - # Returns the node's uuid - def entity_uuid - if (defined?(Chef) && - defined?(Chef::DataCollector) && - defined?(Chef::DataCollector::Messages) && - defined?(Chef::DataCollector::Messages.node_uuid)) - return Chef::DataCollector::Messages.node_uuid - end - end -end diff --git a/libraries/interval.rb b/libraries/interval.rb deleted file mode 100644 index 06aa8e62..00000000 --- a/libraries/interval.rb +++ /dev/null @@ -1,9 +0,0 @@ -# encoding: utf-8 - -def profile_overdue_to_run?(profile, interval) - # Calculate when the profile was last run so we delay it's next run if necessary - compliance_cache_directory = ::File.join(Chef::Config[:file_cache_path], 'compliance') - return true unless ::File.exist?("#{compliance_cache_directory}/#{profile}") - seconds_since_last_run = Time.now - ::File.mtime("#{compliance_cache_directory}/#{profile}") - seconds_since_last_run > interval -end diff --git a/libraries/matchers.rb b/libraries/matchers.rb deleted file mode 100644 index 9b82a5d2..00000000 --- a/libraries/matchers.rb +++ /dev/null @@ -1,27 +0,0 @@ -# encoding: utf-8 - -# used by ChefSpec -if defined?(ChefSpec) - - ChefSpec.define_matcher :compliance_profile - - def create_compliance_token(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_token, :create, resource_name) - end - - def fetch_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :fetch, resource_name) - end - - def upload_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :upload, resource_name) - end - - def execute_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :execute, resource_name) - end - - def execute_compliance_report(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_report, :execute, resource_name) - end -end diff --git a/libraries/server_api.rb b/libraries/server_api.rb deleted file mode 100644 index 0afff233..00000000 --- a/libraries/server_api.rb +++ /dev/null @@ -1,40 +0,0 @@ -# encoding: utf-8 - -require 'uri' - -class Chef - # we need to activate because we need binmode on the tempfile - class ServerAPI - def binmode_streaming_request(path, headers = {}) - url = create_url(path) - tempfile = nil - - method = :GET - method, url, headers, data = apply_request_middleware(method, url, headers, data) - - response, _rest_request, _return_value = send_http_request(method, url, headers, data) do |http_response| - if http_response.is_a?(Net::HTTPSuccess) - tempfile = binmode_stream_to_tempfile(url, http_response) - tempfile.close - end - end - - return nil if response.is_a?(Net::HTTPRedirection) - response.error! unless response.is_a?(Net::HTTPSuccess) - - tempfile - end - - def binmode_stream_to_tempfile(_url, response) - file = ::Tempfile.new(['compliance-profile', '.tgz']) - file.binmode # !!! - - stream_handler = StreamHandler.new(middlewares, response) - - response.read_body do |chunk| - file.write(stream_handler.handle_chunk(chunk)) - end - file - end - end -end diff --git a/metadata.rb b/metadata.rb index d45d0622..6260d659 100644 --- a/metadata.rb +++ b/metadata.rb @@ -13,3 +13,4 @@ chef_version '>= 12.5.1' if respond_to?(:chef_version) depends 'compat_resource' +depends 'chef_handler' \ No newline at end of file diff --git a/recipes/_inspec.rb b/recipes/_inspec.rb deleted file mode 100644 index 54706f2f..00000000 --- a/recipes/_inspec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: compliance -# Recipe:: inspec -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -inspec_version = node['audit']['inspec_version'] - -# install inspec if require -inspec 'inspec' do - version inspec_version - action :install -end diff --git a/recipes/default.rb b/recipes/default.rb index ac3168a7..81c714f2 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,91 +1,21 @@ -# encoding: utf-8 -# -# Cookbook Name:: compliance -# Recipe:: default -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +include_recipe 'chef_handler' -# ensure inspec is available -include_recipe 'audit::_inspec' +handler_directory = ::File.join(Chef::Config[:file_cache_path], 'handler') -# read selected reporter -report_collector = node['audit']['collector'] - -# These attributes should only be set when connecting directly to Chef Compliance, otherwise they should be nil -server = node['audit']['server'] - -# only needed when fetching / reporting directly to Compliance Server -compliance_token 'Compliance Token' do - server server - token node['audit']['refresh_token'] || node['audit']['token'] - insecure node['audit']['insecure'] -end unless server.nil? - -# set the inspec report format based on collector -formatter = report_collector == 'chef-visibility' ? 'json' : 'json-min' - -# handle intervals -interval_seconds = 0 # always run this by default, unless interval is defined -if !node['audit']['interval'].nil? && node['audit']['interval']['enabled'] - interval_seconds = node['audit']['interval']['time'] * 60 # seconds in interval - Chef::Log.debug "Auditing this machine every #{interval_seconds} seconds " -end - -# ensure profile cache directory is available -compliance_cache_directory = ::File.join(Chef::Config[:file_cache_path], 'compliance') -directory compliance_cache_directory do +directory handler_directory do action :create end -# iterate over all selected profiles and download them -node['audit']['profiles'].each do |owner_profile, value| - case value - when Hash - next if value['disabled'] - path = value['source'] - else - next if value == false - end - raise "Invalid profile name '#{owner_profile}'. "\ - "Must contain /, e.g. 'john/ssh'" if owner_profile !~ %r{\/} - o, p = owner_profile.split('/').last(2) - - # file that can be used for interval triggering - file "#{compliance_cache_directory}/#{p}" do - action :nothing - end +cookbook_file ::File.join(handler_directory, 'audit_report.rb') do + source 'audit_report.rb' +end - # execute profile - compliance_profile p do - owner o - formatter formatter - server server - path path unless path.nil? - quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? - only_if { profile_overdue_to_run?(p, interval_seconds) } - action [:fetch, :execute] - notifies :touch, "file[#{compliance_cache_directory}/#{p}]", :delayed - notifies :execute, "compliance_report[#{report_collector}]", :delayed - end +chef_handler 'Chef::Handler::AuditReport' do + source "#{handler_directory}/audit_report.rb" + supports :report => true + action :enable end -# report the results -compliance_report report_collector do - owner node['audit']['owner'] - server server - collector report_collector - quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? - action :nothing -end if node['audit']['profiles'].values.any? +chef_inspec 'inspec' do + action :install +end diff --git a/recipes/upload.rb b/recipes/upload.rb deleted file mode 100644 index 7264da85..00000000 --- a/recipes/upload.rb +++ /dev/null @@ -1,55 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: audit -# Recipe:: upload -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# ensure inspec is available -include_recipe 'audit::_inspec' - -# These attributes should only be set when connecting directly to Chef Compliance, otherwise they should be nil -server = node['audit']['server'] - -# only needed when fetching / reporting directly to Compliance Server -compliance_token 'Compliance Token' do - server server - token node['audit']['refresh_token'] || node['audit']['token'] - insecure node['audit']['insecure'] -end unless server.nil? - -# iterate over all selected profiles and upload them -node['audit']['profiles'].each do |owner_profile, value| - case value - when Hash - next if value['disabled'] - path = value['source'] - else - next if value == false - end - raise "Invalid profile name '#{owner_profile}'. "\ - "Must contain /, e.g. 'john/ssh'" if owner_profile !~ %r{\/} - o, p = owner_profile.split('/').last(2) - - # upload profile - compliance_profile p do - owner o - server server - path path - insecure node['audit']['insecure'] - overwrite node['audit']['overwrite'] - action :upload - end -end diff --git a/resources/inspec.rb b/resources/inspec.rb index ac0d32fa..d23d56c4 100644 --- a/resources/inspec.rb +++ b/resources/inspec.rb @@ -1,7 +1,7 @@ # encoding: utf-8 provides :chef_inspec -resource_name :inspec # FIXME: why is this different than the provides name? +resource_name :chef_inspec property :version, String, default: 'latest' diff --git a/resources/profile.rb b/resources/profile.rb deleted file mode 100644 index 4f049dc9..00000000 --- a/resources/profile.rb +++ /dev/null @@ -1,217 +0,0 @@ -# encoding: utf-8 -require 'tempfile' -require 'uri' -require 'net/https' -require 'fileutils' - -provides :compliance_profile -include ComplianceHelpers - -property :profile, String, name_property: true -property :owner, String, required: true - -# to use a chef-compliance server that is used with chef-server integration -property :server, [String, URI, nil] -property :port, Integer -property :insecure, [TrueClass, FalseClass], default: false -property :formatter, ['json', 'json-min'], default: 'json-min' -property :quiet, [TrueClass, FalseClass], default: true -property :overwrite, [TrueClass, FalseClass], default: true -# TODO(sr) it might be nice to default to settings from attributes - -# alternative to (owner, profile)-addressing for profiles, -# e.g. for running profiles from disk (coming from some other source) -property :path, String - -default_action :execute - -action :fetch do - converge_by 'load required inspec modules' do - require 'inspec' - # load the supermarket plugin - require 'bundles/inspec-supermarket/api' - require 'bundles/inspec-supermarket/target' - - # load the compliance api plugin - require 'bundles/inspec-compliance/api' - require 'bundles/inspec-compliance/http' - end - - converge_by 'create cache directory' do - directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) - end - - converge_by 'fetch compliance profile' do - return if path # will be fetched from other source during execute phase - - o, p = normalize_owner_profile - Chef::Log.info "Fetch compliance profile #{o}/#{p}" - - path = tar_path - node.run_state['compliance'] ||= {} - - if node.run_state['compliance']['access_token'] # go direct - reqpath ="owners/#{o}/compliance/#{p}/tar" - url = construct_url(server, reqpath) - Chef::Log.info "Load profile from: #{url}" - - tf = Tempfile.new('foo', Dir.tmpdir, binmode: true) - - opts = { use_ssl: url.scheme == 'https', - verify_mode: OpenSSL::SSL::VERIFY_NONE, # FIXME - } - Net::HTTP.start(url.host, url.port, opts) do |http| - resp = with_http_rescue do - http.get(url.path, 'Authorization' => "Bearer #{node.run_state['compliance']['access_token']}") - end - tf.write(resp.body) - end - tf.flush - else # go through Chef::ServerAPI - reqpath ="organizations/#{org}/owners/#{o}/compliance/#{p}/tar" - url = construct_url(base_chef_server_url + '/compliance/', reqpath) - Chef::Log.info "Load profile from: #{url}" - - Chef::Config[:verify_api_cert] = false # FIXME - Chef::Config[:ssl_verify_mode] = :verify_none # FIXME - - rest = Chef::ServerAPI.new(url, Chef::Config) - tf = with_http_rescue do - rest.binmode_streaming_request(url) - end - end - - case node['platform'] - when 'windows' - # mv replaced due to Errno::EACCES: - # https://bugs.ruby-lang.org/issues/10865 - FileUtils.cp(tf.path, path) unless tf.nil? - else - FileUtils.mv(tf.path, path) unless tf.nil? - end - - end -end - -action :execute do - # ensure it's there, if if the profile wasn't fetched using these resources - converge_by 'load required inspec modules' do - require 'inspec' - end - - converge_by 'create/verify cache directory' do - directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) - end - - converge_by 'execute compliance profile' do - path ||= tar_path - report_file = report_path - - supported_schemes = %w{http https supermarket compliance chefserver} - if !supported_schemes.include?(URI(path).scheme) && !::File.exist?(path) - Chef::Log.warn "No such path! Skipping: #{path}" - raise "Aborting since profile is not present here: #{path}" if run_context.node['audit']['fail_if_not_present'] - return - end - - Chef::Log.info "Executing: #{path}" - - # TODO: flesh out inspec's report CLI interface, - # make this an execute[inspec check ...] - output = quiet ? ::File::NULL : $stdout - runner = ::Inspec::Runner.new('report' => true, 'format' => formatter, 'output' => output) - runner.add_target(path, {}) - begin - runner.run - # TODO: weird exception, do we need that handling? - rescue Chef::Exceptions::ValidationFailed => e - Chef::Log.error e - end - - file report_file do - content runner.report.to_json - sensitive true - backup false - end - end -end - -action :upload do - converge_by 'run profile validation checks' do - raise 'Path to profile archive not specified' if path.nil? - raise "Profile archive file #{path} does not exist." unless ::File.exist?(path) - profile = Inspec::Profile.for_target(path, {}) - error_count = 0 - lambda { |msg| - error_count += 1 - Chef::Log.error msg - } - result = profile.check - Chef::Log.info result[:summary].inspect - raise 'Profile check failed' unless result[:summary][:valid] - Chef::Log.info 'Profile is valid' - end - - converge_by 'upload compliance profile' do - o, p = normalize_owner_profile - node.run_state['compliance'] ||= {} - - if node.run_state['compliance']['access_token'] - reqpath ="owners/#{o}/compliance/#{p}/tar" - url = construct_url(server, reqpath) - Chef::Log.info "Upload from #{path} to: #{url}" - config = Compliance::Configuration.new - config['token'] = node.run_state['compliance']['access_token'] - config['insecure'] = insecure - config['server'] = server - config['version'] = Compliance::API.version(server, insecure) - if Compliance::API.exist?(config, "#{o}/#{p}") && !overwrite - raise 'Profile exists on the server, use property `overwrite`' - else - success, msg = Compliance::API.upload(config, o, p, path) - if success - Chef::Log.info 'Successfully uploaded profile' - else - Chef::Log.error "Error during profile upload: #{msg}" - end - end - else - raise 'Unable to read access token, aborting upload' - end - end -end - -def normalize_owner_profile - if profile.include?('/') - profile.split('/').last(2) - else - [owner || 'base', profile] - end -end - -def tar_path - return path if path - o, p = normalize_owner_profile - case node['platform'] - when 'windows' - windows_path = Chef::Config[:file_cache_path].tr('\\', '/') - ::File.join(windows_path, 'compliance', "#{o}_#{p}.tgz") - else - ::File.join(Chef::Config[:file_cache_path], 'compliance', "#{o}_#{p}.tgz") - end -end - -def report_path - o, p = normalize_owner_profile - case node['platform'] - when 'windows' - windows_path = Chef::Config[:file_cache_path].tr('\\', '/') - ::File.join(windows_path, 'compliance', "#{o}_#{p}_report.json") - else - ::File.join(Chef::Config[:file_cache_path], 'compliance', "#{o}_#{p}_report.json") - end -end - -def org - Chef::Config[:chef_server_url].split('/').last -end diff --git a/resources/report.rb b/resources/report.rb deleted file mode 100644 index 64ef7069..00000000 --- a/resources/report.rb +++ /dev/null @@ -1,126 +0,0 @@ -# encoding: utf-8 -# `compliance_report` custom resource to run Chef Compliance profiles and -# send reports to Chef Compliance - -include ComplianceHelpers -provides :compliance_report - -property :name, String, name_property: true - -# to use a chef-compliance server that is used with chef-server integration -property :server, [String, URI, nil] -property :port, Integer -property :insecure, [TrueClass, FalseClass], default: false -property :quiet, [TrueClass, FalseClass], default: true -property :collector, ['chef-visibility', 'chef-compliance', 'chef-server'], default: 'chef-server' - -property :environment, String # default: node.environment -property :owner, [String, nil] - -default_action :execute - -action :execute do - converge_by "report compliance profiles' results" do - reports, ownermap = compound_report(profiles) - blob = node_info - blob[:reports] = reports - blob[:profiles] = ownermap - - formatter = collector == 'chef-visibility' ? 'json' : 'json-min' - # counting total_failed based on the json/json-min format - if formatter == 'json' - total_failed = reports.map do |_name, report| - report['profiles'].map do |profile| - profile['controls'].map do |control| - if control['results'] - control['results'].map do |result| - result['status'] != 'passed' ? 1 : 0 - end - else - 0 - end - end - end - end.flatten.reduce(:+) - else - total_failed = reports.map do |_name, profile| - if !profile['controls'].empty? - profile['controls'].map do |control| - control['status'] != 'passed' ? 1 : 0 - end - else - 0 - end - end.flatten.reduce(:+) - end - Chef::Log.info "Total number of failed controls: #{total_failed}" - - # resolve owner - o = return_or_guess_owner - - raise_if_unreachable = run_context.node['audit']['raise_if_unreachable'] if run_context.node['audit'] - - case collector - when 'chef-visibility' - Collector::ChefVisibility.new(entity_uuid, run_id, blob).send_report - when 'chef-compliance' - node.run_state['compliance'] ||= {} - if node.run_state['compliance']['access_token'] && server - url = construct_url(server, ::File.join('/owners', o, 'inspec')) - Collector::ChefCompliance.new(url, blob, node.run_state['compliance']['access_token'], raise_if_unreachable).send_report - else - Chef::Log.warn "'server' and 'token' properties required by inspec report collector '#{collector}'. Skipping..." - end - when 'chef-server' - chef_url = server || base_chef_server_url - if chef_url - url = construct_url(chef_url + '/compliance/', ::File.join('organizations', o, 'inspec')) - Collector::ChefServer.new(url, blob).send_report - else - Chef::Log.warn "unable to determine chef-server url required by inspec report collector '#{collector}'. Skipping..." - end - else - Chef::Log.warn "#{collector} is not a supported inspec report collector" - end - - raise "#{total_failed} audits have failed. Aborting chef-client run." if total_failed > 0 && node['audit']['fail_if_any_audits_failed'] - end -end - -# filters resource collection -def profiles - run_context.resource_collection.select do |r| - r.is_a?(AuditProfile) - end.flatten -end - -def compound_report(*profiles) - report = {} - ownermap = {} - - profiles.flatten.each do |prof| - next unless ::File.exist?(prof.report_path) - o, p = prof.normalize_owner_profile - report[p] = ::JSON.parse(::File.read(prof.report_path)) - ownermap[p] = o - end - - [report, ownermap] -end - -def node_info - n = run_context.node - { - node: n.name, - os: { - # arch: os[:arch], - release: n['platform_version'], - family: n['platform'], - }, - environment: environment || n.environment, - } -end - -def return_or_guess_owner - owner || Chef::Config[:chef_server_url].split('/').last -end diff --git a/resources/token.rb b/resources/token.rb deleted file mode 100644 index a721fa5a..00000000 --- a/resources/token.rb +++ /dev/null @@ -1,26 +0,0 @@ -# encoding: utf-8 -# `compliance_token` custom resource to communicate with Chef Compliance -include ComplianceHelpers - -provides :compliance_token - -property :server, [String, URI, nil], required: true -property :port, Integer -property :token, [String, nil], required: true -property :insecure, [TrueClass, FalseClass], default: false - -default_action :create - -action :create do - converge_by 'compliance server auth token setup' do - # stash token in node.run_state to pass between resources - node.run_state['compliance'] ||= {} - if node['audit']['refresh_token'] - Chef::Log.info 'Using refresh_token to exchange for an access token.' - node.run_state['compliance']['access_token'] = retrieve_access_token(server, token, insecure) - else - Chef::Log.info 'Using token attribute. This token is short lived and will expire.' - node.run_state['compliance']['access_token'] = token - end - end -end From 182ff456e685fb613947ba49f4961ae734e05620 Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Tue, 18 Oct 2016 14:31:14 -0400 Subject: [PATCH 2/8] setting up visibility reporting. almost there. --- attributes/default.rb | 6 +- files/default/audit_report.rb | 2 +- libraries/collector_classes.rb | 173 +++++++++++++++++++++++++++++++++ libraries/helper.rb | 27 +++++ recipes/default.rb | 4 + resources/report.rb | 16 +++ 6 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 libraries/collector_classes.rb create mode 100644 libraries/helper.rb create mode 100644 resources/report.rb diff --git a/attributes/default.rb b/attributes/default.rb index fdf7de58..327d9fab 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -62,4 +62,8 @@ default['audit']['format'] = "json" # set profiles to empty array as default -default['audit']['profiles'] = [] \ No newline at end of file +default['audit']['profiles'] = [] + +# output for inspec results +result_path = File.expand_path("../../inspec_results.txt", __FILE__) +default['audit']['output'] = result_path \ No newline at end of file diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb index 063dab7b..b751f59f 100644 --- a/files/default/audit_report.rb +++ b/files/default/audit_report.rb @@ -25,7 +25,7 @@ def load_needed_dependencies def call Chef::Log.debug "Initialize InSpec" - opts = { "format" => node['audit']['format'] } + opts = { "format" => node['audit']['format'], "output" => node['audit']['output']} runner = ::Inspec::Runner.new(opts) tests = node['audit']['profiles'] diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb new file mode 100644 index 00000000..2a193774 --- /dev/null +++ b/libraries/collector_classes.rb @@ -0,0 +1,173 @@ +# encoding: utf-8 +require 'json' +require_relative 'helper' + +class Collector + # + # Used to send inspec reports to Chef Visibility via the data_collector service + # + class ChefVisibility + @entity_uuid = nil + @run_id = nil + @node_name = '' + + def initialize(entity_uuid, run_id, node_name) + @entity_uuid = entity_uuid + @run_id = run_id + @node_name = node_name + end + + # Method used in order to send the inspec report to the data_collector server + def send_report + unless @entity_uuid && @run_id + Chef::Log.warn "entity_uuid(#{@entity_uuid}) or run_id(#{@run_id}) can't be nil, not sending report..." + return false + end + + # get file contents where inspec results were saved + result_path = File.expand_path("../../inspec_results.txt", __FILE__) + file = File.open(result_path, "rb") + content = file.read + file.close + + # parse that string of contents into json + json_report = enriched_report(JSON.parse(content)) + + unless json_report + Chef::Log.warn 'Something went wrong, report can\'t be nil' + return false + end + if defined?(Chef) && + defined?(Chef::Config) && + Chef::Config[:data_collector] && + Chef::Config[:data_collector][:token] && + Chef::Config[:data_collector][:server_url] + + dc = Chef::Config[:data_collector] + headers = { 'Content-Type' => 'application/json' } + unless dc[:token].nil? + headers['x-data-collector-token'] = dc[:token] + headers['x-data-collector-auth'] = 'version=1.0' + end + + begin + Chef::Log.info "Report to Chef Visibility: #{dc[:server_url]}" + Chef::Log.debug("POSTing the following message to #{dc[:server_url]}: #{json_report}") + http = Chef::HTTP.new(dc[:server_url]) + http.post(nil, json_report, headers) + return true + rescue => e + Chef::Log.error "send_inspec_report: POSTing to #{dc[:server_url]} returned: #{e.message}" + return false + end + else + Chef::Log.warn 'data_collector.token and data_collector.server_url must be defined in client.rb!' + return false + end + end + + # *************************************************************************************** + # TODO: We could likely simplify/remove alot of the extra logic we have here with a small + # revamp of the visibility expected input. + # *************************************************************************************** + + def enriched_report(content) + return nil unless content.is_a?(Hash) + final_report = {} + total_duration = content['statistics']['duration'] + inspec_version = content['version'] + + # strip the report to leave only the profiles + final_report['profiles'] = content['profiles'] + + # remove nil profiles if any + final_report['profiles'].select! { |p| p } + + # 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']}" + final_report.to_json + end + + # Returns a hash with the counted controls based on their status and criticality + # 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] += 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 + + # 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 +end \ No newline at end of file diff --git a/libraries/helper.rb b/libraries/helper.rb new file mode 100644 index 00000000..0057b623 --- /dev/null +++ b/libraries/helper.rb @@ -0,0 +1,27 @@ +# encoding: utf-8 + +module ReportHelpers + + # Returns the uuid for the current converge + def run_id + return unless run_context && + 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 + end + end + return nil + end + + # Returns the node's uuid + def entity_uuid + if (defined?(Chef) && + defined?(Chef::DataCollector) && + defined?(Chef::DataCollector::Messages) && + defined?(Chef::DataCollector::Messages.node_uuid)) + return Chef::DataCollector::Messages.node_uuid + end + end +end \ No newline at end of file diff --git a/recipes/default.rb b/recipes/default.rb index 81c714f2..79531e0e 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -19,3 +19,7 @@ chef_inspec 'inspec' do action :install end + +inspec_report 'report' do + action :execute +end \ No newline at end of file diff --git a/resources/report.rb b/resources/report.rb new file mode 100644 index 00000000..00d93c3e --- /dev/null +++ b/resources/report.rb @@ -0,0 +1,16 @@ +# encoding: utf-8 + +include ReportHelpers +provides :inspec_report +resource_name :inspec_report + +property :collector, String, default: 'chef-visibility' + +default_action :execute + +action :execute do + case collector + when 'chef-visibility' + Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report + end +end From d6eef1dded88d14e806c7271d561a0d64a01ecc9 Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Tue, 18 Oct 2016 21:49:26 -0400 Subject: [PATCH 3/8] fixing lint errors. most tests fixed. Signed-off-by: Victoria Jeffrey --- attributes/default.rb | 6 +- files/default/audit_report.rb | 26 +-- libraries/collector_classes.rb | 17 +- libraries/helper.rb | 15 +- metadata.rb | 2 +- recipes/default.rb | 3 +- resources/report.rb | 4 +- spec/unit/recipes/default_spec.rb | 321 +++++++++++++++--------------- spec/unit/recipes/upload_spec.rb | 84 ++++---- 9 files changed, 244 insertions(+), 234 deletions(-) diff --git a/attributes/default.rb b/attributes/default.rb index 327d9fab..36e26859 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -59,11 +59,11 @@ default['audit']['overwrite'] = true # use json format since this is for reporting -default['audit']['format'] = "json" +default['audit']['format'] = 'json' # set profiles to empty array as default default['audit']['profiles'] = [] # output for inspec results -result_path = File.expand_path("../../inspec_results.txt", __FILE__) -default['audit']['output'] = result_path \ No newline at end of file +result_path = File.expand_path('../../inspec_results.txt', __FILE__) +default['audit']['output'] = result_path diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb index b751f59f..2146241e 100644 --- a/files/default/audit_report.rb +++ b/files/default/audit_report.rb @@ -10,30 +10,30 @@ def report end def load_needed_dependencies - require "inspec" + require 'inspec' # load supermarket plugin, this is part of the inspec gem - require "bundles/inspec-supermarket/api" - require "bundles/inspec-supermarket/target" + require 'bundles/inspec-supermarket/api' + require 'bundles/inspec-supermarket/target' # load the compliance plugin - require "bundles/inspec-compliance/configuration" - require "bundles/inspec-compliance/support" - require "bundles/inspec-compliance/http" - require "bundles/inspec-compliance/api" - require "bundles/inspec-compliance/target" + require 'bundles/inspec-compliance/configuration' + require 'bundles/inspec-compliance/support' + require 'bundles/inspec-compliance/http' + require 'bundles/inspec-compliance/api' + require 'bundles/inspec-compliance/target' end def call - Chef::Log.debug "Initialize InSpec" - opts = { "format" => node['audit']['format'], "output" => node['audit']['output']} + Chef::Log.debug 'Initialize InSpec' + opts = { 'format' => node['audit']['format'], 'output' => node['audit']['output'] } runner = ::Inspec::Runner.new(opts) tests = node['audit']['profiles'] tests.each { |target| runner.add_target(target, opts) } - Chef::Log.debug "Running tests from: #{tests.inspect}" - exit_code = runner.run + Chef::Log.debug 'Running tests from: #{tests.inspect}' + runner.run end end end -end \ No newline at end of file +end diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb index 2a193774..47691e0c 100644 --- a/libraries/collector_classes.rb +++ b/libraries/collector_classes.rb @@ -25,8 +25,8 @@ def send_report end # get file contents where inspec results were saved - result_path = File.expand_path("../../inspec_results.txt", __FILE__) - file = File.open(result_path, "rb") + result_path = File.expand_path('../../inspec_results.txt', __FILE__) + file = File.open(result_path, 'rb') content = file.read file.close @@ -158,6 +158,17 @@ def compliance_status(counts) 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) @@ -170,4 +181,4 @@ def control_status(results) status end end -end \ No newline at end of file +end diff --git a/libraries/helper.rb b/libraries/helper.rb index 0057b623..f21581d9 100644 --- a/libraries/helper.rb +++ b/libraries/helper.rb @@ -1,27 +1,26 @@ # encoding: utf-8 module ReportHelpers - # Returns the uuid for the current converge def run_id return unless run_context && 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)) + if sub.class == Chef::ResourceReporter && defined?(sub.run_id) return sub.run_id end end - return nil + nil end # Returns the node's uuid def entity_uuid - if (defined?(Chef) && - defined?(Chef::DataCollector) && - defined?(Chef::DataCollector::Messages) && - defined?(Chef::DataCollector::Messages.node_uuid)) + if defined?(Chef) && + defined?(Chef::DataCollector) && + defined?(Chef::DataCollector::Messages) && + defined?(Chef::DataCollector::Messages.node_uuid) return Chef::DataCollector::Messages.node_uuid end end -end \ No newline at end of file +end diff --git a/metadata.rb b/metadata.rb index 6260d659..2472e806 100644 --- a/metadata.rb +++ b/metadata.rb @@ -13,4 +13,4 @@ chef_version '>= 12.5.1' if respond_to?(:chef_version) depends 'compat_resource' -depends 'chef_handler' \ No newline at end of file +depends 'chef_handler' diff --git a/recipes/default.rb b/recipes/default.rb index 79531e0e..8247c900 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -12,7 +12,6 @@ chef_handler 'Chef::Handler::AuditReport' do source "#{handler_directory}/audit_report.rb" - supports :report => true action :enable end @@ -22,4 +21,4 @@ inspec_report 'report' do action :execute -end \ No newline at end of file +end diff --git a/resources/report.rb b/resources/report.rb index 00d93c3e..4eb27a6e 100644 --- a/resources/report.rb +++ b/resources/report.rb @@ -10,7 +10,7 @@ action :execute do case collector - when 'chef-visibility' - Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report + when 'chef-visibility' + Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report end end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb index 58d82bef..d0a88c27 100644 --- a/spec/unit/recipes/default_spec.rb +++ b/spec/unit/recipes/default_spec.rb @@ -30,164 +30,165 @@ expect { chef_run }.to_not raise_error end end - - context 'When server and refresh_token are specified' do - let(:chef_run) do - ChefSpec::ServerRunner.new do |node| - node.override['audit']['collector'] = 'chef-compliance' - node.override['audit']['profiles'] = { 'admin/myprofile' => true } - node.override['audit']['server'] = 'https://my.compliance.test/api' - node.override['audit']['refresh_token'] = 'abcdefg' - node.override['audit']['insecure'] = true - end.converge(described_recipe) - end - - it 'creates compliance_token resource' do - expect(chef_run).to create_compliance_token('Compliance Token').with( - server: 'https://my.compliance.test/api', - insecure: true, - token: 'abcdefg' - ) - end - - it 'fetches and executes compliance_profile[myprofile]' do - expect(chef_run).to fetch_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - ) - expect(chef_run).to execute_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - ) - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'When two profiles are specified' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true, - 'base/ssh' => false } - runner.node.override['audit']['inspec_version'] = 'latest' - runner.node.override['audit']['quiet'] = true - runner.converge(described_recipe) - end - let(:myprofile) { chef_run.compliance_profile('myprofile') } - - it 'fetches and executes compliance_profile[myprofile]' do - expect(chef_run).to fetch_compliance_profile('myprofile').with( - owner: 'admin', - server: nil, - token: nil, - ) - expect(chef_run).to execute_compliance_profile('myprofile').with( - owner: 'admin', - server: nil, - token: nil, - quiet: true, - ) - end - - it 'notifies compliance_report[chef-server]' do - expect(myprofile).to notify('compliance_report[chef-server]').delayed - end - - it 'skips compliance_profile[ssh]' do - expect(chef_run).to_not fetch_compliance_profile('ssh') - expect(chef_run).to_not execute_compliance_profile('ssh') - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'When invalid profile is passed' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'myprofile' => true } - runner.converge(described_recipe) - end - - it 'does raise an error' do - expect { chef_run }.to raise_error("Invalid profile name 'myprofile'. Must contain /, e.g. 'john/ssh'") - end - end - - context 'When specifying profiles with alternate sources' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { - 'base/linux' => true, - 'base/apache' => false, - 'brewinc/ssh-hardening' => { - 'source' => 'supermarket://hardening/ssh-hardening', - }, - 'brewinc/tmp_compliance_profile' => { - 'source' => 'https://github.com/nathenharvey/tmp_compliance_profile', - }, - 'brewinc/tmp_compliance_profile-master' => { - 'source' => '/tmp/tmp_compliance_profile-master', - }, - 'exampleorg/myprofile' => { - 'disabled' => true, - }, - } - runner.converge(described_recipe) - end - let(:linux_profile) { chef_run.compliance_profile('linux') } - - it 'executes base/linux in backward compatible mode' do - expect(chef_run).to execute_compliance_profile('linux').with( - path: nil, - ) - end - it 'executes brewinc/ssh-hardening from supermarket' do - expect(chef_run).to execute_compliance_profile('ssh-hardening').with( - path: 'supermarket://hardening/ssh-hardening', - ) - end - it 'executes brewinc/tmp_compliance_profile from github' do - expect(chef_run).to execute_compliance_profile('tmp_compliance_profile').with( - path: 'https://github.com/nathenharvey/tmp_compliance_profile', - ) - end - it 'executes brewinc/tmp_compliance_profile-master from filesystem' do - expect(chef_run).to execute_compliance_profile('tmp_compliance_profile-master').with( - path: '/tmp/tmp_compliance_profile-master', - ) - end - it 'does not execute disabled exampleorg/myprofile' do - expect(chef_run).to_not execute_compliance_profile('myprofile') - end - it 'notifies compliance_report[chef-server]' do - expect(linux_profile).to notify('compliance_report[chef-server]').delayed - end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'when set to run on an interval and not due to run' do - before(:each) do - allow_any_instance_of(Chef::Resource).to receive(:profile_overdue_to_run?).and_return(false) - end - - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true } - runner.node.override['audit']['interval']['enabled'] = true - runner.converge(described_recipe) - end - - it 'does not fetch or execute on compliance profile' do - expect(chef_run).to_not fetch_compliance_profile('myprofile') - expect(chef_run).to_not execute_compliance_profile('myprofile') - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end end + +# context 'When server and refresh_token are specified' do +# let(:chef_run) do +# ChefSpec::ServerRunner.new do |node| +# node.override['audit']['collector'] = 'chef-compliance' +# node.override['audit']['profiles'] = { 'admin/myprofile' => true } +# node.override['audit']['server'] = 'https://my.compliance.test/api' +# node.override['audit']['refresh_token'] = 'abcdefg' +# node.override['audit']['insecure'] = true +# end.converge(described_recipe) +# end + +# it 'creates compliance_token resource' do +# expect(chef_run).to create_compliance_token('Compliance Token').with( +# server: 'https://my.compliance.test/api', +# insecure: true, +# token: 'abcdefg' +# ) +# end + +# it 'fetches and executes compliance_profile[myprofile]' do +# expect(chef_run).to fetch_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# ) +# expect(chef_run).to execute_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# ) +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'When two profiles are specified' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true, +# 'base/ssh' => false } +# runner.node.override['audit']['inspec_version'] = 'latest' +# runner.node.override['audit']['quiet'] = true +# runner.converge(described_recipe) +# end +# let(:myprofile) { chef_run.compliance_profile('myprofile') } + +# it 'fetches and executes compliance_profile[myprofile]' do +# expect(chef_run).to fetch_compliance_profile('myprofile').with( +# owner: 'admin', +# server: nil, +# token: nil, +# ) +# expect(chef_run).to execute_compliance_profile('myprofile').with( +# owner: 'admin', +# server: nil, +# token: nil, +# quiet: true, +# ) +# end + +# it 'notifies compliance_report[chef-server]' do +# expect(myprofile).to notify('compliance_report[chef-server]').delayed +# end + +# it 'skips compliance_profile[ssh]' do +# expect(chef_run).to_not fetch_compliance_profile('ssh') +# expect(chef_run).to_not execute_compliance_profile('ssh') +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'When invalid profile is passed' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'myprofile' => true } +# runner.converge(described_recipe) +# end + +# it 'does raise an error' do +# expect { chef_run }.to raise_error("Invalid profile name 'myprofile'. Must contain /, e.g. 'john/ssh'") +# end +# end + +# context 'When specifying profiles with alternate sources' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { +# 'base/linux' => true, +# 'base/apache' => false, +# 'brewinc/ssh-hardening' => { +# 'source' => 'supermarket://hardening/ssh-hardening', +# }, +# 'brewinc/tmp_compliance_profile' => { +# 'source' => 'https://github.com/nathenharvey/tmp_compliance_profile', +# }, +# 'brewinc/tmp_compliance_profile-master' => { +# 'source' => '/tmp/tmp_compliance_profile-master', +# }, +# 'exampleorg/myprofile' => { +# 'disabled' => true, +# }, +# } +# runner.converge(described_recipe) +# end +# let(:linux_profile) { chef_run.compliance_profile('linux') } + +# it 'executes base/linux in backward compatible mode' do +# expect(chef_run).to execute_compliance_profile('linux').with( +# path: nil, +# ) +# end +# it 'executes brewinc/ssh-hardening from supermarket' do +# expect(chef_run).to execute_compliance_profile('ssh-hardening').with( +# path: 'supermarket://hardening/ssh-hardening', +# ) +# end +# it 'executes brewinc/tmp_compliance_profile from github' do +# expect(chef_run).to execute_compliance_profile('tmp_compliance_profile').with( +# path: 'https://github.com/nathenharvey/tmp_compliance_profile', +# ) +# end +# it 'executes brewinc/tmp_compliance_profile-master from filesystem' do +# expect(chef_run).to execute_compliance_profile('tmp_compliance_profile-master').with( +# path: '/tmp/tmp_compliance_profile-master', +# ) +# end +# it 'does not execute disabled exampleorg/myprofile' do +# expect(chef_run).to_not execute_compliance_profile('myprofile') +# end +# it 'notifies compliance_report[chef-server]' do +# expect(linux_profile).to notify('compliance_report[chef-server]').delayed +# end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'when set to run on an interval and not due to run' do +# before(:each) do +# allow_any_instance_of(Chef::Resource).to receive(:profile_overdue_to_run?).and_return(false) +# end + +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true } +# runner.node.override['audit']['interval']['enabled'] = true +# runner.converge(described_recipe) +# end + +# it 'does not fetch or execute on compliance profile' do +# expect(chef_run).to_not fetch_compliance_profile('myprofile') +# expect(chef_run).to_not execute_compliance_profile('myprofile') +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end +# end diff --git a/spec/unit/recipes/upload_spec.rb b/spec/unit/recipes/upload_spec.rb index 671540b2..fcb5b9ec 100644 --- a/spec/unit/recipes/upload_spec.rb +++ b/spec/unit/recipes/upload_spec.rb @@ -17,51 +17,51 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'spec_helper' +# require 'spec_helper' -describe 'audit::upload' do - context 'When all attributes are default, on an unspecified platform' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '14.04') - runner.converge(described_recipe) - end +# describe 'audit::upload' do +# context 'When all attributes are default, on an unspecified platform' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '14.04') +# runner.converge(described_recipe) +# end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end - context 'When server and refresh_token are specified' do - let(:chef_run) do - ChefSpec::ServerRunner.new do |node| - node.override['audit']['collector'] = 'chef-compliance' - node.override['audit']['profiles'] = { 'admin/myprofile' => { 'source' => '/some/path.tar.gz' } } - node.override['audit']['server'] = 'https://my.compliance.test/api' - node.override['audit']['refresh_token'] = 'abcdefg' - node.override['audit']['insecure'] = true - end.converge(described_recipe) - end +# context 'When server and refresh_token are specified' do +# let(:chef_run) do +# ChefSpec::ServerRunner.new do |node| +# node.override['audit']['collector'] = 'chef-compliance' +# node.override['audit']['profiles'] = { 'admin/myprofile' => { 'source' => '/some/path.tar.gz' } } +# node.override['audit']['server'] = 'https://my.compliance.test/api' +# node.override['audit']['refresh_token'] = 'abcdefg' +# node.override['audit']['insecure'] = true +# end.converge(described_recipe) +# end - it 'creates compliance_token resource' do - expect(chef_run).to create_compliance_token('Compliance Token').with( - server: 'https://my.compliance.test/api', - insecure: true, - token: 'abcdefg' - ) - end +# it 'creates compliance_token resource' do +# expect(chef_run).to create_compliance_token('Compliance Token').with( +# server: 'https://my.compliance.test/api', +# insecure: true, +# token: 'abcdefg' +# ) +# end - it 'uploads compliance_profile[myprofile]' do - expect(chef_run).to upload_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - owner: 'admin', - path: '/some/path.tar.gz', - insecure: true, - overwrite: true - ) - end +# it 'uploads compliance_profile[myprofile]' do +# expect(chef_run).to upload_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# owner: 'admin', +# path: '/some/path.tar.gz', +# insecure: true, +# overwrite: true +# ) +# end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end -end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end +# end From a42530a14a6f1033143de92b69883698a75f10f3 Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Mon, 17 Oct 2016 09:25:51 -0400 Subject: [PATCH 4/8] use chef handler to run inspec tests --- .kitchen.yml | 2 - attributes/default.rb | 16 +- examples/kitchen/.kitchen.linux.yml | 37 --- examples/kitchen/.kitchen.win.yml | 47 ---- examples/kitchen/Berksfile | 6 - examples/kitchen/Gemfile | 7 - examples/kitchen/README.md | 77 ------ examples/kitchen/cc_report.png | Bin 65522 -> 0 bytes examples/kitchen/visib_reporting.png | Bin 61339 -> 0 bytes examples/visibility_win/.kitchen.yml | 25 -- examples/visibility_win/Berksfile | 4 - examples/visibility_win/README.md | 23 -- examples/visibility_win/metadata.rb | 10 - .../recipes/chef_client_config.rb | 24 -- examples/visibility_win/recipes/default.rb | 6 - examples/visibility_win/spec/spec_helper.rb | 11 - .../unit/recipes/chef_client_config_spec.rb | 22 -- .../spec/unit/recipes/default_spec.rb | 10 - .../default/visibility_ingest.rb.erb | 15 -- .../default/serverspec/default_spec.rb | 2 - examples/wrapper_audit/.kitchen.yml | 49 ---- examples/wrapper_audit/Berksfile | 4 - examples/wrapper_audit/README.md | 26 -- examples/wrapper_audit/metadata.rb | 15 -- examples/wrapper_audit/recipes/default.rb | 15 -- examples/wrapper_audit/spec/spec_helper.rb | 4 - .../spec/unit/recipes/default_spec.rb | 10 - files/default/audit_report.rb | 39 +++ libraries/collector_classes.rb | 235 ------------------ libraries/compliance.rb | 16 -- libraries/helper.rb | 73 ------ libraries/interval.rb | 9 - libraries/matchers.rb | 27 -- libraries/server_api.rb | 40 --- metadata.rb | 1 + recipes/_inspec.rb | 26 -- recipes/default.rb | 96 +------ recipes/upload.rb | 55 ---- resources/inspec.rb | 2 +- resources/profile.rb | 217 ---------------- resources/report.rb | 126 ---------- resources/token.rb | 26 -- 42 files changed, 64 insertions(+), 1391 deletions(-) delete mode 100644 examples/kitchen/.kitchen.linux.yml delete mode 100644 examples/kitchen/.kitchen.win.yml delete mode 100644 examples/kitchen/Berksfile delete mode 100644 examples/kitchen/Gemfile delete mode 100644 examples/kitchen/README.md delete mode 100644 examples/kitchen/cc_report.png delete mode 100644 examples/kitchen/visib_reporting.png delete mode 100644 examples/visibility_win/.kitchen.yml delete mode 100644 examples/visibility_win/Berksfile delete mode 100644 examples/visibility_win/README.md delete mode 100644 examples/visibility_win/metadata.rb delete mode 100644 examples/visibility_win/recipes/chef_client_config.rb delete mode 100644 examples/visibility_win/recipes/default.rb delete mode 100644 examples/visibility_win/spec/spec_helper.rb delete mode 100644 examples/visibility_win/spec/unit/recipes/chef_client_config_spec.rb delete mode 100644 examples/visibility_win/spec/unit/recipes/default_spec.rb delete mode 100644 examples/visibility_win/templates/default/visibility_ingest.rb.erb delete mode 100644 examples/visibility_win/test/integration/default/serverspec/default_spec.rb delete mode 100644 examples/wrapper_audit/.kitchen.yml delete mode 100644 examples/wrapper_audit/Berksfile delete mode 100644 examples/wrapper_audit/README.md delete mode 100644 examples/wrapper_audit/metadata.rb delete mode 100644 examples/wrapper_audit/recipes/default.rb delete mode 100644 examples/wrapper_audit/spec/spec_helper.rb delete mode 100644 examples/wrapper_audit/spec/unit/recipes/default_spec.rb create mode 100644 files/default/audit_report.rb delete mode 100644 libraries/collector_classes.rb delete mode 100644 libraries/compliance.rb delete mode 100644 libraries/helper.rb delete mode 100644 libraries/interval.rb delete mode 100644 libraries/matchers.rb delete mode 100644 libraries/server_api.rb delete mode 100644 recipes/_inspec.rb delete mode 100644 recipes/upload.rb delete mode 100644 resources/profile.rb delete mode 100644 resources/report.rb delete mode 100644 resources/token.rb diff --git a/.kitchen.yml b/.kitchen.yml index 1b838192..a4c709ba 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -64,8 +64,6 @@ suites: attributes: audit: profiles: &profiles - base/ssh: true - base/linux: true - name: compliance # compliance direct reporting run_list: - recipe[audit::default] diff --git a/attributes/default.rb b/attributes/default.rb index ea8f64d4..fdf7de58 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -23,19 +23,19 @@ # Attributes server, insecure and token/refresh_token are only needed for the 'chef-compliance' collector # server format example: 'https://comp-server.example.com/api' default['audit']['server'] = nil + # choose between the permanent refresh_token or ephemeral token(access_token). Needed only for the 'chef-compliance' collector default['audit']['refresh_token'] = nil + # the token(access_token) expires in 12h after creation default['audit']['token'] = nil + # set this insecure attribute to true if the compliance server uses self-signed ssl certificates default['audit']['insecure'] = nil # owner needed for the 'chef-compliance' and 'chef-server' collectors default['audit']['owner'] = nil -default['audit']['quiet'] = nil -default['audit']['profiles'] = {} - # raise exception if Compliance API endpoint is unreachable # while fetching profiles or posting report default['audit']['raise_if_unreachable'] = true @@ -46,11 +46,9 @@ # fail converge after posting report if any audits have failed default['audit']['fail_if_any_audits_failed'] = false -# inspec gem version to install(e.g. '1.1.0') -default['audit']['inspec_version'] = '1.2.0' - # by default run audit every time default['audit']['interval']['enabled'] = false + # by default run compliance once a day default['audit']['interval']['time'] = 1440 @@ -59,3 +57,9 @@ # overwrite existing profile in upload mode default['audit']['overwrite'] = true + +# use json format since this is for reporting +default['audit']['format'] = "json" + +# set profiles to empty array as default +default['audit']['profiles'] = [] \ No newline at end of file diff --git a/examples/kitchen/.kitchen.linux.yml b/examples/kitchen/.kitchen.linux.yml deleted file mode 100644 index bf010077..00000000 --- a/examples/kitchen/.kitchen.linux.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -- name: bento/centos-7.2 -- name: bento/ubuntu-14.04 - -suites: - - name: default - run_list: - - recipe[os-hardening] - - recipe[ssh-hardening] - - recipe[audit::default] - attributes: - audit: - collector: 'chef-compliance' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - owner: admin - # fail converge if downloaded profile is not present - fail_if_not_present: true - # fail converge after posting report if any audits have failed - fail_if_any_audits_failed: false - profiles: - base/linux: true - brewinc/ssh-hardening: - source: supermarket://hardening/ssh-hardening diff --git a/examples/kitchen/.kitchen.win.yml b/examples/kitchen/.kitchen.win.yml deleted file mode 100644 index d0da1e5c..00000000 --- a/examples/kitchen/.kitchen.win.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -- name: windows-2012r2 - -# The following (private) boxes are shared via Atlas and are only -# available to users working for Chef. Sorry, it's about software licensing. -# -# Chef-internal users, you will need to: -# 1. Create an Atlas account: https://atlas.hashicorp.com/ -# 2. Ping #eng-services-support with your Atlas account name -# to be added to the relevant team in Atlas, -# 3. Do `vagrant login` with your Atlas creds so that you can download -# the private boxes. -<% [ '', '-i386' ].each do |win_suffix| %> -- name: windows-2012r2-standard<%= win_suffix %> - driver: - box: chef/windows-server-2012r2-standard # private -<% end %> - -suites: - - name: windows - run_list: - - recipe[audit::default] - attributes: - audit: - collector: 'chef-compliance' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - owner: admin - # fail converge if downloaded profile is not present - fail_if_not_present: true - # fail converge after posting report if any audits have failed - fail_if_any_audits_failed: false - profiles: - base/windows: true diff --git a/examples/kitchen/Berksfile b/examples/kitchen/Berksfile deleted file mode 100644 index 12e6e564..00000000 --- a/examples/kitchen/Berksfile +++ /dev/null @@ -1,6 +0,0 @@ -# encoding: utf-8 -source 'https://supermarket.chef.io' - -cookbook 'os-hardening', git: 'https://github.com/dev-sec/chef-os-hardening.git' -cookbook 'ssh-hardening', git: 'https://github.com/dev-sec/chef-ssh-hardening.git' -cookbook 'audit', path: '../../' diff --git a/examples/kitchen/Gemfile b/examples/kitchen/Gemfile deleted file mode 100644 index 8323966b..00000000 --- a/examples/kitchen/Gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# encoding: utf-8 -source 'https://rubygems.org' - -gem 'berkshelf', '~> 4.3.5' -gem 'test-kitchen', '~> 1.6' -gem 'kitchen-vagrant' -gem 'kitchen-inspec', '~> 0.9' diff --git a/examples/kitchen/README.md b/examples/kitchen/README.md deleted file mode 100644 index b681d160..00000000 --- a/examples/kitchen/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Example: Test-Kitchen - -This example demonstrates the usage of the audit cookbook with test-kitchen. In order to use it, we expect to have `COMPLIANCE_API` and `COMPLIANCE_ACCESSTOKEN` available as environment variables. - -``` -export COMPLIANCE_API='https://compliance.test/api/' -export COMPLIANCE_ACCESSTOKEN='eyJh..GTA' -``` - -If you want to use the refresh token, use the following settings: - -``` -export COMPLIANCE_API='https://compliance.test/api' -export COMPLIANCE_REFRESHTOKEN='40/YUP...mA=='' -``` - -For Windows devs, you can set these environment variables in PowerShell (recommended over user/system variables): -``` -$env:COMPLIANCE_API = "https://compliance.test/api/" -$env:COMPLIANCE_ACCESSTOKEN = "eyJh..GTA" -$env:COMPLIANCE_REFRESHTOKEN = "11/z..==" -``` - -## Converge Linux - -``` - -$ KITCHEN_YAML=.kitchen.linux.yml kitchen list -Instance Driver Provisioner Verifier Transport Last Action -default-bento-centos-72 Vagrant ChefZero Inspec Ssh -default-bento-ubuntu-1404 Vagrant ChefZero Inspec Ssh - -$ KITCHEN_YAML=.kitchen.linux.yml kitchen converge ------> Starting Kitchen (v1.8.0) ------> Converging ... - -... - ------> Converging - -... - ------> Kitchen is finished. (0m35.94s) - -# destroy the instances -$ KITCHEN_YAML=.kitchen.linux.yml kitchen destroy -``` - -## Converge Windows - -``` -$ KITCHEN_YAML=.kitchen.win.yml kitchen list -Instance Driver Provisioner Verifier Transport Last Action -windows-windows-2012r2 Vagrant ChefZero Inspec Winrm - -$ KITCHEN_YAML=.kitchen.win.yml kitchen kitchen converge ------> Starting Kitchen (v1.8.0) ------> Converging - -... - ------> Kitchen is finished. (0m35.94s) - - -# destroy the instances -$ KITCHEN_YAML=.kitchen.win.yml kitchen destroy - -``` - - -Now, the node reports are available in Chef Compliance: - -![Chef Compliance Reports](cc_report.png "Chef Compliance Reports") - -If, configured, the reports are now in Chef Visibility instead: - -![Chef Visibility Reports](visib_reporting.png "Chef Visibility Reports") diff --git a/examples/kitchen/cc_report.png b/examples/kitchen/cc_report.png deleted file mode 100644 index 4749403ed69e10eea88cd3c850c8931e889f8c8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65522 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%0D^$FWVSiGRGPqNNZDyBJ~$e83v@dIg0? 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

9VFXP)=WIn)3Q*) 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 diff --git a/examples/kitchen/visib_reporting.png b/examples/kitchen/visib_reporting.png deleted file mode 100644 index fdb9df215e7d4fdfcdb584d1f0e4ca507d48d6f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61339 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' -# Your token from setting up Visibility -data_collector.token '<%= @auth_token %>' - -# If you want to change the default SSL certificate validation -#ssl_verify_mode :verify_none -#verify_api_cert false diff --git a/examples/visibility_win/test/integration/default/serverspec/default_spec.rb b/examples/visibility_win/test/integration/default/serverspec/default_spec.rb deleted file mode 100644 index 6e0b0df3..00000000 --- a/examples/visibility_win/test/integration/default/serverspec/default_spec.rb +++ /dev/null @@ -1,2 +0,0 @@ -# encoding: utf-8 -require 'spec_helper' diff --git a/examples/wrapper_audit/.kitchen.yml b/examples/wrapper_audit/.kitchen.yml deleted file mode 100644 index 80837df9..00000000 --- a/examples/wrapper_audit/.kitchen.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -driver: - name: vagrant - -provisioner: - name: chef_zero - -verifier: - name: inspec - sudo: true - -platforms: -# Your vagrant box name of a windows machines you have privately sourced -- name: windows2012r2 - driver: - # Your box or box_url should also be a privately hosted NFS, or URL, - # to publish your private Windows boxes - box: /vagrant/windows2012r2 - box_url: http://boxshare.yourdomain.com/vagrant/windows2012r2 - ostype: windows - shell_type: powershell - transport: - name: winrm - -# If you need to test a Linux-based profile, call a public box, such as this one. -- name: ubuntu-14.04 - driver: - box: bento/ubuntu-14.04 - -suites: - - name: windows - run_list: - # The run_list should be the wrapper cookbook. - - recipe[wrapper_audit::default] - attributes: - audit: - collector: 'chef-visibility' - server: <%= ENV['COMPLIANCE_API'] %> - token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> - refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> - insecure: true - # The owner should show up in the bottom-left of the home page of Compliance. - # If it is integrated with Chef Server, it will be the Chef Server org-name - owner: yourchef-orgname - profiles: - # Example default profile already in Compliance. - base/windows: true - # If you create and import a custom profile you wrote, you can also add it. - yourchef-orgname/customprofilename: true diff --git a/examples/wrapper_audit/Berksfile b/examples/wrapper_audit/Berksfile deleted file mode 100644 index f5f96eab..00000000 --- a/examples/wrapper_audit/Berksfile +++ /dev/null @@ -1,4 +0,0 @@ -# encoding: utf-8 -source 'https://supermarket.chef.io' - -metadata diff --git a/examples/wrapper_audit/README.md b/examples/wrapper_audit/README.md deleted file mode 100644 index 248e7a43..00000000 --- a/examples/wrapper_audit/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Example: Wrapper cookbook for `Audit` -This example cookbook demonstrates how you could wrap the audit cookbook with a customizable internal cookbook. This might be done to easily change default attributes set in the audit cookbook. The wrapper also helps you control the versioning of the audit cookbook in your environment. It can also be useful to help create roles to target where the audit cookbook applies, or even set attributes on nodes to apply Compliance profiles (if you had some you want to run on all machines). - -## Requirements - -### Platforms -- Windows Server 2008 R2 -- Windows Server 2012 -- Windows Server 2012 R2 -- Ubuntu 12.04 -- Ubuntu 14.04 - -### Chef -- Chef 12+ - -### Cookbooks -- `audit` -- `visibility_win` - -## Attributes -There are no custom attributes for this cookbook. - -## Usage -Include `wrapper_audit::default` in a node's `run_list`. This will also pull down the community audit cookbook, which is used to run Chef Compliance profiles. These profiles will create a report and send it to Chef Compliance or Visibility, depending on your [`audit`][`collector`] setting. - -This cookbook also consumes the example cookbook `visibility_win`, which demonstrates how to setup chef-client to ingest Visibility data. diff --git a/examples/wrapper_audit/metadata.rb b/examples/wrapper_audit/metadata.rb deleted file mode 100644 index 99e973e2..00000000 --- a/examples/wrapper_audit/metadata.rb +++ /dev/null @@ -1,15 +0,0 @@ -# encoding: utf-8 -name 'wrapper_audit' -maintainer 'Your Organization' -maintainer_email 'yourorganizationemail@domain.com' -license 'Proprietary - All Rights Reserved' -description 'Wrapper cookbook that runs Audit cookbook.' -long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version '0.1.0' - -# Put whatever operating systems your company supports where you may want -# to use Compliance profiles -supports 'windows' - -depends 'audit', '>= 0.14.1' -depends 'visibility_win', '>=0.1.8' diff --git a/examples/wrapper_audit/recipes/default.rb b/examples/wrapper_audit/recipes/default.rb deleted file mode 100644 index 54e62f51..00000000 --- a/examples/wrapper_audit/recipes/default.rb +++ /dev/null @@ -1,15 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: wrapper_audit -# Recipe:: default - -# This includes statement is to include the chef_client_config recipe in the -# visibility_win cookbook, which is another sample cookbook under the -# examples directory. The visibility_win cookbook provides an example of -# how you would setup chef-client to send converge data to your -# Chef Visibility server. -include_recipe 'visibility_win::chef_client_config' -# Set the collector to chef-visibility instead of the default chef-server. -node.default['audit']['collector'] = 'chef-visibility' -# Execute the community audit cookbook with the collector set -include_recipe 'audit::default' diff --git a/examples/wrapper_audit/spec/spec_helper.rb b/examples/wrapper_audit/spec/spec_helper.rb deleted file mode 100644 index a1e2776c..00000000 --- a/examples/wrapper_audit/spec/spec_helper.rb +++ /dev/null @@ -1,4 +0,0 @@ -# encoding: utf-8 -require 'chefspec' -require 'chefspec/berkshelf' -ChefSpec::Coverage.start! diff --git a/examples/wrapper_audit/spec/unit/recipes/default_spec.rb b/examples/wrapper_audit/spec/unit/recipes/default_spec.rb deleted file mode 100644 index 38c8633a..00000000 --- a/examples/wrapper_audit/spec/unit/recipes/default_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: wrapper_audit -# Spec:: default - -require 'spec_helper' - -describe 'wrapper_audit::default' do - let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) } -end diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb new file mode 100644 index 00000000..063dab7b --- /dev/null +++ b/files/default/audit_report.rb @@ -0,0 +1,39 @@ +require 'chef/handler' + +class Chef + class Handler + # Creates a compliance audit report + class AuditReport < ::Chef::Handler + def report + load_needed_dependencies + call + end + + def load_needed_dependencies + require "inspec" + # load supermarket plugin, this is part of the inspec gem + require "bundles/inspec-supermarket/api" + require "bundles/inspec-supermarket/target" + + # load the compliance plugin + require "bundles/inspec-compliance/configuration" + require "bundles/inspec-compliance/support" + require "bundles/inspec-compliance/http" + require "bundles/inspec-compliance/api" + require "bundles/inspec-compliance/target" + end + + def call + Chef::Log.debug "Initialize InSpec" + opts = { "format" => node['audit']['format'] } + runner = ::Inspec::Runner.new(opts) + + tests = node['audit']['profiles'] + tests.each { |target| runner.add_target(target, opts) } + + Chef::Log.debug "Running tests from: #{tests.inspect}" + exit_code = runner.run + end + end + end +end \ No newline at end of file diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb deleted file mode 100644 index 5e2adfd4..00000000 --- a/libraries/collector_classes.rb +++ /dev/null @@ -1,235 +0,0 @@ -# encoding: utf-8 -require 'json' -require_relative 'helper' - -class Collector - # - # Used to send inspec reports to Chef Visibility via the data_collector service - # - class ChefVisibility - @entity_uuid = nil - @run_id = nil - @blob = [] - - def initialize(entity_uuid, run_id, blob) - @entity_uuid = entity_uuid - @run_id = run_id - @blob = blob - 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 - - # 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 - - # Returns a hash with the counted controls based on their status and criticality - # 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] += 1 unless criticality.nil? - end - end - end - count - end - - # Return a json string containing the inspec report to be sent to the data_collector - def enriched_report - return nil unless @blob.is_a?(Hash) && @blob[:reports].is_a?(Hash) - final_report = {} - node_name = @blob[:node] # ~FC001, ~FC019, ~FC039 - total_duration = 0 - inspec_version = 'unknown' - # strip the report to leave only the profiles - final_report['profiles'] = @blob[:reports].map do |_name, content| - next unless content.is_a?(Hash) - inspec_version = content['version'] - total_duration += content['statistics']['duration'] - # reports generated by this cookbook have only one profile - content['profiles'][0] if content['profiles'].is_a?(Array) - end - - # remove nil profiles if any - final_report['profiles'].select! { |p| p } - - # 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']}" - final_report.to_json - end - - # Method used in order to send the inspec report to the data_collector server - def send_report - unless @entity_uuid && @run_id - Chef::Log.warn "entity_uuid(#{@entity_uuid}) or run_id(#{@run_id}) can't be nil, not sending report..." - return false - end - json_report = enriched_report - - unless json_report - Chef::Log.warn 'Something went wrong, enriched_report can\'t be nil' - return false - end - if defined?(Chef) && - defined?(Chef::Config) && - Chef::Config[:data_collector] && - Chef::Config[:data_collector][:token] && - Chef::Config[:data_collector][:server_url] - - dc = Chef::Config[:data_collector] - headers = { 'Content-Type' => 'application/json' } - unless dc[:token].nil? - headers['x-data-collector-token'] = dc[:token] - headers['x-data-collector-auth'] = 'version=1.0' - end - - begin - Chef::Log.info "Report to Chef Visibility: #{dc[:server_url]}" - Chef::Log.debug("POSTing the following message to #{dc[:server_url]}: #{json_report}") - http = Chef::HTTP.new(dc[:server_url]) - http.post(nil, json_report, headers) - return true - rescue => e - Chef::Log.error "send_inspec_report: POSTing to #{dc[:server_url]} returned: #{e.message}" - return false - end - else - Chef::Log.warn 'data_collector.token and data_collector.server_url must be defined in client.rb!' - return false - end - end - end - - # - # Used to send inspec reports to a Chef Complinace server via Chef Server - # - class ChefServer - include ComplianceHelpers - - @url = nil - @blob = nil - - def initialize(url, blob) - @url = url - @blob = blob - end - - def send_report - Chef::Config[:verify_api_cert] = false - Chef::Config[:ssl_verify_mode] = :verify_none - Chef::Log.info "Report to Chef Server: #{@url}" - rest = Chef::ServerAPI.new(@url, Chef::Config) - with_http_rescue do - rest.post(@url, @blob) - end - end - end - - # - # Used to send inspec reports to a Chef Complinace server - # - class ChefCompliance - include ComplianceHelpers - - @url = nil - @blob = nil - - def initialize(url, blob, token, raise_if_unreachable) - @url = url - @blob = blob - @token = token - @raise_if_unreachable = raise_if_unreachable - end - - def send_report - req = Net::HTTP::Post.new(@url, { 'Authorization' => "Bearer #{@token}" }) - req.body = @blob.to_json - Chef::Log.info "Report to Chef Compliance: #{@url}" - - opts = { use_ssl: @url.scheme == 'https', - verify_mode: OpenSSL::SSL::VERIFY_NONE, # FIXME - } - Net::HTTP.start(@url.host, @url.port, opts) do |http| - with_http_rescue do - http.request(req) - end - end - end - end -end diff --git a/libraries/compliance.rb b/libraries/compliance.rb deleted file mode 100644 index b2f4e37e..00000000 --- a/libraries/compliance.rb +++ /dev/null @@ -1,16 +0,0 @@ -# encoding: utf-8 - -# exchanges a refresh token into an access token -def retrieve_access_token(server_url, refresh_token, insecure) - require 'inspec' - require 'bundles/inspec-compliance/api' - require 'bundles/inspec-compliance/http' - require 'bundles/inspec-compliance/configuration' - # get_token_via_refresh_token is provided by the inspec-compliance plugin bundled in InSpec - success, msg, access_token = Compliance::API.get_token_via_refresh_token(server_url, refresh_token, insecure) - # TODO: we return always the access token, without proper error handling - unless success - Chef::Log.error("Unable to get a Chef Compliance API access_token: #{msg}") - end - access_token -end diff --git a/libraries/helper.rb b/libraries/helper.rb deleted file mode 100644 index e7cd26a8..00000000 --- a/libraries/helper.rb +++ /dev/null @@ -1,73 +0,0 @@ -# encoding: utf-8 -require 'uri' - -# This helps to construct compliance urls -module ComplianceHelpers - # returns the base url of the chef server - # Chef::Config[:chef_server_url] may be https://chef.compliance.test/organizations/brewinc - # returns 'https://chef.compliance.test' - def base_chef_server_url - cs = URI(Chef::Config[:chef_server_url]) - cs.path = '' - cs.to_s - end - - def construct_url(server, path) - # sanitize inputs - server << '/' unless server =~ %r{/\z} - path.sub!(%r{^/}, '') - server = URI(server) - server.path = server.path + path if path - server - end - - def handle_http_error_code(code) - case code - when /401|403/ - Chef::Log.error 'Auth issue: see audit cookbook TROUBLESHOOTING.md' - when /404/ - Chef::Log.error 'Object does not exist on remote server.' - end - msg = "Received HTTP error #{code}" - Chef::Log.error msg - raise msg if @raise_if_unreachable - end - - #rubocop:disable all - def with_http_rescue(&block) - begin - response = yield - if response.respond_to?(:code) - # handle non 200 error codes, they are not raised as Net::HTTPServerException - handle_http_error_code(response.code) if response.code.to_i >= 300 - end - return response - rescue Net::HTTPServerException => e - Chef::Log.error e - handle_http_error_code(e.response.code) - end - end - - # Returns the uuid for the current converge - def run_id - return unless run_context && - 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 - end - end - return nil - end - - # Returns the node's uuid - def entity_uuid - if (defined?(Chef) && - defined?(Chef::DataCollector) && - defined?(Chef::DataCollector::Messages) && - defined?(Chef::DataCollector::Messages.node_uuid)) - return Chef::DataCollector::Messages.node_uuid - end - end -end diff --git a/libraries/interval.rb b/libraries/interval.rb deleted file mode 100644 index 06aa8e62..00000000 --- a/libraries/interval.rb +++ /dev/null @@ -1,9 +0,0 @@ -# encoding: utf-8 - -def profile_overdue_to_run?(profile, interval) - # Calculate when the profile was last run so we delay it's next run if necessary - compliance_cache_directory = ::File.join(Chef::Config[:file_cache_path], 'compliance') - return true unless ::File.exist?("#{compliance_cache_directory}/#{profile}") - seconds_since_last_run = Time.now - ::File.mtime("#{compliance_cache_directory}/#{profile}") - seconds_since_last_run > interval -end diff --git a/libraries/matchers.rb b/libraries/matchers.rb deleted file mode 100644 index 9b82a5d2..00000000 --- a/libraries/matchers.rb +++ /dev/null @@ -1,27 +0,0 @@ -# encoding: utf-8 - -# used by ChefSpec -if defined?(ChefSpec) - - ChefSpec.define_matcher :compliance_profile - - def create_compliance_token(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_token, :create, resource_name) - end - - def fetch_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :fetch, resource_name) - end - - def upload_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :upload, resource_name) - end - - def execute_compliance_profile(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_profile, :execute, resource_name) - end - - def execute_compliance_report(resource_name) - ChefSpec::Matchers::ResourceMatcher.new(:compliance_report, :execute, resource_name) - end -end diff --git a/libraries/server_api.rb b/libraries/server_api.rb deleted file mode 100644 index 0afff233..00000000 --- a/libraries/server_api.rb +++ /dev/null @@ -1,40 +0,0 @@ -# encoding: utf-8 - -require 'uri' - -class Chef - # we need to activate because we need binmode on the tempfile - class ServerAPI - def binmode_streaming_request(path, headers = {}) - url = create_url(path) - tempfile = nil - - method = :GET - method, url, headers, data = apply_request_middleware(method, url, headers, data) - - response, _rest_request, _return_value = send_http_request(method, url, headers, data) do |http_response| - if http_response.is_a?(Net::HTTPSuccess) - tempfile = binmode_stream_to_tempfile(url, http_response) - tempfile.close - end - end - - return nil if response.is_a?(Net::HTTPRedirection) - response.error! unless response.is_a?(Net::HTTPSuccess) - - tempfile - end - - def binmode_stream_to_tempfile(_url, response) - file = ::Tempfile.new(['compliance-profile', '.tgz']) - file.binmode # !!! - - stream_handler = StreamHandler.new(middlewares, response) - - response.read_body do |chunk| - file.write(stream_handler.handle_chunk(chunk)) - end - file - end - end -end diff --git a/metadata.rb b/metadata.rb index eb5ff57d..e5337634 100644 --- a/metadata.rb +++ b/metadata.rb @@ -13,3 +13,4 @@ chef_version '>= 12.5.1' if respond_to?(:chef_version) depends 'compat_resource' +depends 'chef_handler' \ No newline at end of file diff --git a/recipes/_inspec.rb b/recipes/_inspec.rb deleted file mode 100644 index 54706f2f..00000000 --- a/recipes/_inspec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: compliance -# Recipe:: inspec -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -inspec_version = node['audit']['inspec_version'] - -# install inspec if require -inspec 'inspec' do - version inspec_version - action :install -end diff --git a/recipes/default.rb b/recipes/default.rb index ac3168a7..81c714f2 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,91 +1,21 @@ -# encoding: utf-8 -# -# Cookbook Name:: compliance -# Recipe:: default -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. +include_recipe 'chef_handler' -# ensure inspec is available -include_recipe 'audit::_inspec' +handler_directory = ::File.join(Chef::Config[:file_cache_path], 'handler') -# read selected reporter -report_collector = node['audit']['collector'] - -# These attributes should only be set when connecting directly to Chef Compliance, otherwise they should be nil -server = node['audit']['server'] - -# only needed when fetching / reporting directly to Compliance Server -compliance_token 'Compliance Token' do - server server - token node['audit']['refresh_token'] || node['audit']['token'] - insecure node['audit']['insecure'] -end unless server.nil? - -# set the inspec report format based on collector -formatter = report_collector == 'chef-visibility' ? 'json' : 'json-min' - -# handle intervals -interval_seconds = 0 # always run this by default, unless interval is defined -if !node['audit']['interval'].nil? && node['audit']['interval']['enabled'] - interval_seconds = node['audit']['interval']['time'] * 60 # seconds in interval - Chef::Log.debug "Auditing this machine every #{interval_seconds} seconds " -end - -# ensure profile cache directory is available -compliance_cache_directory = ::File.join(Chef::Config[:file_cache_path], 'compliance') -directory compliance_cache_directory do +directory handler_directory do action :create end -# iterate over all selected profiles and download them -node['audit']['profiles'].each do |owner_profile, value| - case value - when Hash - next if value['disabled'] - path = value['source'] - else - next if value == false - end - raise "Invalid profile name '#{owner_profile}'. "\ - "Must contain /, e.g. 'john/ssh'" if owner_profile !~ %r{\/} - o, p = owner_profile.split('/').last(2) - - # file that can be used for interval triggering - file "#{compliance_cache_directory}/#{p}" do - action :nothing - end +cookbook_file ::File.join(handler_directory, 'audit_report.rb') do + source 'audit_report.rb' +end - # execute profile - compliance_profile p do - owner o - formatter formatter - server server - path path unless path.nil? - quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? - only_if { profile_overdue_to_run?(p, interval_seconds) } - action [:fetch, :execute] - notifies :touch, "file[#{compliance_cache_directory}/#{p}]", :delayed - notifies :execute, "compliance_report[#{report_collector}]", :delayed - end +chef_handler 'Chef::Handler::AuditReport' do + source "#{handler_directory}/audit_report.rb" + supports :report => true + action :enable end -# report the results -compliance_report report_collector do - owner node['audit']['owner'] - server server - collector report_collector - quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? - action :nothing -end if node['audit']['profiles'].values.any? +chef_inspec 'inspec' do + action :install +end diff --git a/recipes/upload.rb b/recipes/upload.rb deleted file mode 100644 index 7264da85..00000000 --- a/recipes/upload.rb +++ /dev/null @@ -1,55 +0,0 @@ -# encoding: utf-8 -# -# Cookbook Name:: audit -# Recipe:: upload -# -# Copyright 2016 Chef Software, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# ensure inspec is available -include_recipe 'audit::_inspec' - -# These attributes should only be set when connecting directly to Chef Compliance, otherwise they should be nil -server = node['audit']['server'] - -# only needed when fetching / reporting directly to Compliance Server -compliance_token 'Compliance Token' do - server server - token node['audit']['refresh_token'] || node['audit']['token'] - insecure node['audit']['insecure'] -end unless server.nil? - -# iterate over all selected profiles and upload them -node['audit']['profiles'].each do |owner_profile, value| - case value - when Hash - next if value['disabled'] - path = value['source'] - else - next if value == false - end - raise "Invalid profile name '#{owner_profile}'. "\ - "Must contain /, e.g. 'john/ssh'" if owner_profile !~ %r{\/} - o, p = owner_profile.split('/').last(2) - - # upload profile - compliance_profile p do - owner o - server server - path path - insecure node['audit']['insecure'] - overwrite node['audit']['overwrite'] - action :upload - end -end diff --git a/resources/inspec.rb b/resources/inspec.rb index ac0d32fa..d23d56c4 100644 --- a/resources/inspec.rb +++ b/resources/inspec.rb @@ -1,7 +1,7 @@ # encoding: utf-8 provides :chef_inspec -resource_name :inspec # FIXME: why is this different than the provides name? +resource_name :chef_inspec property :version, String, default: 'latest' diff --git a/resources/profile.rb b/resources/profile.rb deleted file mode 100644 index 4f049dc9..00000000 --- a/resources/profile.rb +++ /dev/null @@ -1,217 +0,0 @@ -# encoding: utf-8 -require 'tempfile' -require 'uri' -require 'net/https' -require 'fileutils' - -provides :compliance_profile -include ComplianceHelpers - -property :profile, String, name_property: true -property :owner, String, required: true - -# to use a chef-compliance server that is used with chef-server integration -property :server, [String, URI, nil] -property :port, Integer -property :insecure, [TrueClass, FalseClass], default: false -property :formatter, ['json', 'json-min'], default: 'json-min' -property :quiet, [TrueClass, FalseClass], default: true -property :overwrite, [TrueClass, FalseClass], default: true -# TODO(sr) it might be nice to default to settings from attributes - -# alternative to (owner, profile)-addressing for profiles, -# e.g. for running profiles from disk (coming from some other source) -property :path, String - -default_action :execute - -action :fetch do - converge_by 'load required inspec modules' do - require 'inspec' - # load the supermarket plugin - require 'bundles/inspec-supermarket/api' - require 'bundles/inspec-supermarket/target' - - # load the compliance api plugin - require 'bundles/inspec-compliance/api' - require 'bundles/inspec-compliance/http' - end - - converge_by 'create cache directory' do - directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) - end - - converge_by 'fetch compliance profile' do - return if path # will be fetched from other source during execute phase - - o, p = normalize_owner_profile - Chef::Log.info "Fetch compliance profile #{o}/#{p}" - - path = tar_path - node.run_state['compliance'] ||= {} - - if node.run_state['compliance']['access_token'] # go direct - reqpath ="owners/#{o}/compliance/#{p}/tar" - url = construct_url(server, reqpath) - Chef::Log.info "Load profile from: #{url}" - - tf = Tempfile.new('foo', Dir.tmpdir, binmode: true) - - opts = { use_ssl: url.scheme == 'https', - verify_mode: OpenSSL::SSL::VERIFY_NONE, # FIXME - } - Net::HTTP.start(url.host, url.port, opts) do |http| - resp = with_http_rescue do - http.get(url.path, 'Authorization' => "Bearer #{node.run_state['compliance']['access_token']}") - end - tf.write(resp.body) - end - tf.flush - else # go through Chef::ServerAPI - reqpath ="organizations/#{org}/owners/#{o}/compliance/#{p}/tar" - url = construct_url(base_chef_server_url + '/compliance/', reqpath) - Chef::Log.info "Load profile from: #{url}" - - Chef::Config[:verify_api_cert] = false # FIXME - Chef::Config[:ssl_verify_mode] = :verify_none # FIXME - - rest = Chef::ServerAPI.new(url, Chef::Config) - tf = with_http_rescue do - rest.binmode_streaming_request(url) - end - end - - case node['platform'] - when 'windows' - # mv replaced due to Errno::EACCES: - # https://bugs.ruby-lang.org/issues/10865 - FileUtils.cp(tf.path, path) unless tf.nil? - else - FileUtils.mv(tf.path, path) unless tf.nil? - end - - end -end - -action :execute do - # ensure it's there, if if the profile wasn't fetched using these resources - converge_by 'load required inspec modules' do - require 'inspec' - end - - converge_by 'create/verify cache directory' do - directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) - end - - converge_by 'execute compliance profile' do - path ||= tar_path - report_file = report_path - - supported_schemes = %w{http https supermarket compliance chefserver} - if !supported_schemes.include?(URI(path).scheme) && !::File.exist?(path) - Chef::Log.warn "No such path! Skipping: #{path}" - raise "Aborting since profile is not present here: #{path}" if run_context.node['audit']['fail_if_not_present'] - return - end - - Chef::Log.info "Executing: #{path}" - - # TODO: flesh out inspec's report CLI interface, - # make this an execute[inspec check ...] - output = quiet ? ::File::NULL : $stdout - runner = ::Inspec::Runner.new('report' => true, 'format' => formatter, 'output' => output) - runner.add_target(path, {}) - begin - runner.run - # TODO: weird exception, do we need that handling? - rescue Chef::Exceptions::ValidationFailed => e - Chef::Log.error e - end - - file report_file do - content runner.report.to_json - sensitive true - backup false - end - end -end - -action :upload do - converge_by 'run profile validation checks' do - raise 'Path to profile archive not specified' if path.nil? - raise "Profile archive file #{path} does not exist." unless ::File.exist?(path) - profile = Inspec::Profile.for_target(path, {}) - error_count = 0 - lambda { |msg| - error_count += 1 - Chef::Log.error msg - } - result = profile.check - Chef::Log.info result[:summary].inspect - raise 'Profile check failed' unless result[:summary][:valid] - Chef::Log.info 'Profile is valid' - end - - converge_by 'upload compliance profile' do - o, p = normalize_owner_profile - node.run_state['compliance'] ||= {} - - if node.run_state['compliance']['access_token'] - reqpath ="owners/#{o}/compliance/#{p}/tar" - url = construct_url(server, reqpath) - Chef::Log.info "Upload from #{path} to: #{url}" - config = Compliance::Configuration.new - config['token'] = node.run_state['compliance']['access_token'] - config['insecure'] = insecure - config['server'] = server - config['version'] = Compliance::API.version(server, insecure) - if Compliance::API.exist?(config, "#{o}/#{p}") && !overwrite - raise 'Profile exists on the server, use property `overwrite`' - else - success, msg = Compliance::API.upload(config, o, p, path) - if success - Chef::Log.info 'Successfully uploaded profile' - else - Chef::Log.error "Error during profile upload: #{msg}" - end - end - else - raise 'Unable to read access token, aborting upload' - end - end -end - -def normalize_owner_profile - if profile.include?('/') - profile.split('/').last(2) - else - [owner || 'base', profile] - end -end - -def tar_path - return path if path - o, p = normalize_owner_profile - case node['platform'] - when 'windows' - windows_path = Chef::Config[:file_cache_path].tr('\\', '/') - ::File.join(windows_path, 'compliance', "#{o}_#{p}.tgz") - else - ::File.join(Chef::Config[:file_cache_path], 'compliance', "#{o}_#{p}.tgz") - end -end - -def report_path - o, p = normalize_owner_profile - case node['platform'] - when 'windows' - windows_path = Chef::Config[:file_cache_path].tr('\\', '/') - ::File.join(windows_path, 'compliance', "#{o}_#{p}_report.json") - else - ::File.join(Chef::Config[:file_cache_path], 'compliance', "#{o}_#{p}_report.json") - end -end - -def org - Chef::Config[:chef_server_url].split('/').last -end diff --git a/resources/report.rb b/resources/report.rb deleted file mode 100644 index 64ef7069..00000000 --- a/resources/report.rb +++ /dev/null @@ -1,126 +0,0 @@ -# encoding: utf-8 -# `compliance_report` custom resource to run Chef Compliance profiles and -# send reports to Chef Compliance - -include ComplianceHelpers -provides :compliance_report - -property :name, String, name_property: true - -# to use a chef-compliance server that is used with chef-server integration -property :server, [String, URI, nil] -property :port, Integer -property :insecure, [TrueClass, FalseClass], default: false -property :quiet, [TrueClass, FalseClass], default: true -property :collector, ['chef-visibility', 'chef-compliance', 'chef-server'], default: 'chef-server' - -property :environment, String # default: node.environment -property :owner, [String, nil] - -default_action :execute - -action :execute do - converge_by "report compliance profiles' results" do - reports, ownermap = compound_report(profiles) - blob = node_info - blob[:reports] = reports - blob[:profiles] = ownermap - - formatter = collector == 'chef-visibility' ? 'json' : 'json-min' - # counting total_failed based on the json/json-min format - if formatter == 'json' - total_failed = reports.map do |_name, report| - report['profiles'].map do |profile| - profile['controls'].map do |control| - if control['results'] - control['results'].map do |result| - result['status'] != 'passed' ? 1 : 0 - end - else - 0 - end - end - end - end.flatten.reduce(:+) - else - total_failed = reports.map do |_name, profile| - if !profile['controls'].empty? - profile['controls'].map do |control| - control['status'] != 'passed' ? 1 : 0 - end - else - 0 - end - end.flatten.reduce(:+) - end - Chef::Log.info "Total number of failed controls: #{total_failed}" - - # resolve owner - o = return_or_guess_owner - - raise_if_unreachable = run_context.node['audit']['raise_if_unreachable'] if run_context.node['audit'] - - case collector - when 'chef-visibility' - Collector::ChefVisibility.new(entity_uuid, run_id, blob).send_report - when 'chef-compliance' - node.run_state['compliance'] ||= {} - if node.run_state['compliance']['access_token'] && server - url = construct_url(server, ::File.join('/owners', o, 'inspec')) - Collector::ChefCompliance.new(url, blob, node.run_state['compliance']['access_token'], raise_if_unreachable).send_report - else - Chef::Log.warn "'server' and 'token' properties required by inspec report collector '#{collector}'. Skipping..." - end - when 'chef-server' - chef_url = server || base_chef_server_url - if chef_url - url = construct_url(chef_url + '/compliance/', ::File.join('organizations', o, 'inspec')) - Collector::ChefServer.new(url, blob).send_report - else - Chef::Log.warn "unable to determine chef-server url required by inspec report collector '#{collector}'. Skipping..." - end - else - Chef::Log.warn "#{collector} is not a supported inspec report collector" - end - - raise "#{total_failed} audits have failed. Aborting chef-client run." if total_failed > 0 && node['audit']['fail_if_any_audits_failed'] - end -end - -# filters resource collection -def profiles - run_context.resource_collection.select do |r| - r.is_a?(AuditProfile) - end.flatten -end - -def compound_report(*profiles) - report = {} - ownermap = {} - - profiles.flatten.each do |prof| - next unless ::File.exist?(prof.report_path) - o, p = prof.normalize_owner_profile - report[p] = ::JSON.parse(::File.read(prof.report_path)) - ownermap[p] = o - end - - [report, ownermap] -end - -def node_info - n = run_context.node - { - node: n.name, - os: { - # arch: os[:arch], - release: n['platform_version'], - family: n['platform'], - }, - environment: environment || n.environment, - } -end - -def return_or_guess_owner - owner || Chef::Config[:chef_server_url].split('/').last -end diff --git a/resources/token.rb b/resources/token.rb deleted file mode 100644 index a721fa5a..00000000 --- a/resources/token.rb +++ /dev/null @@ -1,26 +0,0 @@ -# encoding: utf-8 -# `compliance_token` custom resource to communicate with Chef Compliance -include ComplianceHelpers - -provides :compliance_token - -property :server, [String, URI, nil], required: true -property :port, Integer -property :token, [String, nil], required: true -property :insecure, [TrueClass, FalseClass], default: false - -default_action :create - -action :create do - converge_by 'compliance server auth token setup' do - # stash token in node.run_state to pass between resources - node.run_state['compliance'] ||= {} - if node['audit']['refresh_token'] - Chef::Log.info 'Using refresh_token to exchange for an access token.' - node.run_state['compliance']['access_token'] = retrieve_access_token(server, token, insecure) - else - Chef::Log.info 'Using token attribute. This token is short lived and will expire.' - node.run_state['compliance']['access_token'] = token - end - end -end From c93b3d0576b046e679c50528b94456e172043613 Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Tue, 18 Oct 2016 14:31:14 -0400 Subject: [PATCH 5/8] setting up visibility reporting. almost there. --- attributes/default.rb | 6 +- files/default/audit_report.rb | 2 +- libraries/collector_classes.rb | 173 +++++++++++++++++++++++++++++++++ libraries/helper.rb | 27 +++++ recipes/default.rb | 4 + resources/report.rb | 16 +++ 6 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 libraries/collector_classes.rb create mode 100644 libraries/helper.rb create mode 100644 resources/report.rb diff --git a/attributes/default.rb b/attributes/default.rb index fdf7de58..327d9fab 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -62,4 +62,8 @@ default['audit']['format'] = "json" # set profiles to empty array as default -default['audit']['profiles'] = [] \ No newline at end of file +default['audit']['profiles'] = [] + +# output for inspec results +result_path = File.expand_path("../../inspec_results.txt", __FILE__) +default['audit']['output'] = result_path \ No newline at end of file diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb index 063dab7b..b751f59f 100644 --- a/files/default/audit_report.rb +++ b/files/default/audit_report.rb @@ -25,7 +25,7 @@ def load_needed_dependencies def call Chef::Log.debug "Initialize InSpec" - opts = { "format" => node['audit']['format'] } + opts = { "format" => node['audit']['format'], "output" => node['audit']['output']} runner = ::Inspec::Runner.new(opts) tests = node['audit']['profiles'] diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb new file mode 100644 index 00000000..2a193774 --- /dev/null +++ b/libraries/collector_classes.rb @@ -0,0 +1,173 @@ +# encoding: utf-8 +require 'json' +require_relative 'helper' + +class Collector + # + # Used to send inspec reports to Chef Visibility via the data_collector service + # + class ChefVisibility + @entity_uuid = nil + @run_id = nil + @node_name = '' + + def initialize(entity_uuid, run_id, node_name) + @entity_uuid = entity_uuid + @run_id = run_id + @node_name = node_name + end + + # Method used in order to send the inspec report to the data_collector server + def send_report + unless @entity_uuid && @run_id + Chef::Log.warn "entity_uuid(#{@entity_uuid}) or run_id(#{@run_id}) can't be nil, not sending report..." + return false + end + + # get file contents where inspec results were saved + result_path = File.expand_path("../../inspec_results.txt", __FILE__) + file = File.open(result_path, "rb") + content = file.read + file.close + + # parse that string of contents into json + json_report = enriched_report(JSON.parse(content)) + + unless json_report + Chef::Log.warn 'Something went wrong, report can\'t be nil' + return false + end + if defined?(Chef) && + defined?(Chef::Config) && + Chef::Config[:data_collector] && + Chef::Config[:data_collector][:token] && + Chef::Config[:data_collector][:server_url] + + dc = Chef::Config[:data_collector] + headers = { 'Content-Type' => 'application/json' } + unless dc[:token].nil? + headers['x-data-collector-token'] = dc[:token] + headers['x-data-collector-auth'] = 'version=1.0' + end + + begin + Chef::Log.info "Report to Chef Visibility: #{dc[:server_url]}" + Chef::Log.debug("POSTing the following message to #{dc[:server_url]}: #{json_report}") + http = Chef::HTTP.new(dc[:server_url]) + http.post(nil, json_report, headers) + return true + rescue => e + Chef::Log.error "send_inspec_report: POSTing to #{dc[:server_url]} returned: #{e.message}" + return false + end + else + Chef::Log.warn 'data_collector.token and data_collector.server_url must be defined in client.rb!' + return false + end + end + + # *************************************************************************************** + # TODO: We could likely simplify/remove alot of the extra logic we have here with a small + # revamp of the visibility expected input. + # *************************************************************************************** + + def enriched_report(content) + return nil unless content.is_a?(Hash) + final_report = {} + total_duration = content['statistics']['duration'] + inspec_version = content['version'] + + # strip the report to leave only the profiles + final_report['profiles'] = content['profiles'] + + # remove nil profiles if any + final_report['profiles'].select! { |p| p } + + # 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']}" + final_report.to_json + end + + # Returns a hash with the counted controls based on their status and criticality + # 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] += 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 + + # 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 +end \ No newline at end of file diff --git a/libraries/helper.rb b/libraries/helper.rb new file mode 100644 index 00000000..0057b623 --- /dev/null +++ b/libraries/helper.rb @@ -0,0 +1,27 @@ +# encoding: utf-8 + +module ReportHelpers + + # Returns the uuid for the current converge + def run_id + return unless run_context && + 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 + end + end + return nil + end + + # Returns the node's uuid + def entity_uuid + if (defined?(Chef) && + defined?(Chef::DataCollector) && + defined?(Chef::DataCollector::Messages) && + defined?(Chef::DataCollector::Messages.node_uuid)) + return Chef::DataCollector::Messages.node_uuid + end + end +end \ No newline at end of file diff --git a/recipes/default.rb b/recipes/default.rb index 81c714f2..79531e0e 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -19,3 +19,7 @@ chef_inspec 'inspec' do action :install end + +inspec_report 'report' do + action :execute +end \ No newline at end of file diff --git a/resources/report.rb b/resources/report.rb new file mode 100644 index 00000000..00d93c3e --- /dev/null +++ b/resources/report.rb @@ -0,0 +1,16 @@ +# encoding: utf-8 + +include ReportHelpers +provides :inspec_report +resource_name :inspec_report + +property :collector, String, default: 'chef-visibility' + +default_action :execute + +action :execute do + case collector + when 'chef-visibility' + Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report + end +end From c730ead95350b892caecf4db3cee1f0c3c85cf69 Mon Sep 17 00:00:00 2001 From: Victoria Jeffrey Date: Tue, 18 Oct 2016 21:49:26 -0400 Subject: [PATCH 6/8] fixing lint errors. most tests fixed. Signed-off-by: Victoria Jeffrey --- attributes/default.rb | 6 +- files/default/audit_report.rb | 26 +-- libraries/collector_classes.rb | 17 +- libraries/helper.rb | 15 +- metadata.rb | 2 +- recipes/default.rb | 3 +- resources/report.rb | 4 +- spec/unit/recipes/default_spec.rb | 321 +++++++++++++++--------------- spec/unit/recipes/upload_spec.rb | 84 ++++---- 9 files changed, 244 insertions(+), 234 deletions(-) diff --git a/attributes/default.rb b/attributes/default.rb index 327d9fab..36e26859 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -59,11 +59,11 @@ default['audit']['overwrite'] = true # use json format since this is for reporting -default['audit']['format'] = "json" +default['audit']['format'] = 'json' # set profiles to empty array as default default['audit']['profiles'] = [] # output for inspec results -result_path = File.expand_path("../../inspec_results.txt", __FILE__) -default['audit']['output'] = result_path \ No newline at end of file +result_path = File.expand_path('../../inspec_results.txt', __FILE__) +default['audit']['output'] = result_path diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb index b751f59f..2146241e 100644 --- a/files/default/audit_report.rb +++ b/files/default/audit_report.rb @@ -10,30 +10,30 @@ def report end def load_needed_dependencies - require "inspec" + require 'inspec' # load supermarket plugin, this is part of the inspec gem - require "bundles/inspec-supermarket/api" - require "bundles/inspec-supermarket/target" + require 'bundles/inspec-supermarket/api' + require 'bundles/inspec-supermarket/target' # load the compliance plugin - require "bundles/inspec-compliance/configuration" - require "bundles/inspec-compliance/support" - require "bundles/inspec-compliance/http" - require "bundles/inspec-compliance/api" - require "bundles/inspec-compliance/target" + require 'bundles/inspec-compliance/configuration' + require 'bundles/inspec-compliance/support' + require 'bundles/inspec-compliance/http' + require 'bundles/inspec-compliance/api' + require 'bundles/inspec-compliance/target' end def call - Chef::Log.debug "Initialize InSpec" - opts = { "format" => node['audit']['format'], "output" => node['audit']['output']} + Chef::Log.debug 'Initialize InSpec' + opts = { 'format' => node['audit']['format'], 'output' => node['audit']['output'] } runner = ::Inspec::Runner.new(opts) tests = node['audit']['profiles'] tests.each { |target| runner.add_target(target, opts) } - Chef::Log.debug "Running tests from: #{tests.inspect}" - exit_code = runner.run + Chef::Log.debug 'Running tests from: #{tests.inspect}' + runner.run end end end -end \ No newline at end of file +end diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb index 2a193774..47691e0c 100644 --- a/libraries/collector_classes.rb +++ b/libraries/collector_classes.rb @@ -25,8 +25,8 @@ def send_report end # get file contents where inspec results were saved - result_path = File.expand_path("../../inspec_results.txt", __FILE__) - file = File.open(result_path, "rb") + result_path = File.expand_path('../../inspec_results.txt', __FILE__) + file = File.open(result_path, 'rb') content = file.read file.close @@ -158,6 +158,17 @@ def compliance_status(counts) 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) @@ -170,4 +181,4 @@ def control_status(results) status end end -end \ No newline at end of file +end diff --git a/libraries/helper.rb b/libraries/helper.rb index 0057b623..f21581d9 100644 --- a/libraries/helper.rb +++ b/libraries/helper.rb @@ -1,27 +1,26 @@ # encoding: utf-8 module ReportHelpers - # Returns the uuid for the current converge def run_id return unless run_context && 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)) + if sub.class == Chef::ResourceReporter && defined?(sub.run_id) return sub.run_id end end - return nil + nil end # Returns the node's uuid def entity_uuid - if (defined?(Chef) && - defined?(Chef::DataCollector) && - defined?(Chef::DataCollector::Messages) && - defined?(Chef::DataCollector::Messages.node_uuid)) + if defined?(Chef) && + defined?(Chef::DataCollector) && + defined?(Chef::DataCollector::Messages) && + defined?(Chef::DataCollector::Messages.node_uuid) return Chef::DataCollector::Messages.node_uuid end end -end \ No newline at end of file +end diff --git a/metadata.rb b/metadata.rb index e5337634..ef380344 100644 --- a/metadata.rb +++ b/metadata.rb @@ -13,4 +13,4 @@ chef_version '>= 12.5.1' if respond_to?(:chef_version) depends 'compat_resource' -depends 'chef_handler' \ No newline at end of file +depends 'chef_handler' diff --git a/recipes/default.rb b/recipes/default.rb index 79531e0e..8247c900 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -12,7 +12,6 @@ chef_handler 'Chef::Handler::AuditReport' do source "#{handler_directory}/audit_report.rb" - supports :report => true action :enable end @@ -22,4 +21,4 @@ inspec_report 'report' do action :execute -end \ No newline at end of file +end diff --git a/resources/report.rb b/resources/report.rb index 00d93c3e..4eb27a6e 100644 --- a/resources/report.rb +++ b/resources/report.rb @@ -10,7 +10,7 @@ action :execute do case collector - when 'chef-visibility' - Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report + when 'chef-visibility' + Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report end end diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb index 58d82bef..d0a88c27 100644 --- a/spec/unit/recipes/default_spec.rb +++ b/spec/unit/recipes/default_spec.rb @@ -30,164 +30,165 @@ expect { chef_run }.to_not raise_error end end - - context 'When server and refresh_token are specified' do - let(:chef_run) do - ChefSpec::ServerRunner.new do |node| - node.override['audit']['collector'] = 'chef-compliance' - node.override['audit']['profiles'] = { 'admin/myprofile' => true } - node.override['audit']['server'] = 'https://my.compliance.test/api' - node.override['audit']['refresh_token'] = 'abcdefg' - node.override['audit']['insecure'] = true - end.converge(described_recipe) - end - - it 'creates compliance_token resource' do - expect(chef_run).to create_compliance_token('Compliance Token').with( - server: 'https://my.compliance.test/api', - insecure: true, - token: 'abcdefg' - ) - end - - it 'fetches and executes compliance_profile[myprofile]' do - expect(chef_run).to fetch_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - ) - expect(chef_run).to execute_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - ) - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'When two profiles are specified' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true, - 'base/ssh' => false } - runner.node.override['audit']['inspec_version'] = 'latest' - runner.node.override['audit']['quiet'] = true - runner.converge(described_recipe) - end - let(:myprofile) { chef_run.compliance_profile('myprofile') } - - it 'fetches and executes compliance_profile[myprofile]' do - expect(chef_run).to fetch_compliance_profile('myprofile').with( - owner: 'admin', - server: nil, - token: nil, - ) - expect(chef_run).to execute_compliance_profile('myprofile').with( - owner: 'admin', - server: nil, - token: nil, - quiet: true, - ) - end - - it 'notifies compliance_report[chef-server]' do - expect(myprofile).to notify('compliance_report[chef-server]').delayed - end - - it 'skips compliance_profile[ssh]' do - expect(chef_run).to_not fetch_compliance_profile('ssh') - expect(chef_run).to_not execute_compliance_profile('ssh') - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'When invalid profile is passed' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'myprofile' => true } - runner.converge(described_recipe) - end - - it 'does raise an error' do - expect { chef_run }.to raise_error("Invalid profile name 'myprofile'. Must contain /, e.g. 'john/ssh'") - end - end - - context 'When specifying profiles with alternate sources' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { - 'base/linux' => true, - 'base/apache' => false, - 'brewinc/ssh-hardening' => { - 'source' => 'supermarket://hardening/ssh-hardening', - }, - 'brewinc/tmp_compliance_profile' => { - 'source' => 'https://github.com/nathenharvey/tmp_compliance_profile', - }, - 'brewinc/tmp_compliance_profile-master' => { - 'source' => '/tmp/tmp_compliance_profile-master', - }, - 'exampleorg/myprofile' => { - 'disabled' => true, - }, - } - runner.converge(described_recipe) - end - let(:linux_profile) { chef_run.compliance_profile('linux') } - - it 'executes base/linux in backward compatible mode' do - expect(chef_run).to execute_compliance_profile('linux').with( - path: nil, - ) - end - it 'executes brewinc/ssh-hardening from supermarket' do - expect(chef_run).to execute_compliance_profile('ssh-hardening').with( - path: 'supermarket://hardening/ssh-hardening', - ) - end - it 'executes brewinc/tmp_compliance_profile from github' do - expect(chef_run).to execute_compliance_profile('tmp_compliance_profile').with( - path: 'https://github.com/nathenharvey/tmp_compliance_profile', - ) - end - it 'executes brewinc/tmp_compliance_profile-master from filesystem' do - expect(chef_run).to execute_compliance_profile('tmp_compliance_profile-master').with( - path: '/tmp/tmp_compliance_profile-master', - ) - end - it 'does not execute disabled exampleorg/myprofile' do - expect(chef_run).to_not execute_compliance_profile('myprofile') - end - it 'notifies compliance_report[chef-server]' do - expect(linux_profile).to notify('compliance_report[chef-server]').delayed - end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end - - context 'when set to run on an interval and not due to run' do - before(:each) do - allow_any_instance_of(Chef::Resource).to receive(:profile_overdue_to_run?).and_return(false) - end - - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') - runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true } - runner.node.override['audit']['interval']['enabled'] = true - runner.converge(described_recipe) - end - - it 'does not fetch or execute on compliance profile' do - expect(chef_run).to_not fetch_compliance_profile('myprofile') - expect(chef_run).to_not execute_compliance_profile('myprofile') - end - - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end end + +# context 'When server and refresh_token are specified' do +# let(:chef_run) do +# ChefSpec::ServerRunner.new do |node| +# node.override['audit']['collector'] = 'chef-compliance' +# node.override['audit']['profiles'] = { 'admin/myprofile' => true } +# node.override['audit']['server'] = 'https://my.compliance.test/api' +# node.override['audit']['refresh_token'] = 'abcdefg' +# node.override['audit']['insecure'] = true +# end.converge(described_recipe) +# end + +# it 'creates compliance_token resource' do +# expect(chef_run).to create_compliance_token('Compliance Token').with( +# server: 'https://my.compliance.test/api', +# insecure: true, +# token: 'abcdefg' +# ) +# end + +# it 'fetches and executes compliance_profile[myprofile]' do +# expect(chef_run).to fetch_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# ) +# expect(chef_run).to execute_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# ) +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'When two profiles are specified' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true, +# 'base/ssh' => false } +# runner.node.override['audit']['inspec_version'] = 'latest' +# runner.node.override['audit']['quiet'] = true +# runner.converge(described_recipe) +# end +# let(:myprofile) { chef_run.compliance_profile('myprofile') } + +# it 'fetches and executes compliance_profile[myprofile]' do +# expect(chef_run).to fetch_compliance_profile('myprofile').with( +# owner: 'admin', +# server: nil, +# token: nil, +# ) +# expect(chef_run).to execute_compliance_profile('myprofile').with( +# owner: 'admin', +# server: nil, +# token: nil, +# quiet: true, +# ) +# end + +# it 'notifies compliance_report[chef-server]' do +# expect(myprofile).to notify('compliance_report[chef-server]').delayed +# end + +# it 'skips compliance_profile[ssh]' do +# expect(chef_run).to_not fetch_compliance_profile('ssh') +# expect(chef_run).to_not execute_compliance_profile('ssh') +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'When invalid profile is passed' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'myprofile' => true } +# runner.converge(described_recipe) +# end + +# it 'does raise an error' do +# expect { chef_run }.to raise_error("Invalid profile name 'myprofile'. Must contain /, e.g. 'john/ssh'") +# end +# end + +# context 'When specifying profiles with alternate sources' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { +# 'base/linux' => true, +# 'base/apache' => false, +# 'brewinc/ssh-hardening' => { +# 'source' => 'supermarket://hardening/ssh-hardening', +# }, +# 'brewinc/tmp_compliance_profile' => { +# 'source' => 'https://github.com/nathenharvey/tmp_compliance_profile', +# }, +# 'brewinc/tmp_compliance_profile-master' => { +# 'source' => '/tmp/tmp_compliance_profile-master', +# }, +# 'exampleorg/myprofile' => { +# 'disabled' => true, +# }, +# } +# runner.converge(described_recipe) +# end +# let(:linux_profile) { chef_run.compliance_profile('linux') } + +# it 'executes base/linux in backward compatible mode' do +# expect(chef_run).to execute_compliance_profile('linux').with( +# path: nil, +# ) +# end +# it 'executes brewinc/ssh-hardening from supermarket' do +# expect(chef_run).to execute_compliance_profile('ssh-hardening').with( +# path: 'supermarket://hardening/ssh-hardening', +# ) +# end +# it 'executes brewinc/tmp_compliance_profile from github' do +# expect(chef_run).to execute_compliance_profile('tmp_compliance_profile').with( +# path: 'https://github.com/nathenharvey/tmp_compliance_profile', +# ) +# end +# it 'executes brewinc/tmp_compliance_profile-master from filesystem' do +# expect(chef_run).to execute_compliance_profile('tmp_compliance_profile-master').with( +# path: '/tmp/tmp_compliance_profile-master', +# ) +# end +# it 'does not execute disabled exampleorg/myprofile' do +# expect(chef_run).to_not execute_compliance_profile('myprofile') +# end +# it 'notifies compliance_report[chef-server]' do +# expect(linux_profile).to notify('compliance_report[chef-server]').delayed +# end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end + +# context 'when set to run on an interval and not due to run' do +# before(:each) do +# allow_any_instance_of(Chef::Resource).to receive(:profile_overdue_to_run?).and_return(false) +# end + +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5') +# runner.node.override['audit']['profiles'] = { 'admin/myprofile' => true } +# runner.node.override['audit']['interval']['enabled'] = true +# runner.converge(described_recipe) +# end + +# it 'does not fetch or execute on compliance profile' do +# expect(chef_run).to_not fetch_compliance_profile('myprofile') +# expect(chef_run).to_not execute_compliance_profile('myprofile') +# end + +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end +# end diff --git a/spec/unit/recipes/upload_spec.rb b/spec/unit/recipes/upload_spec.rb index 671540b2..fcb5b9ec 100644 --- a/spec/unit/recipes/upload_spec.rb +++ b/spec/unit/recipes/upload_spec.rb @@ -17,51 +17,51 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'spec_helper' +# require 'spec_helper' -describe 'audit::upload' do - context 'When all attributes are default, on an unspecified platform' do - let(:chef_run) do - runner = ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '14.04') - runner.converge(described_recipe) - end +# describe 'audit::upload' do +# context 'When all attributes are default, on an unspecified platform' do +# let(:chef_run) do +# runner = ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '14.04') +# runner.converge(described_recipe) +# end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end - context 'When server and refresh_token are specified' do - let(:chef_run) do - ChefSpec::ServerRunner.new do |node| - node.override['audit']['collector'] = 'chef-compliance' - node.override['audit']['profiles'] = { 'admin/myprofile' => { 'source' => '/some/path.tar.gz' } } - node.override['audit']['server'] = 'https://my.compliance.test/api' - node.override['audit']['refresh_token'] = 'abcdefg' - node.override['audit']['insecure'] = true - end.converge(described_recipe) - end +# context 'When server and refresh_token are specified' do +# let(:chef_run) do +# ChefSpec::ServerRunner.new do |node| +# node.override['audit']['collector'] = 'chef-compliance' +# node.override['audit']['profiles'] = { 'admin/myprofile' => { 'source' => '/some/path.tar.gz' } } +# node.override['audit']['server'] = 'https://my.compliance.test/api' +# node.override['audit']['refresh_token'] = 'abcdefg' +# node.override['audit']['insecure'] = true +# end.converge(described_recipe) +# end - it 'creates compliance_token resource' do - expect(chef_run).to create_compliance_token('Compliance Token').with( - server: 'https://my.compliance.test/api', - insecure: true, - token: 'abcdefg' - ) - end +# it 'creates compliance_token resource' do +# expect(chef_run).to create_compliance_token('Compliance Token').with( +# server: 'https://my.compliance.test/api', +# insecure: true, +# token: 'abcdefg' +# ) +# end - it 'uploads compliance_profile[myprofile]' do - expect(chef_run).to upload_compliance_profile('myprofile').with( - server: 'https://my.compliance.test/api', - owner: 'admin', - path: '/some/path.tar.gz', - insecure: true, - overwrite: true - ) - end +# it 'uploads compliance_profile[myprofile]' do +# expect(chef_run).to upload_compliance_profile('myprofile').with( +# server: 'https://my.compliance.test/api', +# owner: 'admin', +# path: '/some/path.tar.gz', +# insecure: true, +# overwrite: true +# ) +# end - it 'converges successfully' do - expect { chef_run }.to_not raise_error - end - end -end +# it 'converges successfully' do +# expect { chef_run }.to_not raise_error +# end +# end +# end From e260c52e55371251b3d01b2e2ad2ebeaca7550d2 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Wed, 19 Oct 2016 12:58:40 +0200 Subject: [PATCH 7/8] recover examples Signed-off-by: Christoph Hartmann --- examples/kitchen/.kitchen.linux.yml | 37 +++++++++ examples/kitchen/.kitchen.win.yml | 47 +++++++++++ examples/kitchen/Berksfile | 6 ++ examples/kitchen/Gemfile | 7 ++ examples/kitchen/README.md | 77 ++++++++++++++++++ examples/kitchen/cc_report.png | Bin 0 -> 65522 bytes examples/kitchen/visib_reporting.png | Bin 0 -> 61339 bytes examples/visibility_win/.kitchen.yml | 25 ++++++ examples/visibility_win/Berksfile | 4 + examples/visibility_win/README.md | 23 ++++++ examples/visibility_win/metadata.rb | 10 +++ .../recipes/chef_client_config.rb | 24 ++++++ examples/visibility_win/recipes/default.rb | 6 ++ examples/visibility_win/spec/spec_helper.rb | 11 +++ .../unit/recipes/chef_client_config_spec.rb | 22 +++++ .../spec/unit/recipes/default_spec.rb | 10 +++ .../default/visibility_ingest.rb.erb | 15 ++++ .../default/serverspec/default_spec.rb | 2 + examples/wrapper_audit/.kitchen.yml | 49 +++++++++++ examples/wrapper_audit/Berksfile | 4 + examples/wrapper_audit/README.md | 26 ++++++ examples/wrapper_audit/metadata.rb | 15 ++++ examples/wrapper_audit/recipes/default.rb | 15 ++++ examples/wrapper_audit/spec/spec_helper.rb | 4 + .../spec/unit/recipes/default_spec.rb | 10 +++ 25 files changed, 449 insertions(+) create mode 100644 examples/kitchen/.kitchen.linux.yml create mode 100644 examples/kitchen/.kitchen.win.yml create mode 100644 examples/kitchen/Berksfile create mode 100644 examples/kitchen/Gemfile create mode 100644 examples/kitchen/README.md create mode 100644 examples/kitchen/cc_report.png create mode 100644 examples/kitchen/visib_reporting.png create mode 100644 examples/visibility_win/.kitchen.yml create mode 100644 examples/visibility_win/Berksfile create mode 100644 examples/visibility_win/README.md create mode 100644 examples/visibility_win/metadata.rb create mode 100644 examples/visibility_win/recipes/chef_client_config.rb create mode 100644 examples/visibility_win/recipes/default.rb create mode 100644 examples/visibility_win/spec/spec_helper.rb create mode 100644 examples/visibility_win/spec/unit/recipes/chef_client_config_spec.rb create mode 100644 examples/visibility_win/spec/unit/recipes/default_spec.rb create mode 100644 examples/visibility_win/templates/default/visibility_ingest.rb.erb create mode 100644 examples/visibility_win/test/integration/default/serverspec/default_spec.rb create mode 100644 examples/wrapper_audit/.kitchen.yml create mode 100644 examples/wrapper_audit/Berksfile create mode 100644 examples/wrapper_audit/README.md create mode 100644 examples/wrapper_audit/metadata.rb create mode 100644 examples/wrapper_audit/recipes/default.rb create mode 100644 examples/wrapper_audit/spec/spec_helper.rb create mode 100644 examples/wrapper_audit/spec/unit/recipes/default_spec.rb diff --git a/examples/kitchen/.kitchen.linux.yml b/examples/kitchen/.kitchen.linux.yml new file mode 100644 index 00000000..bf010077 --- /dev/null +++ b/examples/kitchen/.kitchen.linux.yml @@ -0,0 +1,37 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_zero + +verifier: + name: inspec + sudo: true + +platforms: +- name: bento/centos-7.2 +- name: bento/ubuntu-14.04 + +suites: + - name: default + run_list: + - recipe[os-hardening] + - recipe[ssh-hardening] + - recipe[audit::default] + attributes: + audit: + collector: 'chef-compliance' + server: <%= ENV['COMPLIANCE_API'] %> + token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> + refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> + insecure: true + owner: admin + # fail converge if downloaded profile is not present + fail_if_not_present: true + # fail converge after posting report if any audits have failed + fail_if_any_audits_failed: false + profiles: + base/linux: true + brewinc/ssh-hardening: + source: supermarket://hardening/ssh-hardening diff --git a/examples/kitchen/.kitchen.win.yml b/examples/kitchen/.kitchen.win.yml new file mode 100644 index 00000000..d0da1e5c --- /dev/null +++ b/examples/kitchen/.kitchen.win.yml @@ -0,0 +1,47 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_zero + +verifier: + name: inspec + sudo: true + +platforms: +- name: windows-2012r2 + +# The following (private) boxes are shared via Atlas and are only +# available to users working for Chef. Sorry, it's about software licensing. +# +# Chef-internal users, you will need to: +# 1. Create an Atlas account: https://atlas.hashicorp.com/ +# 2. Ping #eng-services-support with your Atlas account name +# to be added to the relevant team in Atlas, +# 3. Do `vagrant login` with your Atlas creds so that you can download +# the private boxes. +<% [ '', '-i386' ].each do |win_suffix| %> +- name: windows-2012r2-standard<%= win_suffix %> + driver: + box: chef/windows-server-2012r2-standard # private +<% end %> + +suites: + - name: windows + run_list: + - recipe[audit::default] + attributes: + audit: + collector: 'chef-compliance' + server: <%= ENV['COMPLIANCE_API'] %> + token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> + refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> + insecure: true + owner: admin + # fail converge if downloaded profile is not present + fail_if_not_present: true + # fail converge after posting report if any audits have failed + fail_if_any_audits_failed: false + profiles: + base/windows: true diff --git a/examples/kitchen/Berksfile b/examples/kitchen/Berksfile new file mode 100644 index 00000000..12e6e564 --- /dev/null +++ b/examples/kitchen/Berksfile @@ -0,0 +1,6 @@ +# encoding: utf-8 +source 'https://supermarket.chef.io' + +cookbook 'os-hardening', git: 'https://github.com/dev-sec/chef-os-hardening.git' +cookbook 'ssh-hardening', git: 'https://github.com/dev-sec/chef-ssh-hardening.git' +cookbook 'audit', path: '../../' diff --git a/examples/kitchen/Gemfile b/examples/kitchen/Gemfile new file mode 100644 index 00000000..8323966b --- /dev/null +++ b/examples/kitchen/Gemfile @@ -0,0 +1,7 @@ +# encoding: utf-8 +source 'https://rubygems.org' + +gem 'berkshelf', '~> 4.3.5' +gem 'test-kitchen', '~> 1.6' +gem 'kitchen-vagrant' +gem 'kitchen-inspec', '~> 0.9' diff --git a/examples/kitchen/README.md b/examples/kitchen/README.md new file mode 100644 index 00000000..b681d160 --- /dev/null +++ b/examples/kitchen/README.md @@ -0,0 +1,77 @@ +# Example: Test-Kitchen + +This example demonstrates the usage of the audit cookbook with test-kitchen. In order to use it, we expect to have `COMPLIANCE_API` and `COMPLIANCE_ACCESSTOKEN` available as environment variables. + +``` +export COMPLIANCE_API='https://compliance.test/api/' +export COMPLIANCE_ACCESSTOKEN='eyJh..GTA' +``` + +If you want to use the refresh token, use the following settings: + +``` +export COMPLIANCE_API='https://compliance.test/api' +export COMPLIANCE_REFRESHTOKEN='40/YUP...mA=='' +``` + +For Windows devs, you can set these environment variables in PowerShell (recommended over user/system variables): +``` +$env:COMPLIANCE_API = "https://compliance.test/api/" +$env:COMPLIANCE_ACCESSTOKEN = "eyJh..GTA" +$env:COMPLIANCE_REFRESHTOKEN = "11/z..==" +``` + +## Converge Linux + +``` + +$ KITCHEN_YAML=.kitchen.linux.yml kitchen list +Instance Driver Provisioner Verifier Transport Last Action +default-bento-centos-72 Vagrant ChefZero Inspec Ssh +default-bento-ubuntu-1404 Vagrant ChefZero Inspec Ssh + +$ KITCHEN_YAML=.kitchen.linux.yml kitchen converge +-----> Starting Kitchen (v1.8.0) +-----> Converging ... + +... + +-----> Converging + +... + +-----> Kitchen is finished. (0m35.94s) + +# destroy the instances +$ KITCHEN_YAML=.kitchen.linux.yml kitchen destroy +``` + +## Converge Windows + +``` +$ KITCHEN_YAML=.kitchen.win.yml kitchen list +Instance Driver Provisioner Verifier Transport Last Action +windows-windows-2012r2 Vagrant ChefZero Inspec Winrm + +$ KITCHEN_YAML=.kitchen.win.yml kitchen kitchen converge +-----> Starting Kitchen (v1.8.0) +-----> Converging + +... + +-----> Kitchen is finished. (0m35.94s) + + +# destroy the instances +$ KITCHEN_YAML=.kitchen.win.yml kitchen destroy + +``` + + +Now, the node reports are available in Chef Compliance: + +![Chef Compliance Reports](cc_report.png "Chef Compliance Reports") + +If, configured, the reports are now in Chef Visibility instead: + +![Chef Visibility Reports](visib_reporting.png "Chef Visibility Reports") diff --git a/examples/kitchen/cc_report.png b/examples/kitchen/cc_report.png new file mode 100644 index 0000000000000000000000000000000000000000..4749403ed69e10eea88cd3c850c8931e889f8c8c GIT binary patch literal 65522 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%0D^$FWVSiGRGPqNNZDyBJ~$e83v@dIg0? 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

9VFXP)=WIn)3Q*) zp8r`wL0Tg1J0oR(?X;6B?mISdz~yyEhTU;_! zE9Y-wh*?bs*7v&cX@6w(K79EELu0yal$U?&d#&dLnS|S3V#7QT-@}w)%AP7ehH-zY zot^lMV?@$doUt%-{_<%O`;B~&y!C5VM^wb!>vw!J8E9^AAa{(@!|798U zLMEOvu4ueL+E1?`&ayp8#$SqCYUb9q~oereE6je zJ#nbOm?Yg6-(^4#rqU%r|k$0H!%ai(Z`Y0`8n=W;G^^mzIH&;(X zmM6Cz11_}Nm7I6keAOF^_67z_S-(Ksm%aYf680&Oj^7T@=@#88F+l6SC?aq`uLd(e ziA(w-UUWLU`!duaT(2i9SLXMS`MQZEDK$6CeTSAq-;eoE-LHRcUyCVqijbM@dHeE) zksqJ6S5v|P>F=Lbql1#gSYcK9^_O{v@V%3Vz}W;;o zdBo^Idf=#U7Mr&1KIx#Pgv1i@-IKW`9HE$(3gdzQ(EEMuWmja$nX#5L+WyhX?NHpc{zYQN5& z8lQ9)F<)}adCO_tAk-tjSAg}~a_ZQNiaCb{Cw$n3?JwRo)ux^LvZoOQ*_@?5R+&%Z z5G`!FLU%9k0I63+ib33dZa5wYNSUui?%}NXVOVY$w5IlXNHBtb3oXzK66>Bse zvL8gqGVmyo?zlU~Jnpo)+M3h6i{&zC9sM3)3r0qG!sa`7s^=cb+#L2iv~qMHf2aDc zLZ85JmpV6Ae^H+rMm@BMlx|!}R|>(7iQIS}lh?E5S4#fH>MU8%Yx z-o4XQ(Ym>M#pC!cmer&V*F6{~0Z4_nR`7|h<+i8j1UWW&>~mcU^9&CF9;X|NJtfwjE^e;@qU6)n0)>^wLi>6J`LeXm{DXO5_JnC@K?VQI5)YO6vX5!xRIJi8 zZ2kMnQ3^Nd0p-ig#Pp{US6edPdrF7X+IXvn0tssNr3$H(rTYder(1Fh{wS9a;@OsK zA|xq=<5}7(?z!&NDihz8{|f0KiKoyZ&Y`S<8aI~CY_KFNEFrI;B5d{mW$}aAQ}}m z+X6^oi~Q+p5dw71dl2n{`C+lc>yVrnNH&m2D5`CL72PC+*i9kUH9{~0mG%f?+d$Yf z#Ki*Qpqeo<|H35=QSS42P;kSMKr|H7H-R7L#xGw}*oXw&MPTl0m-&@mE5~c<(+Gh{ zmA^mu+&~5a_%49>K(*8XuYyR*6%`qQMl+$If}m(DZbkJ^`hn2yLEH2I@R`RE{Shd> z;BgA@EU0V1T?JDpfVGe`06-dpl?&KoShR`A%{yw5#I-)Gz`~S#cZR8$pAKm01a0&O z{AyP@1HA=`3Fl{QB({fZW1I>Qg&>LnpPxR+&M1uSbs7k-hUk<)JBBC+^H%j|7x~y}ox(8OZ-e z$XfIk6ff{!5S$Sau_1zefcZesA!aT5NEQ-L0~B@+)SXBUUix@dG#GgR34R5ofF&b@ zK&D-J2(o+_z@uCMn~;>=-D5wgLA#M$=t!7ya1ui`-vu)U6OA;xM81E%wRogw2FT-~ zg$n3FB#dwun`#k&zz>tejr;j*dT<({3>(L#>X^iIZm-3Lb#FAhnXZ28sBrE5HMMaT zgQ}5O?dKwV!4I_lz*`m{X?CUuqhEj2w=3vvZ4(m+77oLzbSk4ANb<#%y#aO!4L_D; zsaX-|L%%hl`=)gprRSF^CT$A~RmY5sPD4QWm=BOG=-i|9x1S#`EG)EhIJ;eAz_b^L zqXy|F8aF*w=k)avot^bQ`&14G`RmB1n5x9a#s*bv2S&z_PN$pZv$S<}I|c`H^YZen zO9=Cw0w`2}aM68U+`)#S{(ikmdyAwB2BWOJ{D9#fmXN5}gGe-sh=@2oTgf4vFF%`| zmF3~;dIU23PAx9`VCBdY4Od#q(Sr`>2PY*T<_{EHUOti%AKu&R2m!x`r>3lmii$F_ zvI4zlL{MO34p}l9*pY2P3m06C$`6Rb#-^8 zHEZK=1lq}yC4^HL*$&78P4f0mVY(spaF)PYZkh3UF)lHIRGGYaVv2wh70dSTO za@T&dha)pp5cS2ntZNJx8*Z-pho4UAC2TQ7Wpi+HYL<3AqqHj}Dlb3ZmqIDc&fd1_ zhQ3O&Nyn(~adY#X)E1(*_lfH2>I^D1jWukoEScEIO;q-;cHAH?&Srl*rX(>lJ4^KN zFvd|&fEh5VkxRa`R^-NG_0i;vH&n`I8=@MIS_OebxH^ zxW*XJ5~_b(AdxImObr{P>(A|5yaVS!Il7<#gf>-{gjY)(c*(4EyS zFwrm?Ul!!C-8k|qvaT>f(e8e@yVDw4L(Ys~17UBDrck6ZG(~v1$-;LO`@0~#D}*4Q|9Y=soZ6N0TZbrf0NLi~ rxF;=H^XGiX8pV~bRyb-GlNrks6#7v}Ae>oMiflD8v^ZL7;2iod{;__6 literal 0 HcmV?d00001 diff --git a/examples/kitchen/visib_reporting.png b/examples/kitchen/visib_reporting.png new file mode 100644 index 0000000000000000000000000000000000000000..fdb9df215e7d4fdfcdb584d1f0e4ca507d48d6f4 GIT binary patch literal 61339 zcmd?RWmwZ~{5OmuqEad)ErKE~Af1YYj)noFr5O#5hN%dM2m;DzkQlI0(hZ_?$3~29 z0V(NG_Yb|iuKWMo&x_~P^XA@ha1i_LJiq5RKHoeE)lgF+yGDPFfPjGPsqzyo0s>+> z0)mT&S1tm7nX@Nj1ioEx*HU^+P|(A;4E%D*=8@_n0)nCsB*)K*fZwmWC_~%{2*|&m ze_d#G&aosQ*m&^t$s-*vlby#>H+=U}DczUUJiEjxrT3dce=xYS-81iv_f>DL za0-r z8%{pt4!!$DvEe|=U$MrQSFg)WqY)+nb?|nXpQp39p^d5iL7sZhQLL+{o|<5D`@es9*z8 zpc-Qe4MjBHWschT~v*`{%3)gROJUe!h-ns5D!|v#XiLt9_oKq?l4e6 zNQlT3*^Mb7R37x4Qwu--iNrAML>KGSK-HwrLD*9S{MFomYLU7jA^UX=7$$8rZ)3*65wa8o-eyv ze@RM$)k71fA^eP{SbJhx%&k;sT}^^tOslOxp)$@ll~S_dT* zi{Ow+tSRkUbK(wvHXvBO`wBSbDpj+%GTGtmIMTUbD2G-v@~@bcAy+L?@RJV>Wp9Gd zY2fYMt$FlU#<#7S6Ol3jdjrw8-W3BB2usqn{YSZ138w9{_NV!XM5?MVugk8*d3WB$ z<&@iAcWn21=gx8Yul~s0dn*c>Fy4&6D{u^)KR+Rsz1(%}&NGW~2sEkLBak%;vNDx- zwstN;ZOpxY=+3M?U%yF1MRPm4NeBWxR&e~QnH_APaN~aoiA1*W{oTq-_44J*^z`)5 z=#|MjU-J?uv2sfDek@*eb(tT02XtWY%$*IN9T*A-q@;`dk=08TWO47X+!{eUr85F&8>_%9vlWw&Od17& zN{v+jXBX2E?)|!VfR*wLV2VQC+jsoub0H|}9D3^4Pz*aQhCEVg%Nq5~H1E&`WP3kL ztYTE<%3sY948JCm(I*ey+8)X`Y~g%t`|RO4{g(g*;nP+aEnQ<19@Dhw3``%GTT!6; zd*rrv}9RQvU*2KfHEu|+j~IPO9;$19$)-0a?)^ea}LjW*EG z`}Ja;oGEwz>R_au&L&;++E_)ZEL=uNNXU75|H!n?2e#CctTBS-cSr-c^Yk`|`Woni zp__c&aW{Ty=wJo=__Fz|Y;DOzWu|=6vwsxkrAo$Yb;%0nsr9wBz?sTj(dXn8ox{THhG?C0D7pLs|IqO^AbIK-=Be@;jpLi64QP|}W)vtD`7ZE% zgH*ttmSZPRcrm6G$)KBubG0|B!-P-Zip;Uq)ThRL1<>rETbTg0zcrHaKE4#Wm1l@-nq~&D~FF8KR z+ILjSGr;o*riHM6Yma-RgY>KI=)(I0%u0rFpSxH*7-ja_xi<+m&}i1oME zSEV!{@4&!r#DBIxNNCi-n$dYeYxvxUYOMgO_#}IU4N(mz{`#)crNyF?XS}~SDYa#4 z+X?;-XZ3xO{@Y&kQHq&2Qe@%G9a`A*8%=q!{H8dOXVjR-fNfc#zKt9_u?)UdA{O%A z5>+_0nNKm4@3sH!rBBtD%`ZFM;8DHHWgPhZp*QA@vDu>e`Y}r+^~}B=te)TTF}Xwe z`gN!Ib+pVO3>F=>4(_{yN65rU{jzo14Zp2{Xe9a2e1UPruL%-kpX>|fBtB8CX5rZM zp9_zg6JXqAVRq8gd6Kt!xEC(ktIL855pTM*rlbRq`i!B6PtV@+2;&VoRBH2jeC@;i zYE%SGZJqE-~Y5eYF~#lV7yP94 z&9H$F&?oe1H8qCL-dqfy6rmIR;pNSeF(ooR?x&MW@-kAJ0I>3NpTE(Anpr z%q66qudQ>~x$^A@T1-v2%`BjtMUrFR1Rp^x4d`fol@+M#y7Zcf`uU z5K2Q#M|Zt@j5FYBJ?kmr+gn(m^1Q40{$X2qGg$JcOPAf z@k&U{T`jzImip$*img~D-}uY(_5~l}--mSp3Ev6t8y*%dEK|n9aS4fu47YCO^aua? zkV*6SS7nD5>_cjul;3P_TlVRhdAIBtpsVJ9dpA;Tsjo6%Lx|D{D0GMQ6u-M)o|YeH z3*qU%$xFh=BkcqcO!;miver5r%mC{!(vtq={EXe7Xr>$~tCI(*Fo*5Mhv4VNzJE}+ zDg4Al^n;Mh4mE@(Bid~YsgZ}Qc%3xvX8q9Uiyqf#&1-qlWyc?2YT}i@wK|$Bk_Tak z@UgnasAdrRwnNKm*4riAZ{UnLCM%&>r?o;Y<*gU|m!Gtt-_AaU>TL!0POxo;c)tEo zze3silVM)E&U%>Ik$TSV*DpweGku~KgJ)BM!JQz~N#zJ^vp-G-*;|e&R}&yZdm-#gXoM!(Gq1ov`mbv4`yMZJ}Z0-`t9E$t#?E+ zqX6_-pgb+YAw4`i(A0Nwm~MMVMml{(@R>$gbg6&AI-&Tk{P#ycl zurZ&EF7O_&Pf8UY{fT)nuQOc5V{z1XYbmEruLUmY{klb(F&{DmUVf8$vI;vE$SC3n7NHVrH&Wj~e>zdC3&i%Qpu zH!ircfPQ4)jQ072LK+asI2J1ki(o(xo|C>yK(>s8?HM%;CFdsHCof(KtJqyAyWaiF z=+Y-U zTdi=rNTf9*?_*wv2XD~TMTU~4wqO#l{G3MfM~JCyJq3%>{!N%N1J}WOm(`*CmKMc^DV9+QaH^n?&>#k*V`%8Ry{NjS z{l{Ohg1V)Od6xi)^I^2};xQ1}qZ(ZJe!B9?hc(6KIGhf_dV9Nq>K!b+=Iw8$)_=_s zqOf{|{)@9UiPV|LdXa zU=`B4aRvw*#${X1QA-p_G1EHzTARFuqIjx~UfFwH`H~?jmM-dsOH+{-wvF-~?%VdK zgQY8kdt;TH zC>+8Aep^rbbhQUIfg4oEt`emhO)wtu(T(v4A7sLTxP(!i>w$)8wRbov-SB$#B=uG> zDJI0{iE)Fq;Y^H8FzXSqf3{2;K1gI|kiouUQCC)fAcDM9X;5aa=sqq7upM|<|zy3{VIu(ghABj3o)_QJC z0*|Dm_t*y>tQOfloSU1INmbu4#U6ZVsP|{@zf*!4)f>L2etg)K!H-?NA|(4Mln6so z(gqpSo21cBr!I?pHFAUrYDg42&bIJ9l{=(!yg1}Hs}?y9oSFNlH|}@N0nFy+^3}674-INK4_G^T1Tb8OZCuy z!IAgz$-X(FKK;O0CB7cdUG}E&XRiH<*xEOZ6P_k!?5gshyu~4$9T6%;+UPcdH%}9k zJvQQ{l_H%R*SNu;N%AKxxxM|P%BC%lm||yBr)wZX>yfEobR6|F0~Q&-9MNZF!m3~r zR&Sb*$Q}w=ma%Q(bMB<}C-~th+qJ@*j6z(rDYV$OTfgpmoBLQYs7p679?es**>p?c zwNe+pNV-0lBR+fLBz5)ylX*W${h2K3?myYvl>v8kV@JoegM&%|*6^uwDV{8LCqfN@ z=&{lKVm*rF4BX3-U4MLN`HA?@R0)B$seHAujjQ(Idh}_NX=QrXQ_utTEV!q zs!F`*hP0Zat*wTn+%I;-0v(Glg=X@*1aZr-o}!F623}A&!Z-K{pIMg{k^gkS$#Q`I zvr@-*p@_Y5cWE+nhk+zlln`t4`c3e8>bGS!A)}q|Q`~Iai1E`_+Bg$E-uwwS5Ps z;zDrNC_Lo}pkKbL@#}|#ps)0g5i8GeQ*Hy%5`T1?fL;FLh1ApcwGDeGZFjN^gNKI= zUFm%ZuSA_hDsJrQIPe-E&>YeIEnCCHs}-3QBCJ{B+hyHa*?h-(bw&Bewg;kHMdkm> z`1Zuz>zk^IQhUtlK_7;muQ&e!?91{g^KR3i_w{UB2>Nq&eAJEnNz$Q#`{1{9=8D!R zpA4NbD*aos2OQ4%%5F7S8&2u%_LmjO2a|&MTb_ zRACAvmaraR%~sSoQ%r08_pq?7!I|YF1t6dyuna+Kwsk#BmnUQeIL!#P45h*SV_C|a zKxqLml_a6QWo~CB5fbA#=9~8ICc0$;s~jH+-_kL?BXTIW5II^&U{qN7DEle#WS*j# zFFmLhkX}!_!~F9wUZqtGl$zt(trLScljXD z^()a9-1eXHYa0Q4n%L;pty^(~f1VKh%F;!^M@mkPF7W(Ewbj``LEQfqf391iT!Q{e zg6=gBb-`apcw0Ua`HlLo5G=10>s0MHR`~rZsczuZ{{{f^ZqJ{!=NF z3%>n-$!3}*7~(da6}X(=e{4xA)+xIpc=a!5%))r6@BL-`OWtCgxWB9>C~wnx{+GD~ zBX>YS|9^f6ijGfAOa!9Nq$EaWW@e!J*|$TyOSH?(wIk>zC6iXra-{SKP_1$zyUuR71=ddsWXZ+9mp}c^(4`WJ$6*zCBv`|^HA5Z z3kB8Ur=bZ>G2)g@i22CBSL3>rHa^&WA_R>vFiu6rsCvh6tX#%)y{+=O$~+)9vD~pH zxf`lb(`nB_wmiu8z6?R-ccOf1UGwNfBO^KQyTFrVtd3K1PE2v9FM5ljSzS>VkH1cR$CPr^^z-zKEFqEih&tVtQT zojz~yL0!Tzpr3WR<*wPYJJRysdtH(aMmJtl4fS~b?8mIRm~co!-~E=xMC%1ANB%ne zxPH(*H@m@S2L={-y%}{1H*!M|@3(PFm2ul=@0yRpngsNwlGAK$ER(J3b1ul;`z_Cv z;_ai8jEs!gaA8HHz&Ueyk5o=bV+Q2Y2DTxg$KJK+8(n&Yo=z0Q!>Z+VS~Zs<4K5cj zwe|8#SGg_?2a~E#wm+#!E=hFCTz~D6djt*N@~Eg2fvX3oS-FqJ)pnA;hhf3YxXNtw z(}^ep4}poZ>4Ej6+2|J6HRSgTDiyjkHZhZfqBReM`*x~E@|fcc+V1WjnL9neei;>;9ONe*MvLS~xLOsgy~fYCqzP$?(cUU8@)oTY(EN zyZQpa7>dKC)c3Z+R-fytc=%;=Yr$ATft979=%nK{?~pEVhjRC;^t@!v!LM?|btk^R z+zUyc6h^$KPT*S!YTufjb%Cl0r#-qz%yP>|3w*nRrO%YZ!%ir=1PEd>@|c&(dR+yU z&Zr0OoGO_2!o1{3OL%C72}}kIZk`x!X{}Z#P*#6#LawPaYJzgF__lyzZW@WMCr2Z{ z0iC1e?w+2NZZ*nl>byRkG9TBpcpss~)z+}HI)~dOH|g@<|>GCWVLG$`LoS8@cm-IEL1d z$FXl++0jElQ!fU&KE+5bH#whZ)6QwdyP^;$wonUdWOErYD}{vVH_O#hlTXoG$zzH; z{a3)+RU^1Cw6szoij!@2V$i8-A%bzeZqB#$O*y)D*20g7P%ucP$*m`G<9I%Nyx-o< zpbHPlweB^+6_`NrP*0Wve4Iu2&ap$$(5#FB%rdXQ+FcQDY?NxckG?|D&Q>ldG9&7l2>)Qe7zCpGP^m4{dRWBb=x<ku*wTIa)nB_Mb4itW%%Zfwr2tk7dLreOtF9o=z-vs?=R0*!)t@P~&KCX8aQm z>7B!&f2j?%#}2f`WK`*;hz%=;TB9Opv+mQDKFpk+DzktMa7CFCoS9o#gxoe z?kSk^v>0;mE}F6zRNXLjj#k6* zPId=^tkBH7UY3rjyf9P);X>@&P_U|jyl?l{iC^-GmZ_`?HR`gY(jm_)oE~hwPvYJY zX5qenP3@C#%z-g%#H!-B=_9DB*f2)EwSzkloZ9on3FMNEo9s10jo-=IK;?P=+I&;q zg?P66mH@(~(xzovA$L2n>54GBpfb3*j|R+7?h18oZ%k1STj(wBz3gn1x}FvWHd_X? zx#UOOq>n z$p4^oLMvcpQ<bud`q#wdAX@(sGU)Zd6iMHbKILWg?kvQ5=5S`7lLE|!n<;jHy zx|%*RR7r+Cqi_C&fUve;gY;?djfI76qwH2Cuy39L`0!&eWotNh^?=WDu`aPdc*_#C zh*h|{E>K`^y3=f43;ULSsxTX8FGgDzr}wZZ`O59&ZYgn1w`K36@NqW~Tw6V2?M95E zq1p4yf?EC6v1hA9pff?n0(((g9=pN7(SwR=pb~R4)xZ@FQQ@GmhJWC5u z$eHD>YOY}^kygJpdS~iaUT4wox}z&_edDDCg6n&?RF&NRVe#}tnU}j| zXVxin3!4u~yyH3VwZXJ6dC!nN$d{U6+Dem6RuwR@<8&;??7EtB(*1xa(eNSq_FIvT zIPcO--El@V!~+}Ux?9PoBJ$hZs_nyW5j!W{9TNqMKLP&$1 zqa~y!V4+}DlaFqXIo7G~wGO1*NSNp|(9S+(Auj+kTt(yw%}TsFh(z8S9v>h7@gt{0 z(v-s@5|>Ma`epNFgcubpCOm!zdo%koXd|>E3XiX{J5-^1IjrarWnC}SMM2JeW9?q+ z%pylqrOM`v%;D|KJq1==U}Tyz^Ipx{{ZJU?Ve69L_qk*Glf-wmC0KEXe|+&edvb}+ zVcFAK>RD5c9jOezVpOK9(J`saPyXKmIFqEQ#u87%G@;X{#QBablHf3x6CN~4os3;B zjxE+f(pNe6llhQxwQb4!+*a@B@AhZY)w-8+-p@)ML@C*HimajXu1@Um{u;>oSTb&d zdR{(Uubg&nMqwwkPt6K~)_793hy{a}3$@b*|v2G4sZ z9^=okCn-XL?uQIqTjRDCO8tHkh_XObTtpey*I#>3+Y1vvqG;_1lS zN~w@G2CkFK_i(Ba-@Db{ddC+HMN1#nkaWDB;`mAY!Q{p`d%s<}wL=KqJS4~b+j*~hTo${Bx&GK>!enrkiV2bfC&H_O-?(abK zyJ7L)FT4naK@L?GEORGp5FpFZ(k;AV|JcuUNf0)AP#SN`@o07uW}`Wj(x;7Z zQ_=(iEO_g~mZfL{FOws%rtEwwe4udn>sq&!_hI6*b(H<1_jvInWJgVtbTgXUCY!$f zJ}z%_<*IR99xZLQw!0Wt#v5{zy`YMs>0op(WlbqvJ0z@EYp!ljoR8)t-+hZedc=sZ zlcy7itCp6f!xQkJ7!xC0eTf*i&QfPVQW$8ZsVlyG+X`J*YmC78*Yo7oLY$shqe4n) z)_YcQ-B<|)Fl8^oPU&tzsE@Dr*n-uE`!gk9n87X+VkMZM5WZra!Ah1J#c@AN&3$4A^YT;sc=X4$6BiIhfWz&byb>`_D2k0n`x$cM9N79TSy6_2ocAu*Ajf{U%- z9fm~P!SFlIk)`G0EgRS6)eB-+ucNaf2wm78M!>yj4MO+swcYv9xV8Dh)e?mpM)ldAN>o|NOR^mf zcx^b28(-XrTVADq`TqJ3sElU%2U{Nd>64|@xPnV+yCpz*_mq#?vye?9apk@a3Yyzm z{~*4?p|0|YtZ<@nr+NN~Ib$sh@&0yT2G`XhK1XuH2;J1Mn?7MYgI4_?Wb5ryx6L&t zB}C8e6fLbNnRESmpI6caBq4NP#drcLiEnyO2n>zAqHSz`!n^h4$UV#$!Id@iX=QgT z?L=Jy=MnY+GOUk;*KZNJrE8yNu?%*S7x`zYgTd1dMvs~~W!X*%UF1(8hG$^{K-j#~(0g7>qvkiY9 zSo1(66YI;+$Gkl}XN=u|z8+hah(+>#3Ft1b)y4{c7_%C#<_zNz*6jTC1fH2$rU0{z zLYFC!DdZGWQRk#85Cskw^r+f>V7(ysEi17jZ2!p1z=gF>KL(7895AH<$a~pU{)1;X zBrsQ$+Gtl8BN@X@l&C|n(kAx0q3FkQW~3Q{{^0>euX>lP>dVk9IRBPrX?KE0+K)Q2 zw=gW>DHpApm*jb;Zh%}qMs$)Bo`eKy}5(MybtZW!BgG@yVE#K1H;8RkXqw<_! zG4Lr5S0B8?ZS(60g=|j6WrCZ6Lk3!M9BGbVZ;p*D2T{3~_5x#2fV9kd1sl{Z(Vm@k z_QuX`>}e3+)Ry7eg~Pa7PH-vM^ovB2P{Ok>NGLGMw$$u79~~@EXcAl_4PJY?Ca+&Z zsw1rAUsCx%uj^X4e9VEzLrTKlfJ!%s4aYT0c>z~6D=7Tq)Q0I~2%h&2n+`+ z!h=(X&3;0_L|JHJY-I_?jB>avh%E3`P|#O>|1=ThPxVYOxdohi?IJ9|FoHZs{vKTp zqbVqnc|{ET%vKUQ)4gN@T@v-PkM%pun)HXR0JPZ!1O(XHDl5csW-PhbVSoVE6-|@b zk(zc>S~=Vy43}Ypy5Wkxe==pV7zHOFFne;|dy)F8ib#Mhj&6=rYJ2-ha9bnL-;`G0 zp5YJFRwsF4K9IJiBKb&7dLwKX=;_%yr_z;jgCUKqyK4YK%6&KSe@Y#*aucUE{|%9k zq$<|2c_k+o6brI9Gc(f{%8E})N=it$Nz9hRHuyt3tGb56w2smDROM6JMgvQ=d(D{^ zY$J4zOO{MA$F*Dm3-I(EsiWrZ%^PVR)P4iTo1v#AM#k{YCG|9-z z>#_8~ogZ{{oh3$QrCz`G`8u_!Q=d+eQ7F5ZDu>`A#jE*8?vgl`a1UG3wQR*+Ug<0m zwf(M@Z_-dT?Gu~8$O|G9NhAvoqyE(A@r|U=pkXn&Hmo;~BT=GFi|ITEu-)Dr{65&; z-VPKh%6x~LvhJDIGvZH8&XCSN>N*Annbpo=T-(|wHaYVf4CpGP2L&MU-($C%F98kQ zyjQGaII9x-*%K2L6*V86-Lqp0J2>*KYvmp z4Q&?uH9Hv^Ee~;Z8aK}?v;1IGl&Pso@KVebegoUpmcebhut*(*KH()s^NH>y;N5_p z1?tuBf-24ICGdQ_1L}I3;x&L(Q%40yF7emYnb|AZGS>TOGgqp;JfC*eZTfpL419F7uj%_U9=#7OvdY zguYWbN?T`XSGiPuqane3-mDj?{DWCb&RhrR0^>wspRxRa)4%gSM*nD}x!pWval)jQXkv}1&WSK>hpSnu+I5z=vN!21oq$nrT z$w*Zba0~MuBFs5t6(VF#ein^jkbHJ%3)foI*{lUQ?b%)~6qXNEw$E7?^%|bRB{^7- z_2$wU9+tBblmLiL>%#BiMUdR>&$GSk0RK`F6SWQ1hXuYD1$p-OM`2gkgvntWI^P5G>nDt*KW71MgGvr@jj|ZCylfZq z@}7Kkc8;P?Iu7>P_6A_`R{*e&NxwL&b6eo54QdFYx`1QyO)1kvt63FFHUwnei~Au> z(WazYQvj%mKI1z7ol=CYFchdd3pX}-12aGR%z(|bZ}JF-%I{H7P-IU~o@~XXrZCsS zN@~2|7%}WP4RB6Utz9jh2mO;-^Zji1b{p@&Z~gW<`|^$|_%sxz3TD6KLbyi%&w{<5p$@8bHa(V20hC z_?el>UiF;KhquyNoWh`biivF&1U5pHYx&^2_?J2%YElov@7_fhWVs1*OYP}Qee8rD z&Qb=4dHX@2MP+Mv=|#swRxp@P z?;absy;;nOTFlDwQP&GH%v@~7(g+v#d2*TAOdCAiLP!@o49s?hi(7FReEa^3+rOLR z895Q{gHOp;tt&o+P}Xjs&RYh7EaX!{qi-^{n$lP(qv><$C9Wxl^1!U~BxfDHj1g|8 zFNXp6sfd!;?Rw<;Gy_ROOF;0Y>zs^N5UAGW#Eu+*h8C9N5o4WcE;XzBTwh03HjKxP zR`wWb$}HXIQaaEreA42=QghC>>RhT7y69!YX9Y4VgViK)bk0Bx-&ZX__fh<0r7&Z3 zxoHf;6a;LOH-nG`F-e|{=Dt2!QDDTA>@9bO1PIX8OdV1jnVdLG<>m`Z-vHgK<|k0A zYy-OPypMDv5NFMK7MJ*Fawj?9js!O#i$! zN;TW$WP+%(jHlEx{pjNKo1-u>(s5pJ*^7ChO9TYBsexu8dq%O&{-c$?zDOJm4b9@x z(h<6$=w4>%r*$?fcWsdqv5Oij=u(EC@-{oqKL(3AP4a%ts_mdGbNt1*hbSx!k2OZXF&df<0Oo1)UwCW|fx;W>Blrs|&itlwQ(0C& zdT$&|A5s=Jb*8TQ?yhS47wUu*d{i%d@grRRtTUTwDOG(%dyNJ$ljX&kZA6ESy+-Fd zS+c5KR{LC%90K*SmmM1(wKNtqH{Bz47H_@3bnzvRa8?m57;oD41Z(^>@*08MJD`d4 zRM84`a&p2&Y5b{QbJbDm%}g-9;F}*vnI6unMwF!Q)^)4MdSl_@T1ss#Sk>jB+d_^9 zp(&Q#vg0?qrF`ShfR}!NZuJ|3i6dW515ecHmn`d=$T|?`}!2PbuirUDlY7?-SI5 z%tzbqh9AB2kXm#vm8B)PxlgMWoPagc7C)@%t-q~IL~z^c+*aL-F|S@-hzaHEpz=0- zp`FYGxGTfQ0|%hqt!rh#0AJ3lqwVxdpZNLgj1y>>2KoEjyR-u54sxGoMaLr-MNpTM zNYtxOJ5Sg3R)R)srV9MmhMP~L+Sx zt?8hd@?V+mW`N4e1z!~*FMHvJE=`us?3VV{JF{2YAIMDldu_R{G;P}eWGXIe8-KQr5jAAl#3*5h71^%p$`8VPEC!N3db0UA zugjQbbqh8XH=csoiifA=z>>KM=H*qM@kq3v(7^i!_h~m+Yat0><)%lw7eazEEK!3e zL`PPyAwI~$<-?J|750jA0;3YkQhpOC(qaJ83BzQ>?$&>~Kp+PNTKl0(z*yQSd@T2XB(jie9Zpmwa1zXA6_{8o8&;m#!hsnGZGKdK?Q#}k(I zjfdY1T@mctpLIe`zQ#&;VKRDmXVSv9du97s6^$cMS+IaU^ner_3I3uF(Vbl6<7z%);!u&;*<RXolJR zRcYUr=#MRsA7a#W_Vdkkly^glG2t)z5x)Tqm!sif?UUG}w>GIwRlCL4!CB?CuTa{o zgoE-gE>bVMu4N@R|89H7yFVo^DAp<3e%1S-4qr7i`eTZ5`8YssYGeKbcJ1u5>aq8u zu||zf!=oVDYJ1#5lQ!bB*RNI*$1?@P1C|JwsBrt%PMLLP)Kyfd1p+!5d$Of3!mwaO z5Q$WTVrq&az~^%c%69>evE_oGzj8@OFyZs$qzUtyCy=$(*UZM<YlVb_fPwXv z?GjxTzlfbSHlD+z4!!zv?y2JWEv!u5b$%fJA_kmB(?`fkdg^*=y0~Srsz<4z+kjZ7 zj!g&-a4O2`&C(OHK>jhLq!lhAY~VKFb+be zSfPLpI~SvB6X1gkSPC1zhOZ)W9;OK5sD^W90JITy{g+DSPAwZ78?acy+tbt2^Q7u( z?d91upfLXB39<;Jc_C2a0zqW`e`|lRLd|aK$Ru33yl#3ij3ER%{p)U-3_zsle?-O> z>$rNIZx8eefbB;|KIEToKfAH6wMt0vvh>>tkWpq- zN7JtB+ihSnIFs`~)(An+QyY4Rws)*;Y_NF!o9^1$VO|69gf<3(mk*o%TkIZ)378)~ zv>k70X~A^pKc?(Wg`^L}AveY$Wr6^SEdP-xT8vR3odRBkx-HSGhqIsV@`gh$%F9Eo zfC%f}f5&wO>L0?-*4EajWt*#VVv6R0XMnRmdet_lFxyWO5)x?LmSXyXDl34*PwB6#P@KOR zVci4CYCs()-h^eMb zUiRhDqDT(Ex=s5sLxg9$-Y${bF02aKI%QJl)V!i(@o{OE5sTc4wfn|GqGm9cPc0-Szni=rS<3bOA79_Pe0u%{8oh zi)uq;@35h-WO&Hw%QIlKo0jJMLXe^F>NrT4f1L+x`m=lBEt_8M58|w1jM=EGz2Eb+ zlLN!xQ0`%;J|8En=ho-P_N&nQ3|!36#NG7L9xX~H*gHiO=ly;YZMs(g&b;`2w^Zsj z9R$t%1e*V7S9zyw@pZfzY&Grh|$ zS=Qs{wL`ftH|XRK0eH*#{(KP7>uY)mX2y`^)@-v2!+`A|6Nc87OxE$dNSOqI+WzG1 zoYpJ1P^XI?BsQQR)Wjh#AGVsx)Wc?`i4%1@Al@<`F1s!R7fjwhbb<+PGwaNCY0)0bGGban z4Gw!6gPD16?e0q#oZ5zau#Z;k*i^HX=wzR2ozzQtd)Z&}4|EGW4Oy^X;Bjo?;(s>C z0|Q2#6*9M;V^CD0$H~3)aT17j+Fon|usitQ-B$|Ru{YZ_Mvd}?cfv%ZC1O6V=L?AL z=p?7EeAfr=EWbOEm8>5vh*`zW;-~l6N-%F-k3}u*UZLtqVC*f$zXDe+@b6MSW6pbS5=svsapjZkOBC_^#`B$T2c(+epJJxJPke8`#W(NTde(A*?cirbc8OU zMg2F?=1wf}#%hVsQweKSNl6LUo$%ffefo-VjF2|S9iy=Ypt{?JBp_a+-@^Tey)GY- zJ|QbqSfe4Tv&dJ3b=knZQDEv^Yv7=(yBj4u80n6{_Y|a$kue`qe*M|@_MAn4$3h7M z5$v z(34*JX7;_EI9cPYiv*Fge_-i6C1onXoSp{6M7KQm602i*<=La<>2Cnh9-CO@ zbete6{8q6wDq)NRtbydgX=uNOQun=ZEa2tp;L)A4&NJ50IA}ptAFQH97X6UTZ(DYF?<*o!Y9-I>HveNjuT(nPGTP3feH1hXV)*85 zYPz;gXv$KOlyNdc_h#zVs|3QRZoSskjxZ5)omfNNQ>xxky0iHCjl%^n1Z`DxFA15| z<9(s%zqrsY78wx{f&TPR23l6S5Q(G@<@8|y?@Bn{9kN=Pkc0}~R^6Q#Np>%_R<3(D z&G?RPu;TU-k8sO+=8{d=u5!WdwuT7D2-8zRJ39*tL-1sKHK(xMd`JH{w>r<#t%Xg} z#~WWY91GUk>nls|F3lTP#op~?oD-LvYsd;PGmxUk50hG4r%c8WlQIs98#{u2>6q@^=MiARP*w3u<0+NS<@T6 zxbs7JmzcB0i!Xks)HQAGXPTM4c2O%Ze1&j-@8NYh&GYj@?tKpKJ?izRBKWbyCtFF$ zyPn==7TtFxw>?+a-pZeO{GT*kC6f{sLF`#LS{fiEfDi?Mm}}qFS=SW0n_mc02?ZRB zE>f)(IFOS+w^W&Wom7IkRWle2!?`b4`CxTpXnhdl^u2czpD|cHMpuYXH!$Wf38Y%= zd>6V>N2nQSp}lzPWKA{QtEUHFbLymyu~WxaFsN|^{ZG@V`C}Rh*JRY<%XyO1-_5S^ zz|bY%Z^lV{0&GKO>B`YSt2XLJirkw&=b zcd$z9X4$nTgS^1= zT2$?bpph@|uK~8#=e4(k8zU~!jV%+KiAQIWAj6B5Fyq|$K8v;z2R}lF;S08v8<^@o zNi$i+kA4)`Z#~Y=H=A8OZZw2YH~^g!_0#p&#b)jpj5z;ok$-au_B!Ay42lx~LZ$pg z)~IeBc?A_(cdXlT-g&C`0Cs=SIQg7eWu_C!+DY)!rwv2zW%?$K5U~xY`N_9_R#%(f zaJ25tJM&bgSq1%LkEJ!hG>1qBac_9m24d0vs_}djyPlY%k(aAoXUZ%OjD051Q>^yt zRC~BM#|AksPuKf#UjA#Iq&OJ=pSk6VfMN?{SWF1d^A|f6qM_!g#`7C3go(C!9nrgf zoBgLc|Hm2H+n)kwNNY%)oEgvp{Mk9_=gtHBvXuI~`|oD^@zgWwH-g_(A!U;nkS4{p zvYjKJ08odj@dZqxes8)e^k=#b`4+qAO?+p#NgnayJ66X}6yHK3*k5e+gosZ1RIA8l z@FMk68P0MZ?#vq;YVyAQ#E}RLF2EJLLw5n`ca@YJPWYJ_jA>bjqBvduhq?M#p}v3r z&UHWhd!L3S+)bH~P_)1h@G{>tP66l3^RG;rzC+OZ`uV}7f?nIf=Lb2@LjJe+0h#F( zc~XCBdG6+>mA|M!`BA$@CV$-YFve$%^$+%k4EXN7|LxOn{k!ZNpq0K&LJ}@3GwC}0 zW6VGa)-dWn{dG&I7bnrYgS2ed3Q=m688JP5>WwWm4Yx|JzuBSX%f}$!` zNgB-9vW$I6wh+P~#*&?3>|-D9WAuJs*XO<;_aE@NANO~D^cd%y=W!m#YkfYSFJPlc zT#)P5{~B1fZmpc`Yz(yBZS!Ex14chq%fJRPJp1E^np)mYPQX8W zqUDMR1R}S?DxnM8pDL2&^_Aib@Oe1gH1Ft$t|A^lR`*%K>y>%PTPa+S&(#^3Kj8w0dhV)?P=H{B! z*AL!I+idY_#Yjzbw-3d2tsFJ7Qbr%W*m<-3t;wQ&xT-2b%&%ep%NlNs!q2{f#c1on zwv%>VVxBV}hHOv*QZOXnQ+*KA{M=+mB(y8N24W_IJKG zAvE9&$|-g{P&ieyrB|sAIBhomvh5GekAHq2^vlrIRb~~hpY1K}VrN|wA?BJ1@P>ky zbl>!_uq|zMJ|P^x;8rw>#3sfCAm`GLT&*0Y0*SMf>Zt?fI78@Na{A^$|5BfT{y@$t zk9kt3!ioErj$X`bIj&=QbqIl%P%6+JGM;8>BM`CK7xVO5-&{<1Mm_GQO_0g~kv#y$ zaixlC>RI_re3{42qCni^!zK^`h4h)aY7|g_7jpgt;{YlwmG6}dQAV6zTf78Ji#^W$ zZBcz4p{DM(3~{pJ@gaY9=;D+IWRz<`ef@ZM3vtv}@;dRLyO3C*ZnhwB#?PL?X_US} z$_9DWqB@ZWeyL%}5cR847LtpqFTP#$*;zw&E?}*BIE^wU${qp~R_a}I)anMaLp`Ps z*v&d+-h;!;4`l@v6^nl&(Rh_^Et?lM;5j+2JXNZGIbG-oho<;bMRaO8#u;`(imk>c zdkC`Xgv*l4E!N0=qs)S!a2Kg37@}P<$u|7ITrS8*PI{Nn{RssTiyEU;QBn2S`aagO z85tmNh-(eCITXY5_NDwSX@wLjEe&c@W6wS0#uVixvf03y@l40*Z!-D3LLwHimVzdY$;d`I%DJk6TBV0-6}&7(~@l_toigj$Agd z;Yel2#v{ePv1Ogrg|y%|Jl8Ydx^I2|$qW;v8Sqf~nao2K-cW9{<=Op3Uo?MfI-| zPcLx7cTFcAyBhXs&66H*_y<6eD@d6+64O+NJy6c~wjX=b^%Q#e9;TOf_&BzhZ!_iL z#+MvhX_B9MH5lC$`4PQqFRHF{L<^gBzQf`@o$HcK^pH&yU#F|;2-Bq-TA|Ro^EPdf zeeV!EKE~kCQO}|f(`v!KV1U(_6+w5jO>77Bzwiqtdo1#&#ss)>Pw&LYAm~^e57*a0 z7(6k^=GwEr`#XsTO{d+zZ?fLmE0iD_pp)PBacXBRzqwTB{?3wpMFqo$Fh3%$>D%8~ zxR;Rv7S)|LmqQUD}JCByH?t}xQL6-o>fE^s=pC-hwZk1m38xH*4(dO zgh4+_5=LK8$E#yDDIY-po6b?`!^I%@)m8n6cGph7`NdbIm2}&#>)I51Hz`m9H3Bqq zZ2F7Tztt?;SA4G^)To7F-_LB+WJGnC@ZFPqDQjNnT6y0)ujRpUyF*pi;1iMO!(HV; zftY^EY^m%hRSg?9zxys6(GFz=^87C?^6K{;+M=FR4Q8m0>j(53@ms>L6R?fSH?^Be z&L^p`i;ICWL>QdW_J&Sn>X+gu22@*LDOA|?ht`a-7#VOM{rV^S74B2d~33=D- zRg!MG-_Y3fFw)tl!{!Q$>kII3vj4KlI&wZ%ad=*GL)v2{2ws?8Q=F=*oue#!+{&1^ zy>bN0HSS_T3ac^9j%a)k)-~S1-e{65JszhiemWtB98e{HcET1UmD>wHYl8GTNs_D4 z!pZ@TV`l+Xqzj1o2yGC}(R4{m(nmj~E{f@}tE&qsJ1kop{g~gRbPydhjoCJGeD{m3 zgV#NyzVWd@joejZ9y}yX(sjFj@by+eqBv1;=H}t#bwV@u0O)^9)Pzj>} z=&$udk{E>GdAmq$u@|M?3Bzmk%%wa9FB9FaeJ-Gl#_ zsaQm{aKo3En`ZsxhkX@p8;Zm4J-&;-q6cJdtH^}08bF%A#)s;^OwRu!QWQ4Fn83BF z?dBk}tP^4FvFn```Q)?AQ3JZHr#f$TrXiE|p0%S4^qdwVT40MSZU>!kN3#TjvmIV~ zpIE*Xii(E>;=%%tGRfhFpAwlfn1865B+zI!%}(0~s&isgu8aIBSdmDyohgV500#!5 zF^lJDBW|R#-{Df4qH;ZIWf{+a!1Z-4f4j*l!_8KF9=WQ*d*|xayxbwP`=c7pAS>(m zty+{OE7(qaw#CF9+_)3eelT}k_k&6QX+4WQ)*{%V-|5;R|17bMhr3*U&Bv$^HS$&g z3BHxG){mkOQJ>Fbf5JSfzr>Y<7|BL3P$W+$*^Bne==itS&LEDQM;P1KxlYL3o}?H3 zBQX5OhqP7a8!-{;`J4%BE84%5YPzms}HOhHDpTxbJ* zs_}94OJaRZjdq>dB_N~s;X0_1Z3K5{t$Ip890%r^RTuEa2eJY8?u+nbtgi-0yd}5%j0E@SlYRA~GnjutXyAS6FJ%VjH+mPuvvxYozY} z(l$lXyI$Oy^eUR&?DhWo95bHoml=z>@|l@A%4iBR?J{T&)yYHU;L!YQej$mB$~izZ z?xnK2T7{bZ>I2MmUC&n!QV4NRQhe`-96-=Zmk9C`Nt8EfJ_*x&msRJRHBRBz2nmQK zH;5NjMGhq+DTx+S^{Z_d`|E^%pA#Wi71CV zB!Etim`DNJByh8?5Osg8qn01}Kc3%=(*}{+ORHt#-zDU2J&#%|xe!Y)k))s`P9QyR z;I*)@0e$xqsboxZQsb%=jA>sDU-#>($=tx?s;Xgf;P{ejfn~OtqK#2!i_(abxI5h! zX)~SNwJo(G?bzxszmKOmv>k zbwLRF7f6}L|I$57w}o??RJwTdcYn%{q18*RTmF(T3tB;Gorl6rup4Ra>Do7tcd^zs zNI@d9U=4H=bS>-n$nbL+e~-WgE4BKYznb|SR*G})V046*QDpZ*PRiMjErCaFEW>2ZeAvNC4-`g1 zRkgcryIwm6Zn(h*y=1~2-H~%nZp?fy<4$4PW<}JGeTKO^%BKZZ)JzTNQ_+3DmW97< zy&`n{e&48N+Hhz%-TWA_=yFt#Ixq@A(h%80I6Km{q&~4NIfQH{HXxSsSTl9GwN9j5 z|7^i!LlWeP>gn{CWo7&O(vtPlUwgs!@^@RR0dFiJO(v+Ve)O>S)U?npIB@>^sH{?t z2fWgF+GQzMRPIz>7;^FJk7ZIU>vR_~a3Duqj@Z=hKbpszT7;+9gc9?awSYGmZLy4B$!9QFiyjA*u!$cI`U3aX_KSEY~!6mc5|H6<}<-5bEe09{{*)k zB{^}VCj8x~7$ZLGNL3X*)9SsNI@hyDz?phn6Cc^SF8vcW@q4XMou_3Btkd9Fz^&}s z<%O%ApU7lVsw}cI^Gn0L!Px}~`;$ei{WP6BtNQ_8m4*gRRgmd< z;lavGl?D$+W3NG7Cu1|`fDuxv9g|GKA^8|TrpisV`fvCLmw^xth@kQsV?<;3?LAyF zVe!o=H1ltI?KoC))hNFbX;!8*ojM;YHhk~V{$g;=r|%&|nSq-NKMalyHpxMnHE%g) z$#f7C8ToIB@%fwfCb(qJj8%t7-6LT-T6Tjzt( z{DWV59-k_`c@tiSsZx=i**;J9`oo`I<4H6Lt|ujx2W(JeR1{L=-8ZEbKO2&TTz*_l zyGTR!y6xYP1R0B<0?(0RM8lO|fun{P;WR)eTrUrFFLh32l>Wr0kKvNS!k@tve~|iQ z@7@E@CaLKE->xGv{GTB4$-9&89q1M?f#$kB$8DN``BKn+wXV+7E;t9$d-{LVdk&y* zqt#c59Eg2?nYl58@(`d|sQ=l8PjObrFxk1)or8ho$M^e-%#1+(C+N8oebU9f_s2ki z)H}meE;g3O5vu5^3jPC71xUXQfDHB=En5M8-Qa~Y1aus7g68OjKbbr)KcsG_9YwP` z146OB0~R1adb`uy@31RIHGVap-&Tt!IF#@EnWOEWej*RG=;Xo-B+I*tCf+SM?Nw{5 zK7KHfwy`66sDdS!JN-H!O#6$NCfeFdmU{G5tUqdub5xD@kv+;*uKRHX8F#X{*u%qG zBRZ~|y_z}IvVcZqy!1+z?jq*j#qL zjBmKl+?K>$q1^@88vcJC+EKdLzh8jvuJR`vm@h% z$nkVg-F~>-!R+>i&)7cZu?$0bsI^|c+=h;igo{tncFD$~N(!4YMa0NP^K{XUgTb-3 z>QLUae6 z?5vxAcGgv5WPo^q8}HJw7DcjV#(DrJ1ac$5YeBiG`57GgM96v%OTMEc_{)32xvRA7 z6K8syDy68w3q?oc5$}bfvNQhG{%v6_v^0hVfd98gkTMd5COIV_%1uky4ui>6{^}rc~*wnL2;3R5=?KeCMdu~Wh1#PE=6gDG;AW{L6;QhSCe+Yn)d-@%ro2Z#oS~V z0SM5juZ#%{X*B>AQ8usp0v7Lj(;jBxedFf$%(i&%=&Jd0Pl>&{`iT6Save6C2Mzj@ zcK6ml@LU~TiQ`eL-8HE%V>*5+*7xdJ+<3PRd?009&Xsd3wSJcAILF-KvcOQM+B2IM z!9~kI^)%ayz+baZS9Rt0WOQ6{b6tSFQE^Bpp?r-9*Vg8Pqya!b2^y1}%yHTA!-#I8 zoR|ng57g(l{v?E7r?7}4>q;pd`(AbjhS?lLWv2k+FS6b>81>{AcaqCeT?o-jeyzOd zMIc& z{m&NchRktRJ=3ia^DDLNzI_v-kO5kePs?>gql}6QgZHGB)w$7oDfh4BZ2p?PW){SS z@!Cw%{Vf6$NJ2nNm0*r?c2;~d9^99eDk=?AJ;ps~OkaCM2(5d{ErQeBC*R@aGZ5Lo zlES&7&{E0e<45bvKC&THwHCagC(-yGp;pE=Z0px5S83=5hb|XmG|FC-LKX>aNUlT# z|0g>V?8%6!(`s#w2EgL7e%_@A$QFeYqkbLO>ZBw!{Qbjcy>}!lAby_Sb*XtWt3_cB z3Cu&}1V?k{_gJrECEI7YHaTK%qrs1%3*072g~Skwt@esuQ5){=mTgbLx+U zjwGiQ*7uvsg&N`o7<$cd5gmk$9h!{MxT?vYG6l46ME2M8^q>t5yt`(wLP@TxgP@mz zh7j`kA@YoH(DqwQTC@#)gW}j>NINf`%n&&j$sOw};$n<%2%Ab<|L8Du5tVD^X5L z0!eylc0jd?^wL~oWayLc`?{&$d!tLo$=r!<&1t>N);96tv7hEv$bvFQ+qzhpw8&D; zhJQ0mo`_(k8z)yK4tWG8T$;@p2}kt|4k`#159D;hOHnbW6*TvjFMH!3qGFQ`Q5Q?? zpy~<=*cDpBb+qGBL#W`$=x4pw%gj|fY4uyzM>Pt$#EDW@g3_DS{V~iJy+qwKPpzfl zd1FULBB;!Xkik5@)$q&V+U9<-GRpRC2oWJ^2e}zcBe|(HVld2`>&H$^6p{c;&;Ip4 z&Zm->p35ohZ=D;~r8=2_Pm0L7AtRHPBkO#SkgtFIe&EFgEo-k;^Xixn$oS%0B#K&= zmZij@q5k@*&gP?~p%Z`~i6(S{?<9Oor-oelOoaq)ph^1@>L(WKH@}@XLDUmfj-NG6 zfgz1jCAVXp_aIgPV|SYqEkNHEnU>q9&0XvCapl$QcG@0`+asu1$Mm`BvUEVM29 zUWK{E@vc;O`sFczEV##<=hvZX)R?eZv%f#X%uOETl+QUwz|y)dk&D zFGbC%+_)@u6$?)58PBv5wy;^M$}bn!(ys6%!#-!2HbyxSv@8u>vh__ET>l;l0^GMk z87BSG<%!gv@5D{mRht0^>XSbunJ2j+ic(dWbr&&yZrT2VR*+7&))^O1KR-X2f*mYu zF84aY!|(!L%X)bIfGj4q!T+f7;X%#;{;AD#|Dj&jb;$A1JZAs37+|Q7M563j`kkKS zP$bLBmAUi`#mqz)c)Z8!d(2;%kC0M#9C+a4W|&^7?le#$JzsUfqw_*r-0w{8Zkx$3 z7Fx}IKP(Fbt?xQ6BnZs#0^qUqw||76ZV7jO6|}EDZoIuNpxeh-9Y-l0#5*A08sNh( zqhB=Bng4eQ{*1oDu=&oO0t+ps<8kqSP2MX%kvi&;@bfKjiTm^Y@ zb`$plaBFkoCK}&P*Q5AuGe9m}Sv{_WdWWU3Oag z6sKLb&D-tqeuGVL-Zw#1BzFm_)(s?`k~d94d=x{bpR8%n&zHV5xX(2uHCH@XBC`kB zhK*Q%2_7Rjx3rvbKKkoZ2ff&?{IF^iul7|kPf9~nyhEuWtV+EO%FRIk?Y}}&A|=~b z2|cfOTSlj}7>jrWMhr%t#ldm7NBI4Cy(GrD5nY#ceT`%TO1jl2Ot<~hO019q{Ej^m zhGN@mzq${J^>!kf#`ha)xgpooZLyQ|Ie=_k(vdR2&Kj7WAv3d8$bEs~O4i~#&IDIL z>13N>Bi;N_TsdS_8sL6hFP;-W5;sT$b;-S*uZWC z#2C}G0gHbEDvgM6$mhSqcb-{feCXvU)Slzj9jq`S8`<}|YkqZ$9-S(NxhGmS1(<=@ z4%my<+G_9TcWe}^J~Gl^K3uCCmF?5hLYro9qkifU(mZk49 zH_~3*dewqm#h25%EOF_>-Ar9JHmu<*6=ynbmfYZxuN3Of|04u7W^Zd=GM3k*b_PqN z(08enJxx{{O=>YH!f~rhK7=Emb7+VowjAx)MoCv>hEl!$`;`FH9jLhX`W-GjH5P3Z9O_EU~O5=KDpu3hRrUwo?OBw&hoi5 z4%FmCnO>xFh2MvWjB3t1lZ1oH`L^!nHs${{9vf6BwafOqjBM&K;gimTz~}O}6E1 z9qH)O=38Bg7_Z8vpM@)+Cq7Oa-gw5ArwX557*ZyCJr6LE z@vqvof})9M!qAYhax{^+GeW(6Dd&#jGv8VObH05mD(4kDzvbO~R#Y{?5~{Pf8(r0| zOR6J4JdK6g$+jzcSqaZb=MlCq6w~dNHNhi!Ev7$Ha?DpUU6I41AmZZj{m#kHf$D)! z(veMzrOD?H4*p6}`<8bg`l_HAvP(pIkDt4h&!&hC%j7*e?q8Xc?K<$p_L23cE-JA& zVUkI|oL^(X7J0Gf#7a@!PT$D%-xReL%oA`n(_}#hcsw**GrDK0pPZpP4rTJ;F613p z_og9R1F-v(w!e3u+&dUjP&3{I$LSUq2jwyNFx=i=*o1(`3U>>R4Is-;duBNBf6#R$ zXl9Hjjh$%A1XhH;fftpycA(hK+j^h?MRsQ!z#i)aubZFS7_SruQGTVlGC;ds zW?;9?uCOVptZ7~RhwHD8n}*^AiRaH;XMQ?vxq=)EDU7^zD}UTghzB{7OHJI6l9)ke>yX|jFm8vUKn!Y$uWM_{mLv|4*$sEp|AP?7et=f zhN;r`iQ}2?7lrEFb9mffsGKXM7kqVx=-GZ)e4f<;#7tTH{`9Oi+}{sTcYY4|ewvA0 zE>V>o_q09U<81ZmTyUGM`&6&0-Ru0CHJTI08diNngChp`d=$%x z;8dm%Rl@I!$E{%}3NZIhu zrN817z$`JO)6!z@5tQ&sl2J94)B3kBh?_olXtA?l?fUIrFF(|cen3Cl9HsiS#eH(Q zeJpcH-fT9ky71YOQHsX{cp~W#3<1tz{8k6)5CnylL*iAn(cV$m*~VQ~_|ffD;4tITG_Keya;C0l8v?Z31`a zYDLBB{>zyIAE?4TQhnVj>sx8!G+hUivRD_iX}RUthPk$B*jfMSZ` zepE{jv>%O2dYhjF;C~#(; zfXj1-P0r|54JMkl1S|J_<@=tWhjq*7%;yn{)n&UW0B>1gy52uu@aFC*s zi2Y~3Uca}C>uuWPWQn;lwm0*P*e+B+=A`???C94>Nl(G5=PQD z529I1Ua=RQJ%1rL%3J4|?RUr3+(!9Ws$Y!$uu`WTpNfeH-r;)GT>ab21HG%b=5YD~ zob}suoVrtk{<=zC$628!N4_1Xy~CKD=jf7trvxM3wqWy&e$~)!WyZy;p&-Xd+e;4U zv*>r4Qy z1Wx$Q=j2d2k3W`o(%GY>NIC&(vtx0Wop}C*J{<1Ol;*Q+8*v9W#j(@Qr(jB9110+QPrZ`;(-#ObQ zgZ!K71_($2y)Ov4U0$B*AcohHl0E!r*+$9AKKIJ^uosAQKx-DA{k^>x2D_{fxu9Q0 z>SL;spIr=N`i!$~YqxPJQ)4ZV`vkA()S|=@K&xB@i0W6XK7``y=Gs_^O6 zfW*>&+2R9=3XCjE-zVlvOi_BSj~01cE^zh_!bfEBkIT@LaG=VTK)ZMX= z&biuO2d85H5|U#|mA&rq6j4K{ebBNu;YZeF z(D>Wuk+hj}NlWxzeV9zFJ8uBBLSC`}V_0@{;NA#hRRFH+B*oO8;*bG?en4C*sBOfK z6fZS(k4Y&m${NY~?sWeE3JR(nfVIuM*F9wF`t$vpJBah3LJIvg|ZTe%UVpK+3v8$u1{tdQPVO&<^Dj68?ovJVIXvQ-ok zB}o68$q;%nnxKysLi!)B2d{w#~5( zkd0aO8}iwwhU_Pm0lPLh`WZ&?HQjf`?9OM8Xbi0_-QR)B#((Q5WS}xem$l=f?qujK zpQTk(grgEu5W$#1861u5q+I{;^~2DHXAIFmGbKV9&P?)?ueU(qQy&oP>6^V^Y?6u1 zFk~7#9(VZoxGK-B$4RpqBF9qe;y1PTevS#W$}af&?1`Y|Y2wp6!joPt-MwmXA(I#V zNdiL)tVWQ4Q7reJK?Z0>E62-)IIDoo*m*mR>5h@RjNtK5*B`baPY{R#e6Bc}zb$b5lgXss!y4!WDHJLL<2Smicm| zoa(ez&@Y-h)+xz-=G+$OJv;vyE8+fEAVMIT@Oa3_e;GnGR)tK*$C55~(LUc!9ZeYz5c)&BH5JCl**}c6zP|(AA z`0eh4abt7AVA<-}jRl{kxK@_s<$jfPF(g%%BZp{jzn;<3VA!Yz6EW$1N(dXo_xoyG8XmeDZSl&~b$5j`>{9 zz!kv0KLqp0Xk(F>&7ZV|*Kzh_NF+d@%^+sO&p=Xc~3a@rmBh$D*xNWEaPL zyX5Sm)Q7rKYLt@oV~&rl>iwUpg76SY>dON3EO%(d#|m78igSWdqMYYu>*$qlDeK2b3TmIY*Fnj$@` zL&@1I2RVD3O-6JW25LsycH?oLD;7*g1%b5G7C*iexdeYCGr$LIHe&G5S zMMk=WXWO;Rj*TZRF+ECQc$3W?Szs}-aH{%hy}jSEWW30|Zs$N3RMql?m|P(ogk{J- zV{ znJnqeR&tTVHJ^NmOps(KNm_dW&psYc?R9@U+=3>I5ba!!5xB)dHFxGeUt&L+D2LbJbY$+)Ud;6LgwkK&YB=DU8=XOILBn{y6 z1$529-Hw5249v&tZS|!#)iJE5I2bZ$4-}UGS5ZaU_iHGaBu)Bs|9SL2RrgnsWrz1( zPJ64*7Ow;X9z?(UA~JuWK}Tj(LvCO=69zix;PYCXKwag+UTSPBbGNrCzr zrxxx5t)HK+8W}9ui&swUE3d4&5PYcn}N&NWvA6}lNt&34quHY9%>6)>xq8lxu1 z>AvC%vLJK~q~Q>s@YR)Ob$yXCH6~vin^;E1Ck#?dUlJM}Z5@$K8V z5%$qoFeOh{BW4vtY1m-ECx-#zpw{e!BwPkuYdwr#+_Yb$@Xp&vncA0Yf%y)))WbSg z8h$;?rTUcmA-n#%D|{k>hn8zer6&2KE!I%`P@ybY`^Z8zQX?$)9`f;XdA% z^6Yh?G4W2j>jTgDIAz7LR7KJ(dTyWh!_mg2)X@hcoS3(`H%ruwVqoPm`kxZNq@P4*v(pZrv*{29WtMDIN*F#5jk*A3+0 zNza;UK&V?f` zohB_Im)|gMb%u$k6q`lXpi1=%$Bi_PwQ9beImFk8dkp4Lmv(z2sn1K-UgsYVwk&rN z`Ub{>&a{}-vA9yVi4~R0*nhqctwPY$ohgW|qnIcUIUK(VyNA-V_|Mlw2 z?NqK^W2&M2@v_qW#@BkvyOiuEqiDO?5oz;Ep@f9xyf&=+R#TXwI*7o(c|sY%hSHgomE^h{gP&Td1BBa zz&=V`>bNs_DnH(ydR4h#How&gZ%`$9@I%2JaZ#U+IJVShep5uFlP@L&F}0+zQlLhV zAT(^@$G&hJ?uGA?MISWVz-FZo+>{?CeC0FhzgOR#8!C`>^x$5JbkAW@c6|0;9<7nT zBT;%1oaj`(NO=o0^YR!=IWxHZ`Dp)}*v*tM#ZE1Dct_DtAQ;?SeCJAW;md~`t|d;h zICmboN~cPhd!`|We3V1KOk8IKC#lo%)=$jB<+~a=3LUS4>Cc57B@WL&dM||!P~K$L zxE`h1$(MGwIIGw-wjm1iR zPHG=i_mSdaG<`NoY4EahJe(OPh7ITVjRgi~oY@fjNPv2x!^SzI72-gNJcU~zUJJp`4J!w|>e%@E&6b;Wf@mumB!M9lA zaQ-UZ-oVbTT%`Xn(?Y>6sCfJf@k%G{+#S63^429dA;ww{Q{*)Qv%<4VQb*y(9XXSm zOVOV7=#liaZOU|wnh{3I&8;8%?#>xP0b>KGrNHe0SvVzn)b(dQHT^Dz2T}jvs7gou zau@ppKA1_>(KGQ=AJ`FVoFgm!%u7q~hC3bu)g~GF^p<0Gt(q)}pVj!TZ2o)fhHqzX z927gs@E4sLyrWZYY+&GN!d*}7>`bgpcNBN31#;R!)P4M%Io)9?R4#Vs6>qdI#lrTA z&Ekalf_N0f=(iJYPgngi!=5*~0LI)eVuT1(W{SX4erk?x?Ra=lcWBWVOrN*uo9&Ek zq^A^cF7_=NKo0@I9OQg(X88A~PMnp6W{PE@T-mp#Th z^{FT_h@ARmWHMotm1??d#6JVn$A=1JmPo^t%#>@S_`&q^%Du&PeoOB!NFTu1747$scbtB9)MKJVY6FX;?Dg1oM zrP-0IQ($WQ2vE#&=F8o#TP_xU8R!8HDeJ*%V|K?wqO93X?zpv#eHxy9KQA7=*1b-%0pQ>{@ElCk^Mm+WVOvdc}9!`i!)v-PlPI>)usB=0cW zWS@UczM+#Jr*|f!Uo78NpVjaeM(ts6@+|{JM$&>7yu-Id8iyWUmR{e$Dcj5AjV%Wr z2OE}TG-~(=?w%nJ{$St?tq~*ETH}MNNkzYevex!`}bldYH^G9_>)WJd)+edKqDHKeSGyrdsoU z?VH~2ZVib}N9HAd-SZ6ZWX&7z`2FS*@gCT!RVhro0)gx%y}M3#QAVl;#I3%ObF`iaP?Dlj%GGO z(Q+%FZ60I&NTETUe}T&byn%?8Cw%nX_`^&k`}C_TFMn3D4&OjZlGP*&MOR0JU!lOb zay2hz<%kcsPR3X*xb1(mh=Q63$S&`j+pB=^p+zSwN%@n<{@G6aTN{ahE+Hr7qlb^( z)f|mO9w80RTR3+WI_aEuepXg0q|*&L@YAb4h5?h9@nw;H@sZVEVoFV}nQ&u0I#XJK z46d`$*6eKa+6QD%?ZVVfW2U_^6|jWr<}W8TiVv!-O}+}I)+wZY3?qd&bw+n_2dRdC zqG%JLQEo~J>6~X`JQma=3RhcsQqAOPOIoVGok`;7EP*)VSEE{&G`5trqe?%Sz-OK} z_g=jjUT^F}6OirOkG0I$4ATga=ll%Dj1HOc( z*JQmPUO=08>QyGc&roJ^>B!eEQcxi%eNcCa?N>H%;uPj-9g^;cm1W|~-VVW5?_YQl zT8G}PM=ME48BQc0bgO-od~X@iz?4Mw+)%R<5n60BJJqT3MGS@~&*f-1hmVNz`X#gX z5cj|E^GJyB1BFjp29a`PLkQ$ROW$`(SGWDE`f$ zM#yVYi~#QpyM~618Ryu8O}3zr{T7>`Si{TY4T<#XD!~*gd&37aV)`Oa9fk&$pS5f- z1I&qB;KLE}(#8vvd|0L(`us}-o2Z`bxyUS1tVVJ<@7QH(igRX^?Nk?OH+ZzSigT=H zvyUP#6=v&jqGU1~DC*$6B7;NHov=I1TQ~l49>&YG-Zbz`4ly!;Ls2v;TD4aN>;FB5 zpa*^I&(6Gj`@6aM?i_BJXK;V4l+&>9$)MW6ki~@RSYX!(UX$5*k4E0&V08Y zNVdSsKKfF}o1_=%(gmli#h0KVyk0kG-LFyze1sdzZz$NXUNod;QYa|n;HJX6ReO(h ztTEUQzi^waVK_gn3=y4v~oP;-&LqVs(Ss2(G?R>@m${v6Vl362K6VZZ!u0k`{(u78$Py$~00MKj>Opsu#j zcJjoQAGYHOu6BAQ zn+OjS)vYKu?3`%*QVYEFn`<)dbI#aL<7WryFR?#xAuvoV$eRXz7a-46&%oyld*)3>LOVCF4SOZxRbht><~ zX@mH`DA>$?RSkL$x|o#e7y0B>-Vxp|3s_r>uVeYfMK1lu$cbz3B+<}$2|1n#@4*B{ z)TlJ(sw!sc-uy&yHsB3gk${1HK2ma(y$epRi+%1GmP$;Rf zKd)l-(_1d`62d^BYjI)}ob8Jn&`J(%$0eEK_K0F@lWVInyCG{q6ze-Xb+ySA zN~@hLT!BVT61k{l6^QN2y>kVkZsC_&7-C+wA^*7f(l25CLwsC=X)j2DRM$GM_Wvzj zRczNn)CXrtjhp2~RprxEj{eN5c>U#`V90Tg+}^N2RyVw-|)b!>>{>uCEwp52GWPjJ&^h$@;^lq|^ zu|RvdzUawmI5c)U8idM7bv_e$kA_pn|BT*W(T@lS%}wC@45Aln!Cv<~=>t{*pS&+c zSB3zVw&cjeq9Dw#uN1R3Kct~!%}C1Ew9v7e{}|!_6~&&@|Jy5dkITQ#EG#rzJ*Ybk z2Svk^0_1<^WWTn`gezzPvhIt9k^LHd<5DU1OF103|5JMW?-1_KJjXAG6wDRs^w{dJ zZPE!p+tcj45%$6?t^aSG0$*RJ$Ep-?I`p;oocAO~_m=J4O7+qSk!t$`=btfYb~b*K z6CEAfHn3Y_W6MHq{F&q({;J=jq59=!GRP7PJ6Y^YsS9NpwIfb-zBanhE;M3%?YtJc zZ-qtI?e(kzALY(zzXGu(x%PVExX9GyORG4C+#;Fg6C@=}*6}kPV?D09M5VsqsqbsWKfr`J0 zW)FZE&lOl?RPWQsR#w^vngBkOF=Qv{^$=Jpu2#Q;n|}V(bUpuzC%C82N#iN!{z7_lRS#zkmfs&SaZ%*XM}VTQ_lv;PqroahN252kxwEn7)oWbkC+!{~ zy_ubT`fPH_bUCJn+UuJ}vcp&VF0hAvf;WBoi%kT_W%GB7$C2&_?xND$LoePuv#811 zdzXCrR;UqwoN6vC>jrwqNRs0yTt?`yws(~LYuem}HfI}vSjsLhv_f(L90ABTIA)Qd zZue(F6&HF_ss6NtheC@2L2||gIVg+57_mo`@h(G&#}SzJOS2T0ZiS-5GEierG%9^Hy^sm<%H)+l@vw!5bO7O=_9 z^%5V7IK6RV@H3FR?;|O>SG#ZGq-mN;;`w*KIR}`UWNPd(2CKco15RCjU}_e&u1RTI z0TZ8C6e#~5ARfwC3`Bbl)4f_#u(t)e`WBMu2Hl$?O6#l=m7dP7o}aliKPR)teAm=5 zSuGFDCvvb_U#&ND)tG%nb1Zen1}+greRVjHF<`PQ$(?N?v8{z-o6IowAv{riYI zVik5?1R2)7;)=_?c5vv+XJ0Rb;xjM+=!$Qg&RS5i4-2Hn((>@dT{%BaeeL^3VeYd)kIk@ozD_fsr=C2YCS2A zyn|@+)y?RHztJfU^U3#jDf~dmo>cIM^S8KmZR~xWyh7i8xzg_s`p9|eNZvwwF9tm8 zv)Rns*LF}3WbC&w$a2^QsTHJk>2$J!eP3kECWi>? zbxvx#Ia@9@w$zmYaV_t!+2R}xY61ZF#inDeRsh7P^W5=hDI|NlcU_MK-<#LoyF3by zptZcun$8H?y77R1sB1r75WRjb3h2H2vA%7HtSOty3Tyck{H^TZ8&Qdp*091bm%@=a zbpnI(pGc$6i1LRbS{lT_y&8jpXJDgCT>qh~p0$8HM}mbInITSd#`dwui))MrG#96o z_yQXlR`^7fpom*dpMyI<6{Mok_<;|kn8IdEb>M1m1RHIj0Yy-79Q3k53ImTa4RlpX zHFh=udI7&QV^F5r2<#e`_nUb!>lWl+9ZrU-Z(aq&_)?ltR6qWAZzLE0xEab}qRU!a zEJ_nNv94uU^ziT|?FV2|3t7^|)(s^M>)-}(*|G4EFI8yYSgkSE-47&la4l>c#qHLI z<9^5tOurp%R!$WGJUuz`?P4*`<1rkdHt0WO!(au`#HqS*0 zlWyR$4q`sc6J$Y%1OaGT^O3l zEz=4f++kON?FGifkb^zIGklda?Y}P)ZUx{?j`KksFN%%ssqGIfvo6IwHB6|JMm;N1 zjtf@Eh^xO7O56!7)zk_CP+xIJC_#fn^_}#Q41p0{!f(+ZXO4%c!95N4OHDo~R107S zSsUfAX7(<9=v1nl>@MWe@w@ea-37b4v=Dww_nH7!nJgr#kWWd+fP-tO|MX8UWZ4*C71##_0Pf5Kd@Luz)Q#a-i3uJ#P+ zb$LU#^$OlV+v+m`;VAm~Mt+|$vpcU)FU%OOsPu2K7;ohmf&sb$p4Z9%Up1Vn@9Q(W0L*BjI^nI2Ho(wt>RGR@bk4!UzbMa zPAtFfJ8{i+%kPO4#2i>jX}?!JKnnG*o}!@bv&FZ03b?^Ag%>ngvXb{W0rKzw$V3FW6HRm^4a;e2#e6iNxI|yj%lae2#Kog_ z2pYRWRr>s1%~Il!l`;@P@=z4o=P*M1<9LSHZ|Z;A+4irs^fb?RrR$CnfV;3`eb#nX zW4cpt=Td;7uI|ab7G<1?y#T{q06k}Hr8fIz?Z#I=r3#7i+wk$x+ z0m>L|A+@B)1nprs*%)`9GWw@HiIRLkHru}!1oY$Eo|+Y^$+;=j4P#e1W0VZ>PFxT` z(5ieB$uyF%EbWMs6hTf5b>y_| z>K8d>nwEbyGJ{LU%;s1hDI^~c&aNRF1s=Ga4RmPwntT=Wp=DF<#;y?1;rp^EieBOE4H- zSh%G@uGb(hcSHEwNK@Seec&5UpcyAv*bAOJ)gOoaX?_(#j1 zji{ikX8NNgCuia*hdb)INp393x)-rFNc4WFvma^bFXl^O?*$87=wcfHQUgNanxb zV%X&Ex`vDcwt-wH)!iDYNAqFBn2*5+#)K z_5Th<^H8aA120G1N(WeU;5aIZSY11B0S%Ng(|`MLn-Xh0X%Vsq5fLrV!#xI;9@f=^ z8B_9x#*kDlCcELkd=la-Fhbey`%Fg<*GMbm?N#*5NEPwu2pb6WI2Z51ayNNepxnMY zJ(bLkynYM>`w?<_+qmG}r@b?olj$B6O6pEHXw7Em)VLZC__unMG0P@QMJeKVgjCbpA#aSfxpIZs1P|oa{`_6c5#U&uj2`B*A{TRCW>Eb{$ z3=2fV9N&AC1LR2q4)W`tUpjL?1|Y9M0W@1F;LcTuYMHpZ{NwhI27jI0w>S<51r9L+ zB_Ue>dgb4KTEV%0n*Mm&w3o&M^?N|Bz2m}hI_haNj^xPzslQtRa_Am6eDc7Ve=TpP zSN}qtom~Ah|4y#{fu0>-{j-doRQ-cLJGuIoP3h#~pS9-X>VF$M^FOj1_sA8VK(^qN zD|O`EnuO#i5}mE8p=*W7&%NLfO+`b5A641CGNoU=O>_h7(zM|}bPa@msnc?twW}Y1 zME{%@-=S!4zdm)ov#fa@_z=86bymfhlvmah{aF0Hfj_FfUFn{%2O@#_mtzR(6{mjTmd3tq~9}XC2Ds zq8(yKsi&Mj>JX<9NA{UriLtij@e%KB8yb1yxt3h5)MqM_R7LiC9p`B3W0>mQBeyPZ zj0!Iw zTPYYU#W{wXl~-zf_kl?9RiR&S$;RGe?k6QYAWC2Y=Vm@BYfhLmVZ@y)8{;-lW#tXC zbI!^iv>IpWFODfyyHa{BjXX|1lG}-u_RBZ@s|Na?@s zx`qimadi*e3l|Ar#Bm|4#fE!-RZwzh;C$QZQm>TCiuH9IMR$ClZ(hosZDB6mfeZ8w zVI{kD8@DcP<&$^JW_f-N6UE#hnA*qPw z-AKM<$lz9GAtrytxx2+~+1S>mvP$wRj|ca(VS1G1vK|3t6&bx?w-=xlo~Gjbr&M2( z_`R{ZbF%u}e$Uc*-D_uKc=uPVlp-y)By8sS&=(3UMLsUAX2dM8fv!?)x&sGzHz)neYV-Bf1wXX$qb zx4?*)%}j&a>S{>jeo@JHP6hX`ArWSyYy8*xXY&2cAr8(83L8<&OjV9dyl>KaV=BG* z^K+8rTDw}WNKBP~HS)aY%tF~#w@n<$nq5k}iP2p3t6+%jTa4syx@@!}P3@>HEVGfJ zssZv6L<1fCYXsxidAL2?+FeIIt6`OLF!(`C;K+`Hrf?2Ru{>dq8Ol%lG6wP$&^wR3nsiwuKDGbq{3jl4z}uk6Nfls-TYT}AiJ_5&I9 z@i`vICX0huMWU`1oyWRW6IBeCFAuL_^5JBOm>l72ZyKGCSsyk$Zn(u*K*!&ZkX{!m z!X&nXs;$;MlFT{o%|xMB4r}RUb)`Jh{#I(3z)=BXB~&aHv|-uJXD|5SYi!AwRQk;X zIkS7RjCI{#%>lmUn$s?oLG({n8}06nBg`Q4xxRQF^*Kvx=8^csm{jWO-iLPnOWS8N zXP;$fIze*wq}cN-9a_ZcJ9ftSW$y+qw*$tDms>bZoA%%S=4tv(eH+f+&M+ zuZi(FPiZmpXNBDsbQ~l_G0zC%IlkED&?Bwqk<``fQ=dPj*=86KKDc&e1nVl*z%h#y z8$F?;n1O2}#I!(8Wt}ftXP3X5!e^Zy28_}ZzjH(kG>S>}f6d=nG{o9m8!d@wdX^%b zn#m8Rnd-mkO>_;TcwUbzj>p9liv}UP<4l@am)kj0J!^QPKqZrx9fL#o#r!W>k7@5- z6-{X!Pv=@IVvg6jA|I6#EImC-(lYh*cq%D%p>cH*g%0*y`Pwi>LtGVnMC^4;{UrGS zWwPz?`lw<|V;N2CUeeSfcN^|rduQb99oRtF{~1gn^ZOfEj=7B{xx=U;dGK;bJ(aV) zmB+mMoIx?6&Z+=NA84AC9P@f!s$8aaa7@7ZK`sLWnBb!-pfg6|cFTN$@*jJ(YsHDo0>77a{F;A)nCoK5GYsRO8H z;B{mPkxK@td25Gt9lwH`uw8RQkp;{#lcb@LJ7&83jkE$+RJ&(FTV8OF8sM1&9(cMzQQkV{C4dz1HBKaroH z8x)cpnlhE#8I?0^snj5NzyCpXb=`m_0L0JG!X+8t^EKL9rRta_R1t?FtTbD z11Va@kVSXGV$F;P`8Jx98uUk`u=gcZ)qMOpDjo!hR*%V8P+jBcz)CiEePxc$y_^qg z3>49rk-NpJw(Ll+BnPu~uzyfw7FLpI8THZ`Y&}TMoz^Ob0Ib){L^g{Fg);GV@2G~ob74F2ULCz%^=E1ea&Yc|+ z5Y*h?2AVIDyol9EBYW#p;6zIj&7fA9cb)5R_*1b=tFCO;YB?sni6HJi(G?|Ec<2Ry zV}DPxTJ(`-SHsPwX9v-a_&16DV7kV=_cJY~{Eg$5(5Asb_bWyt*<;v4b^7E*WrYI6 zgg=3tjB7~GXCrI2*Ot4>TU`m>NOg!Fp8ODKH|42xk{Y_?LwK+I*az z#lpT}G3UtaKL#}C?jg8YXC(3MFLP~(NoED53WN*aC9ga8zo&R|Bt~v&f3GZGtGXK1hMaIVcYpsn4NvG0hST&4BP(Bw z;R=0oXSs7oAtE#1Rer&6;=PqO*)|~eiN}WSS=w4wwc z03Ag9yv0>YXn-N(M|Bm{Xo?It@K^e~*xE_cB3()!k_mZRyeTM z53f*nis-JeR2@8dny`29MS@kUVJORN<${Y{rYZa^8*@SUZogh~;gzt=uF?ZxV+_?6 z@8X;!ibK}M%$gvH=#Mb@=%}8|`NQ)_Y-Lh0s0~!gU!~sca8P7;qzho`si>0&^MmX$t--$nj-& zc5oYrnu)LC`;Zh*L*#2zJbZtuEevrctI)mUaIq9&cI%!)h0{egwOO*k+fs^xWxITSncw%o(iS>ZmG~Typ z>v`9^)l1TJN6g3!BceDo*k|_^XU4~N8;~PimX{nMZDLHa8d>KIa&#$3PgrU@Xl^hU zL(0bJ-;#eHwmK;D=PoqJVoeh~X?_#8eI~NY>Y_tCYdQr}!9tLG7cwZVlw$Ehwr)=@ zu7Oi60;zXooLWMVru3n-g*`aLf2GOBs#oFiR;6@e4a2V$8Wj4Z`A*+h${BLir$LeL zy02Ia%#2xH?ycKiUQy#w=JT1qJk?RBrL&*U9K|>@q-Cfkhxs;9S>SY+)hbgovC1K4 zDPLpm&$GfC$~p7b!=B>ilkuTj)$S+W8m5 z#sv|U%$wKL?*=c`!0Yhv#*fd)d6@w$5pVUW8Raibvt( zFw=^uphNw-@6`(3ef%ZWOJggwhDwB`ySkOAo&M@xz8BB2j-{8H+6EoW{5eV=1c~{C z_B{%mJ)uFVjTP`{Pbg~RfE9)t>O$_0|>>197{keSP1y8B1@YR|VXy@a<-$CFr9s#c!0#pPUO+lZDw!5a-%E3*I^Yo zLx{|+`ZOYq3unRiG|;Rpb3WIoRL1I)?9Ao_ovFX>^<49MFU>i3Z@i0Xy%m^`J{GVg z9vKXxtEyBk9zp=t6i#ljZ610%6)?s~?-p!iT zs&lJSAD-m;EX4gs66o>wtrxRKH*iFFY5er-jV2geYb+Jd^m}mC+{()@qTD5TOmc^i zj@+^Es}iUgD&ojExY~AAgg(#_$sxo{cX5>jiZM-Z<$XRCwkmPy(xp;u)Vc&RyhN)$ zD@}{-Og6RmM4P0J+ynEpiH@|P1{(w8XEo}5r6^`}!2%;(V_C6Ah`^X_+@qu&xF0{N z8IQG3J%?Zw+!OOqvW9)ih^MUPaASpWDlP>)B-7fHW$42D;Jzv6_Vs)Up1$_@wh^=Z z925BftA_OD$&V?>U$h0`)RV_+nEoge2s7%@$74cgu}Y5atT2et0qNa-g&mQcoMsed z+dTx9JlFP+xbY(SdC{<%-TBxqzn6rNTeo2(kdRrUWC^e%?|_?VlAG+N$t!MTTCu)4 zME^DZUt;QQSRBq|w?gTYWmK9o(!%%0-YAGiNXHqh9qBVQS$KOltqKr_trKxrwRMYw zXTDU}jfWdTnn!tVK#I+IgO>aWe^!YxBVABChb#!o>CvJA?TT5?iX+D*2Ipl1?kH(( zni5>v>WsG7yq;nCqbA-1S)3%aTB8}Pg1e;Gsj^##c>FPX;ewIreM#Rl$|I(D^;4lp zvVeWwh||zc!FzwRc$Vem^=UB5(xjD{SmmfYzs;DUd=nS-g!Qk74=Dqj%9=K=SHDPI zrI2ulgLk_o?r&-~BB6NiFLO0Y0zpK7!WR9mC9O$Gnu0HzMv6^`b#mLRjeTB}MrSEY zX=O#jfaH>DDve9$fNeLjsDM+MrKXU@3eoSaSmfROa$j82wftFecQ!4@q~dPM$BzyA z@ZGG%izb}a6KCG;f@f_CCI4ca{jglSoMMErgcI(+oVOX0E@0*j;)QMBoql5}uWDO= z&mAkIa#+T5@C83tSH_{NR@%9#M2geS?=47R5b=0 zOB+_@f>xw6GGFM1OKWj@u9PjJ+WEwZz2GHuqBFQ7y5z7yhYQ1oOG9C34cZW{!It0H z^K3bh4q_!V(l{%;1Zhg5WOIJT0-;@>Hfo1PEvFy=#;hiYLphcKB)5-oU2_)P?<}k0 zb^mazzvADdeYfjww21MyW^T3Fupv6i%rw2&{>iz~NM5 z{&;(`G!Q=P!_#yW)twhC9LfU@AYV~{5hb?fiIp$fZv=$iKLe3Bod1@8xy!4a6K_LQ z985Pi%2+g6oO*h%T1hI^3lIpOdU{taPNOXeQuAtFs#Dfq_a?9Htut3`No_K@Z>3E{ zJN|89@dr}w+yQxVWUF)2>wBN4A*5zuyWcEbk>BN3ZwtkU?=tb#4L-CJ`7$=~G_x}N zrsMz^PqigH*5g&fu7ISfad>sei%F;&be|)o{Q3>WR%`7Xi^)8su{)wO_WUM)KVX3! zD_ex=(|9_IyTJCoh#$^c1WAlDe%W&B80Bxm3MO1MZ5}eD$v?;&do;+&!&qRgcx5MP zB%K=mW_bZMoo4T{B-Hxp+4r6-QRfcg*>h!VYRUdZmUAtxySRJdA70XYWu!_<-4@89s^AV+{LFB zqOU>ISgD-P-zHXGSLOI}e&jBqp8$QQy16MJgsa@4j-XWE8M2A-)%*HmS#?dfj%=z) z1?RpPM?^h_KQ2O5zD}(6c!*ocDSw}^_odE@I{pBKMe0ZE!(Vqhl*iVgC8o6X601d+ zroUAN9Sa90a^j9O@aNShOJ5-l!__sC^i0?b9WE4Mi8eg$b7$es!pcH*aStP^yiZz+ zu~}mSTDnT2UZJ^EhhqdXRfM2Nq+#I$O)^63x#~kG=?UYRc+ZR zma zAMb8Jup{7)$t>XS?iS$7l{{Zh+!^i|87h}scKM!>S5Q=P5Siyt!20Q9=S#x`U#Xe~ zO2wK+{O0oEp;;0$pQl1x@U;S7AZZK#@(Zh|9DRH_;Jy6Y;{&qVHVMMhb5#^{VIEVz zO$EHjzH#8?dn!AfN|-#{2&4} zXQp}a|C3#0|3kcj!*=f80p1GaYbOKub~ormTpiMptx5tK{@a=BS#-H1R~HZ^kQV4< zWC6z~fC;MToN2HI635M!61RNBPpZz0QJ(lktJUI$ZI{_};^J4@eE@3I<1%*fv`Xee zbA1s&F}bdW6*;N+;rsOTef4HDDPqd8mcmcufowTIdAs}h0J_cE8?Va4ceK!Gy*sM5&&et48hW&uYbnEY=Iy9u32J9~GI&n!!19T4 z1w|mbQmn}IH7=o60CJ8$HKG69S6F*^2)#}%owTwN8tqeN6kp;-pj6c(S898bM!&Lz zmu(NPYsBO(g*_ZC3}m}j*mV`Fqx6I`K>GF97unSg4|ePcA!#6q&RAKQGXp=`W*%8* z7wUjR+$d`2ym^LC*PEQSq2HY!D`;1Fkq?Arvz1<*lZho#Fx{N>Ix1t?Ho0fQVq0LI zwAl0n_XAELBY0-{iK=nMX8o)M%y(eO4>!Q&UNr^ePB&eg41W@rL^2tT;(})x3HVfe zQ@XQqRRhBDUK`P0COYV;3(f0t*;!jPO~0B|5lncA(7tPp5XdysRyCYw;~cUFILVHC ztbsb#Apz>L79|YucrfI||9NyKnZZL$%P593}R`!*Zu3Lz?VpXimxODmnU+jk8koVekfX^1h*O3B~hN zk-u=C9b~j0bL(?Qm+jQ5VwL>|2!0;+_8#A~>cC43J=0N=r{jF@SV|+cW3QF=|B5gv z@B1xxsfI_D8D$DM{*Aw`rC4Rm+nT>x+%S@f39kU;>e*vj}v)u&@g zdLGkbEBRf#1b1I~n?Zf5Mh0^p2Y<4i=G9cN6f?gZoi`^Z)m#!kGylFSdIR^Xco)n+ z2U~0}GI5OXXL;#^^_V;yOo-u=v6a>12#hzX9vfJ9t~`7a&w`Z2`0JB#gAoFLxLrj` z3dH_J=mGb=f;8x27l>Hg`VJ|4eO$-K-D?P5G28Y565E51r6DlbSU`(AFN0b^eFHD2 z=P5M;19%hjicTz&dUunH)BZrG~c74cf8ppRaSbGmg7gcpRWYKOxWE|HZ3ss z)$l-fY5aYh$x?~RT7u^v(~7fJY&a5r`-QDB;Gj)Oxf;bcXTb~{{U$2~4E=hYI3SRm zTkZ?bj~=ONdq_}K>1!w4;}EZu<1GG`S?6iy{!NiHmfi|fb%U#qyr*edcQF0PIi%L! z)YOI#Bfp8?7Wo|mM2#rtJ+q62jY(N5AzT|GJ4TLu?ReH}9&rYYHoQ`INj#iO7M6X# zqtkv|=W#^Z<^r6W1JJa?dvbm-ckt2to<1JjEw(=y67M?~ik?sN^E9{{E2$crRaZ%R z8fpNM8Z&U+acVW4LCqR1?QhnLq~=dK9z7)ITQ|Max{6+Zdf+`l0hIr|kIzYKYD)qCh5R900hoAkXrW$5a!|{k| zPq$lA71e{>b}g*cb+&|Uh2_p-+83j=IA>UA&E>iyo1s#r@5nC2EbG3GQB0t{@bT@w zj^TNPJGr87oMa!&>+YFIt^sdCb}nx9LfjWVzZoU3w^7QZ$3XAs7rUP$cRiMQW&h2X z!fRx$68BW)WHr+!)3VRc9DUC1cSwQK1_(1;dL>W(S7)dyKjF&39j zu4?N5jmyBDFXR->ku&dr_Y{eS5{GJrHhasnoK2?wbiZa<$49??II}^U9+mO^Ohc~R5B{7;Q zZ^UNIw#ovlls#fTBUHVR*WLfS7R7gN_#MlW82~rUN0|$9LmBSDcnJ!XJ4k;+`kVC? zTe2;DMGkf=%awZm{T+8)i>?(H3kU~px1WeALr=Q@0Z?ys70%SvNgigr%tgIA96 za>u!=7Jd;$KmM4eE7ON)X*+nLT5?bv3O5aP*1e~z*;U3M7N+}~9-N4bzg>fHH3LsX zv&1?#CB*Qkc1pVQO&$JqComSkwJu8(uLd|*PQ7b0nX-o6IdUtg#gofUGaJ8sQHW--96VlpI2^*qA&tVF(b zylPv$C$ku9R;LvsdC`|}m&zk5#H6Y9-FxFwPnp|35Rner#t~#nPN3^ixj_zZW$G@o@;WXT(^CU0=bhIUx zEMQUq5jn6QA8gMR*{#uL-HnGb%&t1EbGwPJRu^2(xXA5`vo;Lw9|sJPSkB1F;i5Vv zy*rk=vAv-Mhk)8RNiS2eA?4HdqP;-Gkom1a*nxtX6!sM~U9nYo%u~cg5ycx)Fwp*u z2gt_3z1`6CH9V!i;7pCIYw;ruHWx!6TJ8r6J3~9+ z+iqsibME1nSGZW{P>7g!@h=%}%|}eif~Iwv_v>)`GKVek_-yxUR?WO@he`9O)7%p(u2w3aU_yB)Uz6yQw7U>*#R7&xKV8#U z3!KRd=En5O?Y8xWUmkRPd(~w0S$_V_V1{BrmtG1XyIAU5$CAaD34$-%^&2zMs3Y@y zU^3$gF+u!)Y}(eWkm`nvb#(RE#V7(Dk9eyEb*>$bj)jvC=kw1`E?DiY4cU&+=Na$2 zZ4p4J#@GKedZ>@jt}CZ!zpZSosn2}`&AF|^C1NEp{!Acfv5h`^r}lfDhQG1TE4TfT z4#Rf?nF#Fz)lu1#y%-aS!Nuz=m5a}6mt?i%3ODe?`|7YdKmHEDh@yXoW~F~o8q@pe zCYKBFz249$Wz@3%6Xx2AiH*g?28Dl4GTR^F)OVxN6bkO-rGQa@3gKDdmkXQ2^XcOh ztlTUy%hR90^cL&j`Kmz$jM=4?P4~4-cFs=Tki3f^eflDT9S?9O@ijQ)PJ!#fMosZ8 z=>kdbU|;mxhYK$57w-DIV*&nv6=^zI-;ABlgFobklD?>op3Q^5PJ$5ij@mF>@KAl` zjr&JXhhH3c=;x-u?K9cXaLYvKCKK6BF|L~U(m$JYOOoh`dl$`1BkPr)0aUD<9wjRr zo{QP5Do7lua0dFO6O{9!X{URg+;4*xTR_Z5P^&pT;c`U=9!hn8Ak%0{Zl@3ZhcChe9*JMI=>gv45BBC z+&Msc@4{C;FAHGw&+90rzqURHiE{kxC`TPJB&L3A^YLMkN^x|Hg&Yb)YT9${^lRSi z(s5UvEs}1QD_P)mpX+IlXjEudP8~D_Lu)_p_c2Q*syVKW zVaPF8HU7h4PZwQL_eNQ&Y(vAheUv#!SG$MOibH-dfkSq0nI{I^I2Yrdwg1E1?;NsbZOI+Z1-Q>3;a4S;L1ycU>XneQcY^#@W z@l5Zha;p4jnEfQqSA-5Dyg%>gPtGQ8=6Z|{K&?CHJ3dw6u&><5xNo()k_rx+OIdNk zyCK4~IkyO)cyp0vE*9!;-N!z@?nVk<9}<-jQo#rkus_$;RW(0bqZ)WN2*RJFnX2jc!DVYj3esGUlR0rCde9&!iuK8gM3= zb7-PwXf!t|Psn##)5!<3!S2CG-cKwaq8hdD38ITdYMK8DtEpepiilf!Xc2kP46WW; z%ba4#27>E^#kO`!SO3Cr17S(;khpWHRQjw)B$BUJVqMZp13pG|Dg>$=oU)}4e|z0q zoZmA9l+(kBKhOM?hm5KY-UKO$=!`#|FAU^iI2iwu9ElO@cF_4cZ|bkIck#@b>rSUH zxB{pJwSsR#5&OKz^{n_6X-%3l*Twzy6od}n52^3M`YOaU9E~gQOIh*B8M%~fdw2%V z1KQX2LgNjZmW(KG?u$Ko?)o@Xd>#Nc4QaV zWC2G6KO9p0m(FYd_(WY2vqpOI!c<_gDwR7T{#B>ir`@^J(d1H%avfW6Wo&!%5&kzK z83yDr0JJPIAPVxNy;r+;POMkSr3Y@yU&RidJ4?97h>}jfWf<5Jf&JKF2!EIy&@2xH z86E`E{SEg&Q-1N}L;q$zesp@mJpI2v|NP%7z*mUy%C?<0W$pCl(BnkvV0-% zH{0{sQ@J~>yAFh+0SoH?R-MTG|Ha;zlv1@nj97#mu4Nt)J$;nTnzqRxf;w6`>gm>@ zg9+c59BFr7QKkio2J339%h3@D4_>>rSM}6nkL{qdP*yikCrPJ|f5sob9ODjl#@$Cm zk0Qt$x|AXHD#ls~PzUMmPHUKFfra(G3DfkUJKR0btOe0n8P{}v$)ftCZ8>U9)g`UsE zHA2K(-T1c9ka<{q(wnr^iGlm!vu>ym8S1sm&(@z6YLYjw68a$e5_1}FUxW49EMw1s zDwb_CaoKN&{aA9fubdO0V(8k&M3|%Ie6p^So2QG+B+Z{Uof5o#TV+d3VN(_Hh`sAQ?dH; z7QD6>Q%k06?+#55Q%xS~*Nj1pZ}+D{8E)`fyKTcr?P-sS&q_6Gt2(G%pO0~nzDU`; z4VGA0L<#k?iZ)$k7Agrog2_Dgumjq)u0k~(XOSJOD`-BQg|C|JB~+2au_0d0S-<

8SMeH*SjA8v+j%t2_^h;yoQsE)E>g`b{}PoqIha*jGtm}vG%m4CTqhRQm6 zJxYCl?0g^3;~pBl=^{WAavuh)JH|jv|73E3!^v-ZyK9*bWd3{~8rxT8FRH2|@@R$Z zLc=WJAgGGWk9PpDMpMRSoEeOe-rcWIA1r`S#_Ld_i%NiZCG#qFd4JH>S7aC72KG;& zc*&I~Koxg+!13bmrsE!}@ExpZGgJ=py6>2FEEc|X2`ugB>;B0jq7NP+y^e|d#fvex za3tBH>)V{k1BKrx@<+jQPlNS-s1F&$;fp#J_=-HH%5N>2XtTXhqqgSI-I-674GIP2 zeDp}mldsR?71?k}(#+zF4?SQTyX#i3Q9a2dy}U?p84?;kOf^Er zSftIn`Yf}q_a$<|yAg@Ap*}PIhj)cHIMu8u_&t70*cN%{EXRKTDdkfhf7EM)S`$(g z31*>sv=yN!GYP9mNzTrYJL#Su;lnC%;6R7fG-2jzP3BFIuItzh^y+eN@`!h{&$#f8 zw7n)hlvB8D-VyES(r(lFJJRSz(n5@bgsMmrhjPivU=p>hplF=yMni5nY4^wirr0z6 z-jYC=eWC5epu@jghv_?a($cFyJHnvW+cH3bkPKm=V>0(-N?crw7b^-IoRw2z$}$OC zB%eHZ=113YU=vpd=vo?^4vh@|^|;)+vfkbZ6F-mf(XS9-GBgheKn$?;B~d{KFR(u; zU2J{m2yY*~T&|2xj)~G45ze@H=7(?j`qC~k9xxvV*3Ww1i|4PqN!{Iyt6kZEzzTpvy|5^ueqJt3d}DfE?xksd1`j8IZktND@Ws*6<(p71 zmK&)cdC|l*M@cLhEWfVN$Urnq!PqTZ$==PrWJameEPy)Oh zl{wV1P{7is1*3f#KTWVwFO?kCGBy5+HtiB(=aF;cnhJI@OTgO~P|VI*wCJyN1J=@? zP@ajt8C3A*;T3!K%$Ou()sEr*BwWB}4Cb6KGd=_O2?!QlOzs=lVsPjceegjtjt8a)90);aPzLG8aBiOw zler)ju?|oc=Oeo-e2ovO+EJU@l!FDM3D6?B!q(_^Ca_>ulbR1@x{u}eMeQOVExp#F zRpTgXUJq>xr7)RD!`?gb4*;7`pQeAm;BQ`fk6t|Tx0b*1y{c72a=C2e=YXRkHop=F zZS=!KBg23_zvP0qk~p6_X)+J-7M~) zM{!ykyV+tg?`B`}yxtrZlI~mPXWRrEm+Q-l(hV@IBov;Qw1?XcL*6k$TW7KXo1Vp( z!3ai1*VH@74Y}(3{}qJhid5omNEL^ z`m7o;SzXlGucL3=KbER?Cw0fBihO3JNS84tdOaO?3O@KgS>w^EMAeUfq#Ii8wEGyA zGW@9sN%&;ChB4~ULS6rAj9Oj&^kZ(JV8Ut7Y;nbb=knKfHZp3am(cV%qS20!M*wuz z`R=yF^rO9Bp8k&86Ed?3^(`dCuNe71QJs z#|yHxu3IPA;PAWn>$vI>+&xY&FKC31@W8;AaFFjd716TdvQ~{L9H&eLOhSa3KKv(j zHaxR=01$0(wgtk-|)629g=h%2Dl)z6U6WTjk zW%aWRk_3d8;t0gx)%+Yso~Va1cjt$`Ga*QTy<22v2K9*m;NFIQ_l!`6#y9!7JfR6= zo-T1vE4Z~$pTr4nSznQsnHMU=%h4JHciIFv`*lzVI%JX(e7wIQTsd53v%Q)DqhzlY z>cwZ~!~Uktrw+6<@Xv=t*Uih^cwfr_`@`vrO8HXm>&&nh_2cU{;-dlf(N!u!y_TS!z>OO>@k1>HJwQ_0KPjKe$&_-3!y`x28v%e=fCvJ>ph_ zK*kFEB*&O2^r{#Lo}-dXq^YsW081);aHTYQu4G}));_x^^U!I~vpTae20as)-d?p~P zIIm4Q?Jsh8*V5Cl&KM16mt4(9i>AlD&hPrSuY)tr?;lskTaMlkd$=ZK|7pQeEFdrZ z9T!OLD4!o|C`^>nVSjFL$8+I70B=Ij6ofy32guE;8aB;^FW2bNZ#^vwA_J+~aL`+$ANjP9ul$ z9V*_Qr3?~TpTB&45D=G?JnO&#gdWUeQV;u=gm&dMOWS@+6!<4r_G-c85J^GIAMl=n zZb|QoNeQ3xcrg+hzR0{-T9m=IUjd{9S2|X6Ci_=(DOx)US{>8(R39Ivl-aBU8%yUs`CJnBn=J89et_|iGz#E1>wskOVpgAjTYFM@I9;Q;hQBSz;Xr2IC`>3d zrw3e$`ugBgAIZ8AMSPkGKNoqg+ZXk7)MYK<09J_*Y3gI8j!-!8A|N?cjdA*TG%D8g zZgz;Lt7$9tNH4vx7JpY&%`*mqcCmF*OnK|JmM2)+zmGk|3BZ7s z6dL==s#5onU2)vGi*hYp?R7Ig+Bh%s7P~c8aCF9lw>NLmxQlMt65W<70e4W}+Va!h zwB<#**LttO9c4uY(trbz(F%6nbOIK2Wq+Kcqm$h}YtqUMDEoxX6 z|8Ymv-=nGlb@jyGVgtA^%NRp4YC=Y{;(VLcVYacq|DX2GJRZt@kK@|7qQw=GCR*f@ zrB0TjF_lmzWEjR|EHPXUk!>bxi%K%cHW?aIG$)=hmJ!O@Df=>x$#5*`*al;?IT~id zc`UDc|Gxj<|DWgeyk5WU`+Ps|&-eSo-0I<9KBMRh37JI9G?^(z_+>}>`RlWKa7WIO zjboe$`Plt);iR*&5K+0W&23K`vg0tP;KW_wA;MQMQk7M(GidjD=ZwwB-FHBb9$#a? zK;B$VVQ;6_V=WI7jm`smI7xDiTL~7Fz+WR{9W`>UZDw%%3Z=D-1-#kZfkIpcYL8uM zw}{w%{FB@jFs`vuHcQ78#>`MNQ+MBdT|$x3ysz0Qs1&SP|SSjJ^t~SFEvwhum1d* zsJA@Six4rUfU`9z7|Fh&hDj7sVabBs_(yCnue$J4yybz*5k;tfCYujHn%fS=oax@B zXjT=%nI8ZlAQ;~fP9J7PP$Uh{lB?`jS9R;gswOR3<~bhW>loOxqkMVG4~d%@PqSq) zj9tgjg;U*d?*k0b;W;LMB0gy(xVWH3JAe!r_7kk#4T<{1%Yy?~T8| zJ*o_l>@Y5?^6QHit9$ztgI?nf?Ni4s$Pl1WM#HM|V#hKR09LMeizsBe@MH`b(5*Nb zGBjdaYubAaZfKR!QNusLzzHxPE-^TaJj1Ep!G#31@&T7F-ahiRXk9%0rSV{4Ll%zf zQFl}X;I zMvwd1)!jD8oKB2`!-1m*5<>T6&^d0vK2!$ElRQTy2sJKR29@UdPjt9Q2V3>(q^;0cEy8Lh{JNQi>-&A+EMKLV(U|(Fb48A7Q z$p~cGG4Dm?UF^z0{lTXlbQg>+3($W})p`k%U=Kt(FWt5=q*)XQKYN~L-&V0deVowiL%KF!%-&Be;-B3%=zz^5(Y z&|!0i5aV39K0q-*X$K|zIZ`NT;iGi)^R(|TjKpnaVh#9>8!O!`J_z8j4U;UxAPcre zm<}_{aiSOc#htk_-id;Z2=2u8oAYED;7o+Kr%yrBu*45oi;Q#omHF~xaob8XWj-od zT}bT76#liA%ILX%rd)M%%a%{3SM4nee7)cd+?`w~M%3fNUXNSMEDVT5)hS2q2K8;o zTHiar&iahniJK0!N_}hB?`2xnbl)e~l@ZXjDJRUha|KgUy-`Uk3u7U)eR&;qGIt?% zHlaCZIf_XXLJ@8tLRhp+gUX*`@BvH0HOA1LorCB7Mh@&sgCnS*T%pa74sb?6m*lwur#xyM z@}d^)pY6l;J3s%2D&A%4vI1@FpGMzyKslZYvz1y9r4E?+|CT)IUe$8&w@U|uu*=L@=&n#CP-4l5oatzV7Dwsx! z0HNP8##NQYI^MOM(=}Z=@s+N8{!QV;96H#lbg$BY*Do{W3qL>akZS>bvvSIBp`kg@ z1D8P;$7jwIB5D_X%;lT#{XqbKmJVK6e+cO zhH4x6@KrLA90qF~Xa7 zKod+PRpq#NIi(udS*^W&PUR zk`P)%^cujjtm}gsiG-Y2=(HVA4TP@lwx>!zfjG$7s@-UO;F;|xr86?S+VXU59OQg` zM@uh;)Z4dMmGS2yx?fgEtehEt6VAP`9w_ zDeO(+N&E}h)lM27WPYnHGuQHqL7F@*Jm5$!lGF9Avdu@h_?tB3YdrU(AKU%=ip5ZA zK5u2wiPi-6Lq^%#IOs;rI)6VhXelsnpEVfXt8dXCMaC|4w?ksrcF0rvl{d|lQJTZg zt-M!PLIx76yT%|D=MS0HO!o)AAYy7*|5TCcwd~ja>d0uhI?AZ7|GK)Rw%TRoI#lme zKb)sHI6AMy(|rCU5oeFcrk|jIg}J1P?%&ticS)$tuWkpRtmiCd7KQ{-U@|1jSquHw z)uJ_30m4jvn!#+9=m0b2#485tlt8T!dQZlg@0~(lSMUU=b)5FWk(NaLZb8%3eHp-M z+W5%C`ooTe?D}cq83(O$`mLKO8@;aFRsPSMR#D;qO5om!L@Qe=Z=' +# Your token from setting up Visibility +data_collector.token '<%= @auth_token %>' + +# If you want to change the default SSL certificate validation +#ssl_verify_mode :verify_none +#verify_api_cert false diff --git a/examples/visibility_win/test/integration/default/serverspec/default_spec.rb b/examples/visibility_win/test/integration/default/serverspec/default_spec.rb new file mode 100644 index 00000000..6e0b0df3 --- /dev/null +++ b/examples/visibility_win/test/integration/default/serverspec/default_spec.rb @@ -0,0 +1,2 @@ +# encoding: utf-8 +require 'spec_helper' diff --git a/examples/wrapper_audit/.kitchen.yml b/examples/wrapper_audit/.kitchen.yml new file mode 100644 index 00000000..80837df9 --- /dev/null +++ b/examples/wrapper_audit/.kitchen.yml @@ -0,0 +1,49 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_zero + +verifier: + name: inspec + sudo: true + +platforms: +# Your vagrant box name of a windows machines you have privately sourced +- name: windows2012r2 + driver: + # Your box or box_url should also be a privately hosted NFS, or URL, + # to publish your private Windows boxes + box: /vagrant/windows2012r2 + box_url: http://boxshare.yourdomain.com/vagrant/windows2012r2 + ostype: windows + shell_type: powershell + transport: + name: winrm + +# If you need to test a Linux-based profile, call a public box, such as this one. +- name: ubuntu-14.04 + driver: + box: bento/ubuntu-14.04 + +suites: + - name: windows + run_list: + # The run_list should be the wrapper cookbook. + - recipe[wrapper_audit::default] + attributes: + audit: + collector: 'chef-visibility' + server: <%= ENV['COMPLIANCE_API'] %> + token: <%= ENV['COMPLIANCE_ACCESSTOKEN'] %> + refresh_token: <%= ENV['COMPLIANCE_REFRESHTOKEN'] %> + insecure: true + # The owner should show up in the bottom-left of the home page of Compliance. + # If it is integrated with Chef Server, it will be the Chef Server org-name + owner: yourchef-orgname + profiles: + # Example default profile already in Compliance. + base/windows: true + # If you create and import a custom profile you wrote, you can also add it. + yourchef-orgname/customprofilename: true diff --git a/examples/wrapper_audit/Berksfile b/examples/wrapper_audit/Berksfile new file mode 100644 index 00000000..f5f96eab --- /dev/null +++ b/examples/wrapper_audit/Berksfile @@ -0,0 +1,4 @@ +# encoding: utf-8 +source 'https://supermarket.chef.io' + +metadata diff --git a/examples/wrapper_audit/README.md b/examples/wrapper_audit/README.md new file mode 100644 index 00000000..248e7a43 --- /dev/null +++ b/examples/wrapper_audit/README.md @@ -0,0 +1,26 @@ +# Example: Wrapper cookbook for `Audit` +This example cookbook demonstrates how you could wrap the audit cookbook with a customizable internal cookbook. This might be done to easily change default attributes set in the audit cookbook. The wrapper also helps you control the versioning of the audit cookbook in your environment. It can also be useful to help create roles to target where the audit cookbook applies, or even set attributes on nodes to apply Compliance profiles (if you had some you want to run on all machines). + +## Requirements + +### Platforms +- Windows Server 2008 R2 +- Windows Server 2012 +- Windows Server 2012 R2 +- Ubuntu 12.04 +- Ubuntu 14.04 + +### Chef +- Chef 12+ + +### Cookbooks +- `audit` +- `visibility_win` + +## Attributes +There are no custom attributes for this cookbook. + +## Usage +Include `wrapper_audit::default` in a node's `run_list`. This will also pull down the community audit cookbook, which is used to run Chef Compliance profiles. These profiles will create a report and send it to Chef Compliance or Visibility, depending on your [`audit`][`collector`] setting. + +This cookbook also consumes the example cookbook `visibility_win`, which demonstrates how to setup chef-client to ingest Visibility data. diff --git a/examples/wrapper_audit/metadata.rb b/examples/wrapper_audit/metadata.rb new file mode 100644 index 00000000..99e973e2 --- /dev/null +++ b/examples/wrapper_audit/metadata.rb @@ -0,0 +1,15 @@ +# encoding: utf-8 +name 'wrapper_audit' +maintainer 'Your Organization' +maintainer_email 'yourorganizationemail@domain.com' +license 'Proprietary - All Rights Reserved' +description 'Wrapper cookbook that runs Audit cookbook.' +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version '0.1.0' + +# Put whatever operating systems your company supports where you may want +# to use Compliance profiles +supports 'windows' + +depends 'audit', '>= 0.14.1' +depends 'visibility_win', '>=0.1.8' diff --git a/examples/wrapper_audit/recipes/default.rb b/examples/wrapper_audit/recipes/default.rb new file mode 100644 index 00000000..54e62f51 --- /dev/null +++ b/examples/wrapper_audit/recipes/default.rb @@ -0,0 +1,15 @@ +# encoding: utf-8 +# +# Cookbook Name:: wrapper_audit +# Recipe:: default + +# This includes statement is to include the chef_client_config recipe in the +# visibility_win cookbook, which is another sample cookbook under the +# examples directory. The visibility_win cookbook provides an example of +# how you would setup chef-client to send converge data to your +# Chef Visibility server. +include_recipe 'visibility_win::chef_client_config' +# Set the collector to chef-visibility instead of the default chef-server. +node.default['audit']['collector'] = 'chef-visibility' +# Execute the community audit cookbook with the collector set +include_recipe 'audit::default' diff --git a/examples/wrapper_audit/spec/spec_helper.rb b/examples/wrapper_audit/spec/spec_helper.rb new file mode 100644 index 00000000..a1e2776c --- /dev/null +++ b/examples/wrapper_audit/spec/spec_helper.rb @@ -0,0 +1,4 @@ +# encoding: utf-8 +require 'chefspec' +require 'chefspec/berkshelf' +ChefSpec::Coverage.start! diff --git a/examples/wrapper_audit/spec/unit/recipes/default_spec.rb b/examples/wrapper_audit/spec/unit/recipes/default_spec.rb new file mode 100644 index 00000000..38c8633a --- /dev/null +++ b/examples/wrapper_audit/spec/unit/recipes/default_spec.rb @@ -0,0 +1,10 @@ +# encoding: utf-8 +# +# Cookbook Name:: wrapper_audit +# Spec:: default + +require 'spec_helper' + +describe 'wrapper_audit::default' do + let(:chef_run) { ChefSpec::SoloRunner.new.converge(described_recipe) } +end From 2ed2b59b0cd22de17e2328524ee39f7ab5831622 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Wed, 19 Oct 2016 14:25:21 +0200 Subject: [PATCH 8/8] readd version attribute for inspec gem Signed-off-by: Christoph Hartmann --- attributes/default.rb | 12 +++++++----- files/default/audit_report.rb | 24 +++++++++++++++++++++++- libraries/collector_classes.rb | 2 +- metadata.rb | 2 +- recipes/default.rb | 16 +++++++--------- resources/inspec.rb | 4 ++-- resources/report.rb | 16 ---------------- spec/data/mock.rb | 15 ++++++--------- spec/unit/libraries/default_spec.rb | 6 +++--- 9 files changed, 50 insertions(+), 47 deletions(-) delete mode 100644 resources/report.rb diff --git a/attributes/default.rb b/attributes/default.rb index 36e26859..7ae0af25 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -14,7 +14,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# + +# inspec gem version to install(e.g. '1.1.0') +default['audit']['inspec_version'] = '1.2.0' # collector possible values: chef-server, chef-compliance, chef-visibility # chef-visibility requires inspec version 0.27.1 or above @@ -43,9 +45,6 @@ # fail converge if downloaded profile is not present default['audit']['fail_if_not_present'] = false -# fail converge after posting report if any audits have failed -default['audit']['fail_if_any_audits_failed'] = false - # by default run audit every time default['audit']['interval']['enabled'] = false @@ -65,5 +64,8 @@ default['audit']['profiles'] = [] # output for inspec results -result_path = File.expand_path('../../inspec_results.txt', __FILE__) +result_path = File.expand_path('../../inspec_results.json', __FILE__) default['audit']['output'] = result_path + +# inspec gem version to install(e.g. '1.1.0') +default['audit']['inspec_version'] = '1.2.0' diff --git a/files/default/audit_report.rb b/files/default/audit_report.rb index 2146241e..3a05222e 100644 --- a/files/default/audit_report.rb +++ b/files/default/audit_report.rb @@ -1,4 +1,5 @@ require 'chef/handler' +include ReportHelpers class Chef class Handler @@ -7,6 +8,7 @@ class AuditReport < ::Chef::Handler def report load_needed_dependencies call + send_report end def load_needed_dependencies @@ -23,9 +25,20 @@ def load_needed_dependencies require 'bundles/inspec-compliance/target' end + def set_json_format + reporter = node['audit']['collector'] + if reporter == 'chef-visibility' + format = 'json' + else + format = 'json-min' + end + format + end + def call Chef::Log.debug 'Initialize InSpec' - opts = { 'format' => node['audit']['format'], 'output' => node['audit']['output'] } + format = set_json_format + opts = { 'format' => format, 'output' => node['audit']['output'] } runner = ::Inspec::Runner.new(opts) tests = node['audit']['profiles'] @@ -34,6 +47,15 @@ def call Chef::Log.debug 'Running tests from: #{tests.inspect}' runner.run end + + def send_report + reporter = node['audit']['collector'] + Chef::Log.debug 'Reporting to #{reporter}' + + if reporter == 'chef-visibility' + Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report + end + end end end end diff --git a/libraries/collector_classes.rb b/libraries/collector_classes.rb index 47691e0c..7433b4ef 100644 --- a/libraries/collector_classes.rb +++ b/libraries/collector_classes.rb @@ -25,7 +25,7 @@ def send_report end # get file contents where inspec results were saved - result_path = File.expand_path('../../inspec_results.txt', __FILE__) + result_path = File.expand_path('../../inspec_results.json', __FILE__) file = File.open(result_path, 'rb') content = file.read file.close diff --git a/metadata.rb b/metadata.rb index ef380344..acaef5a2 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 '1.1.0' +version '2.0.0' source_url 'https://github.com/chef-cookbooks/audit' issues_url 'https://github.com/chef-cookbooks/audit/issues' diff --git a/recipes/default.rb b/recipes/default.rb index 8247c900..4b42a7b1 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -1,7 +1,13 @@ include_recipe 'chef_handler' -handler_directory = ::File.join(Chef::Config[:file_cache_path], 'handler') +# install inspec if require +inspec 'inspec' do + version node['audit']['inspec_version'] + action :install +end +# run chef handler +handler_directory = ::File.join(Chef::Config[:file_cache_path], 'handler') directory handler_directory do action :create end @@ -14,11 +20,3 @@ source "#{handler_directory}/audit_report.rb" action :enable end - -chef_inspec 'inspec' do - action :install -end - -inspec_report 'report' do - action :execute -end diff --git a/resources/inspec.rb b/resources/inspec.rb index d23d56c4..a11082b2 100644 --- a/resources/inspec.rb +++ b/resources/inspec.rb @@ -1,7 +1,7 @@ # encoding: utf-8 -provides :chef_inspec -resource_name :chef_inspec +provides :inspec +resource_name :inspec property :version, String, default: 'latest' diff --git a/resources/report.rb b/resources/report.rb deleted file mode 100644 index 4eb27a6e..00000000 --- a/resources/report.rb +++ /dev/null @@ -1,16 +0,0 @@ -# encoding: utf-8 - -include ReportHelpers -provides :inspec_report -resource_name :inspec_report - -property :collector, String, default: 'chef-visibility' - -default_action :execute - -action :execute do - case collector - when 'chef-visibility' - Collector::ChefVisibility.new(entity_uuid, run_id, run_context.node.name).send_report - end -end diff --git a/spec/data/mock.rb b/spec/data/mock.rb index 0f2d8f2e..cb5ee5df 100644 --- a/spec/data/mock.rb +++ b/spec/data/mock.rb @@ -1,12 +1,9 @@ class MockData - def self.chef_client_report - { :node=>"chef-client.solo", - :os=>{ - :release=>"10.11.5", - :family=>"mac_os_x" - }, - :environment=>"dev_blog", - :reports=>{"tmp_compliance_profile"=>{"version"=>"1.0.0-beta1", "profiles"=>[{"name"=>"tmp_compliance_profile", "title"=>"/tmp Compliance Profile", "summary"=>"An Example Compliance Profile", "version"=>"0.1.1", "maintainer"=>"Nathen Harvey ", "license"=>"Apache 2.0 License", "copyright"=>"Nathen Harvey ", "supports"=>[], "controls"=>[{"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.003508, "start_time"=>"2016-09-21 20:48:09 -0400"}]}, {"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"}, "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", "results"=>[{"status"=>"passed", "code_desc"=>"File /tmp should be owned by \"root\"", "run_time"=>0.010822, "start_time"=>"2016-09-21 20:48:09 -0400"}]}], "groups"=>[{"title"=>"/tmp Compliance Profile", "controls"=>["tmp-1.0", "tmp-1.1"], "id"=>"controls/tmp.rb"}], "attributes"=>[]}], "other_checks"=>[], "statistics"=>{"duration"=>0.015729}}}, - :profiles=>{"mylinux-success-failure"=>"alex", "tmp_compliance_profile"=>"nathen"}} + def self.node_info + "chef-client.solo" + end + + def self.inspec_results + "{\"version\":\"1.2.1\",\"profiles\":[{\"name\":\"tmp_compliance_profile\",\"title\":\"/tmp Compliance Profile\",\"summary\":\"An Example Compliance Profile\",\"version\":\"0.1.1\",\"maintainer\":\"Nathen Harvey \",\"license\":\"Apache 2.0 License\",\"copyright\":\"Nathen Harvey \",\"supports\":[],\"controls\":[{\"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\"}]},{\"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\":null,\"development\":null,\"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\",\"results\":[{\"status\":\"passed\",\"code_desc\":\"File /tmp should be owned by \\\"root\\\"\",\"run_time\":0.028845,\"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\":[]}],\"other_checks\":[],\"statistics\":{\"duration\":0.032332}}" end end diff --git a/spec/unit/libraries/default_spec.rb b/spec/unit/libraries/default_spec.rb index f5e8a70c..7bae6588 100644 --- a/spec/unit/libraries/default_spec.rb +++ b/spec/unit/libraries/default_spec.rb @@ -25,8 +25,8 @@ before :each do entity_uuid = 'aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz' run_id = '3f0536f7-3361-4bca-ae53-b45118dceb5d' - @enriched_report_expected = "{\"profiles\":[{\"name\":\"tmp_compliance_profile\",\"title\":\"/tmp Compliance Profile\",\"summary\":\"An Example Compliance Profile\",\"version\":\"0.1.1\",\"maintainer\":\"Nathen Harvey \",\"license\":\"Apache 2.0 License\",\"copyright\":\"Nathen Harvey \",\"supports\":[],\"controls\":[{\"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.003508,\"start_time\":\"2016-09-21 20:48:09 -0400\"}]},{\"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\":null,\"development\":null,\"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\",\"results\":[{\"status\":\"passed\",\"code_desc\":\"File /tmp should be owned by \\\"root\\\"\",\"run_time\":0.010822,\"start_time\":\"2016-09-21 20:48:09 -0400\"}]}],\"groups\":[{\"title\":\"/tmp Compliance Profile\",\"controls\":[\"tmp-1.0\",\"tmp-1.1\"],\"id\":\"controls/tmp.rb\"}],\"attributes\":[]}],\"event_type\":\"inspec\",\"event_action\":\"exec\",\"compliance_summary\":{\"total\":2,\"passed\":{\"total\":2},\"skipped\":{\"total\":0},\"failed\":{\"total\":0,\"minor\":0,\"major\":0,\"critical\":0},\"status\":\"passed\",\"node_name\":\"chef-client.solo\",\"end_time\":\"2016-07-19T19:19:19+01:00\",\"duration\":0.015729,\"inspec_version\":\"1.0.0-beta1\"},\"entity_uuid\":\"aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz\",\"run_id\":\"3f0536f7-3361-4bca-ae53-b45118dceb5d\"}" - @viz = Collector::ChefVisibility.new(entity_uuid, run_id, MockData.chef_client_report) + @enriched_report_expected = "{\"profiles\":[{\"name\":\"tmp_compliance_profile\",\"title\":\"/tmp Compliance Profile\",\"summary\":\"An Example Compliance Profile\",\"version\":\"0.1.1\",\"maintainer\":\"Nathen Harvey \",\"license\":\"Apache 2.0 License\",\"copyright\":\"Nathen Harvey \",\"supports\":[],\"controls\":[{\"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\"}]},{\"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\":null,\"development\":null,\"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\",\"results\":[{\"status\":\"passed\",\"code_desc\":\"File /tmp should be owned by \\\"root\\\"\",\"run_time\":0.028845,\"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\":[]}],\"event_type\":\"inspec\",\"event_action\":\"exec\",\"compliance_summary\":{\"total\":2,\"passed\":{\"total\":2},\"skipped\":{\"total\":0},\"failed\":{\"total\":0,\"minor\":0,\"major\":0,\"critical\":0},\"status\":\"passed\",\"node_name\":\"chef-client.solo\",\"end_time\":\"2016-07-19T19:19:19+01:00\",\"duration\":0.032332,\"inspec_version\":\"1.2.1\"},\"entity_uuid\":\"aaaaaaaa-709a-475d-bef5-zzzzzzzzzzzz\",\"run_id\":\"3f0536f7-3361-4bca-ae53-b45118dceb5d\"}" + @viz = Collector::ChefVisibility.new(entity_uuid, run_id, MockData.node_info) end it 'returns the correct control status' do @@ -83,7 +83,7 @@ it 'enriches report correctly with the most test coverage' do allow(DateTime).to receive(:now).and_return(DateTime.parse('2016-07-19T19:19:19+01:00')) - expect(@viz.enriched_report).to eq(@enriched_report_expected) + expect(@viz.enriched_report(JSON.parse(MockData.inspec_results))).to eq(@enriched_report_expected) end it 'is not sending report when entity_uuid is missing' do