From 22b2130a53f8a01887fde9e482970e15cdd9cedb Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Tue, 23 Aug 2016 23:44:45 +0200 Subject: [PATCH 1/3] extract refresh token handling, ensure we exchange it only once --- Rakefile | 1 + libraries/compliance.rb | 11 + libraries/helper.rb | 8 +- libraries/inspec.rb | 38 ++++ libraries/profile.rb | 322 ++++++++++++++---------------- libraries/report.rb | 192 +++++++++--------- recipes/_inspec.rb | 26 +++ recipes/default.rb | 38 ++-- spec/unit/recipes/default_spec.rb | 5 +- 9 files changed, 349 insertions(+), 292 deletions(-) create mode 100644 libraries/compliance.rb create mode 100644 libraries/inspec.rb create mode 100644 recipes/_inspec.rb diff --git a/Rakefile b/Rakefile index 7dde208c..f33119db 100644 --- a/Rakefile +++ b/Rakefile @@ -29,6 +29,7 @@ end desc 'Run all style checks' task style: ['style:chef', 'style:ruby'] +task lint: ['style'] # ChefSpec begin diff --git a/libraries/compliance.rb b/libraries/compliance.rb new file mode 100644 index 00000000..d16ae050 --- /dev/null +++ b/libraries/compliance.rb @@ -0,0 +1,11 @@ +# 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' + _success, _msg, access_token = Compliance::API.post_refresh_token(server_url, refresh_token, insecure) + # TODO: we return always the access token, without proper error handling + access_token +end diff --git a/libraries/helper.rb b/libraries/helper.rb index 43ae3244..5b9b3635 100644 --- a/libraries/helper.rb +++ b/libraries/helper.rb @@ -45,17 +45,11 @@ def with_http_rescue(&block) end return response rescue Net::HTTPServerException => e + Chef::Log.error e handle_http_error_code(e.response.code) end end - # exchanges a refresh token into an access token - def retrieve_access_token(server_url, refresh_token, insecure) - _success, _msg, access_token = Compliance::API.post_refresh_token(server_url, refresh_token, insecure) - # TODO we return always the access token, without proper error handling - return access_token - end - # Returns the uuid for the current converge def run_id return unless run_context && diff --git a/libraries/inspec.rb b/libraries/inspec.rb new file mode 100644 index 00000000..63184c5b --- /dev/null +++ b/libraries/inspec.rb @@ -0,0 +1,38 @@ +# encoding: utf-8 +class Audit + class Resource + class ChefInspec < Chef::Resource + resource_name :inspec + + property :version, String, default: 'latest' + + default_action :install + + # installs inspec if required + action :install do + converge_by 'install/update inspec' do + chef_gem 'inspec' do + version new_resource.version if new_resource.version != 'latest' + compile_time true + action :install + end + end + + converge_by 'verifies the inspec version' do + verify_inspec_version version + end + end + + def verify_inspec_version(inspec_version) + require 'inspec' + # check we have the right inspec version + if Inspec::VERSION != inspec_version && inspec_version !='latest' + Chef::Log.warn "Wrong version of inspec (#{Inspec::VERSION}), please "\ + 'remove old versions (/opt/chef/embedded/bin/gem uninstall inspec).' + else + Chef::Log.warn "Using inspec version: (#{Inspec::VERSION})" + end + end + end + end +end diff --git a/libraries/profile.rb b/libraries/profile.rb index a50016ba..3df497c3 100644 --- a/libraries/profile.rb +++ b/libraries/profile.rb @@ -6,200 +6,176 @@ # `compliance_profile` custom resource to collect and run Chef Compliance # profiles -class ComplianceProfile < Chef::Resource - include ComplianceHelpers - use_automatic_resource_name - - 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 :token, [String, nil] - property :refresh_token, [String, nil] - property :insecure, [TrueClass, FalseClass], default: false - property :inspec_version, String, default: 'latest' - property :formatter, ['json', 'json-min'], default: 'json-min' - property :quiet, [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 'install/update inspec' do - chef_gem 'inspec' do - version inspec_version if inspec_version != 'latest' - compile_time true - action :install - end - - require 'inspec' - # load the supermarket plugin - require 'bundles/inspec-supermarket/api' - require 'bundles/inspec-supermarket/target' +class Audit + class Resource + class ComplianceProfile < Chef::Resource + include ComplianceHelpers + use_automatic_resource_name + + 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 :token, [String, nil] + property :insecure, [TrueClass, FalseClass], default: false + property :formatter, ['json', 'json-min'], default: 'json-min' + property :quiet, [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 - # load the compliance api plugin - require 'bundles/inspec-compliance/api' - require 'bundles/inspec-compliance/http' + converge_by 'create cache directory' do + directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) + end - check_inspec - 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 + access_token = token + + if 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, 'wb+') + tf.binmode + + 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 #{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 - converge_by 'create cache directory' do - directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) - 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 - converge_by 'fetch compliance profile' do - return if path # will be fetched from other source during execute phase + end + end - o, p = normalize_owner_profile - Chef::Log.info "Fetch compliance profile #{o}/#{p}" + 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 - path = tar_path + converge_by 'create/verify cache directory' do + directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create) + end - # retrieve access token if a refresh token is set - access_token = token - access_token = retrieve_access_token(server, refresh_token, insecure) unless refresh_token.nil? + converge_by 'execute compliance profile' do + path ||= tar_path + report_file = report_path - if access_token # go direct - reqpath ="owners/#{o}/compliance/#{p}/tar" - url = construct_url(server, reqpath) - Chef::Log.info "Load profile from: #{url}" + 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 - tf = Tempfile.new('foo', Dir.tmpdir, 'wb+') - tf.binmode + 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 - 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 #{access_token}") + file report_file do + content runner.report.to_json + sensitive true + backup false 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 'install/update inspec' do - chef_gem 'inspec' do - version inspec_version if inspec_version != 'latest' - compile_time true + def normalize_owner_profile + if profile.include?('/') + profile.split('/').last(2) + else + [owner || 'base', profile] + end end - require 'inspec' - check_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 + 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 - 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 - log "INSPEC #{e}" + 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 - file report_file do - content runner.report.to_json - sensitive true - backup false + def org + Chef::Config[:chef_server_url].split('/').last end end end - - def check_inspec - if Inspec::VERSION != inspec_version && inspec_version !='latest' - Chef::Log.warn "Wrong version of inspec (#{Inspec::VERSION}), please "\ - 'remove old versions (/opt/chef/embedded/bin/gem uninstall inspec).' - else - Chef::Log.warn "Using inspec version: (#{Inspec::VERSION})" - 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 end diff --git a/libraries/report.rb b/libraries/report.rb index d0e013a8..721fe666 100644 --- a/libraries/report.rb +++ b/libraries/report.rb @@ -1,108 +1,110 @@ # encoding: utf-8 # `compliance_report` custom resource to run Chef Compliance profiles and # send reports to Chef Compliance -class ComplianceReport < Chef::Resource - include ComplianceHelpers - use_automatic_resource_name - - 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 :token, [String, nil] - property :refresh_token, [String, nil] - 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 - total_failed = 0 - blob[:reports].each do |k, _| - Chef::Log.info "Summary for #{k} #{blob[:reports][k]['summary'].to_json}" if quiet - total_failed += blob[:reports][k]['summary']['failure_count'].to_i - end - blob[:profiles] = ownermap - - # resolve owner - o = return_or_guess_owner - - # retrieve access token if a refresh token is set - access_token = token - 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' - access_token = retrieve_access_token(server, refresh_token, insecure) unless refresh_token.nil? - if access_token && server - url = construct_url(server, ::File.join('/owners', o, 'inspec')) - Collector::ChefCompliance.new(url, blob, 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..." +class Audit + class Resource + class ComplianceReport < Chef::Resource + include ComplianceHelpers + use_automatic_resource_name + + 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 :token, [String, nil] + 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 + total_failed = 0 + blob[:reports].each do |k, _| + Chef::Log.info "Summary for #{k} #{blob[:reports][k]['summary'].to_json}" if quiet + total_failed += blob[:reports][k]['summary']['failure_count'].to_i + end + blob[:profiles] = ownermap + + # resolve owner + o = return_or_guess_owner + + # retrieve access token if a refresh token is set + access_token = token + 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' + if access_token && server + url = construct_url(server, ::File.join('/owners', o, 'inspec')) + Collector::ChefCompliance.new(url, blob, 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 - 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?(ComplianceProfile) - end.flatten - end + # filters resource collection + def profiles + run_context.resource_collection.select do |r| + r.is_a?(ComplianceProfile) + end.flatten + end - def compound_report(*profiles) - report = {} - ownermap = {} + 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 + 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 + [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 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 + def return_or_guess_owner + owner || Chef::Config[:chef_server_url].split('/').last + end + end end end diff --git a/recipes/_inspec.rb b/recipes/_inspec.rb new file mode 100644 index 00000000..54706f2f --- /dev/null +++ b/recipes/_inspec.rb @@ -0,0 +1,26 @@ +# 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 730378f6..8c5ff40d 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,29 +17,44 @@ # See the License for the specific language governing permissions and # limitations under the License. +# ensure inspec is available +include_recipe 'audit::_inspec' + +# 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'] -token = node['audit']['token'] -# Alternatively, specify a refresh_token and it will be used to retrieve an access token -refresh_token = node['audit']['refresh_token'] +ruby_block 'exchange_refresh_token' do + block do + # Alternatively, specify a refresh_token and it will be used to retrieve an access token + refresh_token = node['audit']['refresh_token'] + if report_collector == 'chef-compliance' && !refresh_token.nil? + token = retrieve_access_token(server, refresh_token, node['audit']['insecure']) + node.override['audit']['token'] = token + end + end + action :run +end + +# 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 -# set the inspec report format based on collector -formatter = report_collector == 'chef-visibility' ? 'json' : 'json-min' - +# ensure profile cache directory is available compliance_cache_directory = ::File.join(Chef::Config[:file_cache_path], 'compliance') directory compliance_cache_directory do action :create end -# iterate over all selected profiles +# iterate over all selected profiles and download them node['audit']['profiles'].each do |owner_profile, value| case value when Hash @@ -62,11 +77,9 @@ owner o formatter formatter server server - token token - refresh_token refresh_token + token lazy { node['audit']['token'] } insecure node['audit']['insecure'] unless node['audit']['insecure'].nil? path path unless path.nil? - inspec_version node['audit']['inspec_version'] quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? only_if { profile_overdue_to_run?(p, interval_seconds) } action [:fetch, :execute] @@ -75,12 +88,11 @@ end # report the results -compliance_report 'chef-server' do +compliance_report report_collector do owner node['audit']['owner'] server server collector report_collector - token token - refresh_token refresh_token + token lazy { node['audit']['token'] } insecure node['audit']['insecure'] unless node['audit']['insecure'].nil? quiet node['audit']['quiet'] unless node['audit']['quiet'].nil? action :execute diff --git a/spec/unit/recipes/default_spec.rb b/spec/unit/recipes/default_spec.rb index 961625d0..0689524d 100644 --- a/spec/unit/recipes/default_spec.rb +++ b/spec/unit/recipes/default_spec.rb @@ -34,6 +34,7 @@ context 'When server and refresh_token are specified' do let(:chef_run) do ChefSpec::ServerRunner.new do |node| + node.set['audit']['collector'] = 'chef-compliance' node.set['audit']['profiles'] = { 'admin/myprofile' => true } node.set['audit']['server'] = 'https://my.compliance.test/api' node.set['audit']['refresh_token'] = 'abcdefg' @@ -44,12 +45,10 @@ it 'fetches and executes compliance_profile[myprofile]' do expect(chef_run).to fetch_compliance_profile('myprofile').with( server: 'https://my.compliance.test/api', - refresh_token: 'abcdefg', insecure: true, ) expect(chef_run).to execute_compliance_profile('myprofile').with( server: 'https://my.compliance.test/api', - refresh_token: 'abcdefg', insecure: true, ) end @@ -74,13 +73,11 @@ owner: 'admin', server: nil, token: nil, - inspec_version: 'latest', ) expect(chef_run).to execute_compliance_profile('myprofile').with( owner: 'admin', server: nil, token: nil, - inspec_version: 'latest', quiet: true, ) expect(chef_run).to execute_compliance_report('chef-server').with( From 52f9e09971f1e64f0b42859ccb57930ff24aa037 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Tue, 23 Aug 2016 23:45:01 +0200 Subject: [PATCH 2/3] output errors for examples --- examples/kitchen/.kitchen.linux.yml | 4 ++++ examples/kitchen/.kitchen.win.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/examples/kitchen/.kitchen.linux.yml b/examples/kitchen/.kitchen.linux.yml index 2a6c6a76..bf010077 100644 --- a/examples/kitchen/.kitchen.linux.yml +++ b/examples/kitchen/.kitchen.linux.yml @@ -27,6 +27,10 @@ suites: 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: diff --git a/examples/kitchen/.kitchen.win.yml b/examples/kitchen/.kitchen.win.yml index e51f7926..d0da1e5c 100644 --- a/examples/kitchen/.kitchen.win.yml +++ b/examples/kitchen/.kitchen.win.yml @@ -39,5 +39,9 @@ suites: 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 From b231d30bdf851b529f352e0f754d7ec97c15efc5 Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Wed, 24 Aug 2016 16:28:53 +0200 Subject: [PATCH 3/3] move berkshelf dependency to test group --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index c66b59fd..8d8b4fb0 100644 --- a/Gemfile +++ b/Gemfile @@ -9,12 +9,12 @@ end group :test do gem 'rake', '~> 10' + gem 'berkshelf', '~> 3.3.0' gem 'chefspec', '~> 4.3.0' gem 'coveralls', '~> 0.8.2', require: false end group :integration do - gem 'berkshelf', '~> 3.3.0' gem 'test-kitchen', '~> 1.6' gem 'kitchen-dokken' gem 'kitchen-inspec', '~> 0.9'