summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2019-03-12 16:14:40 -0700
committerGitHub <noreply@github.com>2019-03-12 16:14:40 -0700
commit14870e73b475853ad35d8f8344d13807b869a9cf (patch)
tree714ab0a8a5dc5883a31114aa85f531c1d1be4965
parentd7aa84a98f888d37affe054cc21bc7631502ec82 (diff)
parentdfab5dcee8e8bfa25bba7b87b5a4366347d53279 (diff)
downloadchef-14870e73b475853ad35d8f8344d13807b869a9cf.tar.gz
Merge pull request #7728 from chef/audit
Remove audit mode from chef-client
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock30
-rw-r--r--chef-config/lib/chef-config/config.rb8
-rw-r--r--chef.gemspec7
-rw-r--r--lib/chef/application/client.rb23
-rw-r--r--lib/chef/application/exit_code.rb10
-rw-r--r--lib/chef/application/solo.rb3
-rw-r--r--lib/chef/audit/audit_event_proxy.rb93
-rw-r--r--lib/chef/audit/audit_reporter.rb176
-rw-r--r--lib/chef/audit/control_group_data.rb145
-rw-r--r--lib/chef/audit/logger.rb36
-rw-r--r--lib/chef/audit/rspec_formatter.rb37
-rw-r--r--lib/chef/audit/runner.rb196
-rw-r--r--lib/chef/client.rb155
-rw-r--r--lib/chef/dsl/audit.rb51
-rw-r--r--lib/chef/dsl/recipe.rb2
-rw-r--r--lib/chef/event_dispatch/base.rb31
-rw-r--r--lib/chef/exceptions.rb21
-rw-r--r--lib/chef/formatters/doc.rb48
-rw-r--r--lib/chef/mixin/properties.rb5
-rw-r--r--lib/chef/run_context.rb8
-rw-r--r--spec/functional/audit/rspec_formatter_spec.rb54
-rw-r--r--spec/functional/audit/runner_spec.rb121
-rw-r--r--spec/integration/client/client_spec.rb39
-rw-r--r--spec/integration/client/exit_code_spec.rb27
-rw-r--r--spec/unit/application/client_spec.rb69
-rw-r--r--spec/unit/application/exit_code_spec.rb10
-rw-r--r--spec/unit/application/solo_spec.rb5
-rw-r--r--spec/unit/application_spec.rb4
-rw-r--r--spec/unit/audit/audit_event_proxy_spec.rb318
-rw-r--r--spec/unit/audit/audit_reporter_spec.rb435
-rw-r--r--spec/unit/audit/control_group_data_spec.rb482
-rw-r--r--spec/unit/audit/logger_spec.rb42
-rw-r--r--spec/unit/audit/rspec_formatter_spec.rb29
-rw-r--r--spec/unit/audit/runner_spec.rb144
-rw-r--r--spec/unit/client_spec.rb156
-rw-r--r--spec/unit/dsl/audit_spec.rb43
-rw-r--r--spec/unit/recipe_spec.rb5
-rw-r--r--spec/unit/run_context/child_run_context_spec.rb7
39 files changed, 35 insertions, 3044 deletions
diff --git a/Gemfile b/Gemfile
index a3e020b4c3..9a19a80d69 100644
--- a/Gemfile
+++ b/Gemfile
@@ -54,6 +54,10 @@ group(:development, :test) do
# if you bump the ruby version you should confirm we don't end up with
# two rake gems installed again
gem "rake", "<= 12.3.0"
+ gem "rspec-core", "~> 3.5"
+ gem "rspec-mocks", "~> 3.5"
+ gem "rspec-expectations", "~> 3.5"
+ gem "rspec_junit_formatter", "~> 0.2.0"
gem "simplecov"
gem "webmock"
diff --git a/Gemfile.lock b/Gemfile.lock
index 75e3499d2e..b98b7899b7 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -49,12 +49,6 @@ PATH
ohai (~> 15.0)
plist (~> 3.2)
proxifier (~> 1.0)
- rspec-core (~> 3.5)
- rspec-expectations (~> 3.5)
- rspec-mocks (~> 3.5)
- rspec_junit_formatter (~> 0.2.0)
- serverspec (~> 2.7)
- specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
chef (15.0.183-universal-mingw32)
@@ -80,12 +74,6 @@ PATH
ohai (~> 15.0)
plist (~> 3.2)
proxifier (~> 1.0)
- rspec-core (~> 3.5)
- rspec-expectations (~> 3.5)
- rspec-mocks (~> 3.5)
- rspec_junit_formatter (~> 0.2.0)
- serverspec (~> 2.7)
- specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
win32-api (~> 1.5.3)
@@ -217,8 +205,6 @@ GEM
necromancer (0.4.0)
net-http-persistent (2.9.4)
net-http-pipeline (1.0.1)
- net-scp (1.2.1)
- net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
net-ssh (4.2.0)
@@ -227,7 +213,6 @@ GEM
net-ssh-multi (1.2.1)
net-ssh (>= 2.6.5)
net-ssh-gateway (>= 1.2.0)
- net-telnet (0.1.1)
netrc (0.11.0)
octokit (4.13.0)
sawyer (~> 0.8.0, >= 0.5.3)
@@ -296,23 +281,12 @@ GEM
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
semverse (3.0.0)
- serverspec (2.41.3)
- multi_json
- rspec (~> 3.0)
- rspec-its
- specinfra (~> 2.72)
- sfl (2.3)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slop (3.6.0)
- specinfra (2.76.9)
- net-scp
- net-ssh (>= 2.7)
- net-telnet (= 0.1.1)
- sfl
sslshake (1.3.0)
strings (0.1.4)
strings-ansi (~> 0.1.0)
@@ -421,6 +395,10 @@ DEPENDENCIES
pry-stack_explorer
rake (<= 12.3.0)
rb-readline
+ rspec-core (~> 3.5)
+ rspec-expectations (~> 3.5)
+ rspec-mocks (~> 3.5)
+ rspec_junit_formatter (~> 0.2.0)
ruby-prof
ruby-shadow
simplecov
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index 29dadf54e0..0c257a49b5 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -482,14 +482,6 @@ module ChefConfig
default :ez, false
default :enable_reporting, true
default :enable_reporting_url_fatals, false
- # Possible values for :audit_mode
- # :enabled, :disabled, :audit_only,
- #
- # TODO: 11 Dec 2014: Currently audit-mode is an experimental feature
- # and is disabled by default. When users choose to enable audit-mode,
- # a warning is issued in application/client#reconfigure.
- # This can be removed when audit-mode is enabled by default.
- default :audit_mode, :disabled
# Chef only needs ohai to run the hostname plugin for the most basic
# functionality. If the rest of the ohai plugins are not needed (like in
diff --git a/chef.gemspec b/chef.gemspec
index 3e41b8e5ba..1f3c6e4291 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -38,13 +38,6 @@ Gem::Specification.new do |s|
s.add_dependency "plist", "~> 3.2"
s.add_dependency "iniparse", "~> 1.4"
s.add_dependency "addressable"
-
- # Audit mode requires these, so they are non-developmental dependencies now
- %w{rspec-core rspec-expectations rspec-mocks}.each { |gem| s.add_dependency gem, "~> 3.5" }
- s.add_dependency "rspec_junit_formatter", "~> 0.2.0"
- s.add_dependency "serverspec", "~> 2.7"
- s.add_dependency "specinfra", "~> 2.10"
-
s.add_dependency "syslog-logger", "~> 1.6"
s.add_dependency "uuidtools", "~> 2.1.5"
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index 0e5584ded3..cdeb376f96 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -272,11 +272,6 @@ class Chef::Application::Client < Chef::Application
boolean: true
end
- option :audit_mode,
- long: "--audit-mode MODE",
- description: "Enable audit-mode with `enabled`. Disable audit-mode with `disabled`. Skip converge and only perform audits with `audit-only`",
- proc: lambda { |mo| mo.tr("-", "_").to_sym }
-
option :minimal_ohai,
long: "--minimal-ohai",
description: "Only run the bare minimum ohai plugins chef needs to function",
@@ -374,13 +369,6 @@ class Chef::Application::Client < Chef::Application
config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
@chef_client_json = config_fetcher.fetch_json
end
-
- if mode = config[:audit_mode] || Chef::Config[:audit_mode]
- expected_modes = [:enabled, :disabled, :audit_only]
- unless expected_modes.include?(mode)
- Chef::Application.fatal!(unrecognized_audit_mode(mode))
- end
- end
end
def load_config_file
@@ -521,17 +509,6 @@ class Chef::Application::Client < Chef::Application
"\nEnable chef-client interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options."
end
- def audit_mode_settings_explanation
- "\n* To enable audit mode after converge, use command line option `--audit-mode enabled` or set `audit_mode :enabled` in your config file." +
- "\n* To disable audit mode, use command line option `--audit-mode disabled` or set `audit_mode :disabled` in your config file." +
- "\n* To only run audit mode, use command line option `--audit-mode audit-only` or set `audit_mode :audit_only` in your config file." +
- "\nAudit mode is disabled by default."
- end
-
- def unrecognized_audit_mode(mode)
- "Unrecognized setting #{mode} for audit mode." + audit_mode_settings_explanation
- end
-
def fetch_recipe_tarball(url, path)
Chef::Log.trace("Download recipes tarball from #{url} to #{path}")
if File.exist?(url)
diff --git a/lib/chef/application/exit_code.rb b/lib/chef/application/exit_code.rb
index c87592f06b..6c9618fcb4 100644
--- a/lib/chef/application/exit_code.rb
+++ b/lib/chef/application/exit_code.rb
@@ -34,7 +34,7 @@ class Chef
REBOOT_SCHEDULED: 35,
REBOOT_NEEDED: 37,
REBOOT_FAILED: 41,
- AUDIT_MODE_FAILURE: 42,
+ # 42 was used by audit mode and should not be reused
CLIENT_UPGRADED: 213,
}.freeze
@@ -78,8 +78,6 @@ class Chef
VALID_RFC_062_EXIT_CODES[:REBOOT_NEEDED]
elsif reboot_failed?(exception)
VALID_RFC_062_EXIT_CODES[:REBOOT_FAILED]
- elsif audit_failure?(exception)
- VALID_RFC_062_EXIT_CODES[:AUDIT_MODE_FAILURE]
elsif client_upgraded?(exception)
VALID_RFC_062_EXIT_CODES[:CLIENT_UPGRADED]
else
@@ -105,12 +103,6 @@ class Chef
end
end
- def audit_failure?(exception)
- resolve_exception_array(exception).any? do |e|
- e.is_a? Chef::Exceptions::AuditError
- end
- end
-
def client_upgraded?(exception)
resolve_exception_array(exception).any? do |e|
e.is_a? Chef::Exceptions::ClientUpgraded
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 763d52226a..148e7720a5 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -288,9 +288,6 @@ class Chef::Application::Solo < Chef::Application
config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
@chef_client_json = config_fetcher.fetch_json
end
-
- # Disable auditing for solo
- Chef::Config[:audit_mode] = :disabled
end
def setup_application
diff --git a/lib/chef/audit/audit_event_proxy.rb b/lib/chef/audit/audit_event_proxy.rb
deleted file mode 100644
index 1cb8545d28..0000000000
--- a/lib/chef/audit/audit_event_proxy.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-RSpec::Support.require_rspec_core "formatters/base_text_formatter"
-
-class Chef
- class Audit
- class AuditEventProxy < ::RSpec::Core::Formatters::BaseFormatter
- ::RSpec::Core::Formatters.register self, :stop, :example_group_started
-
- # TODO I don't like this, but I don't see another way to pass this in
- # see rspec files configuration.rb#L671 and formatters.rb#L129
- def self.events=(events)
- @@events = events
- end
-
- def events
- @@events
- end
-
- def example_group_started(notification)
- if notification.group.parent_groups.size == 1
- # top level `control_group` block
- desc = notification.group.description
- Chef::Log.trace("Entered `control_group` block named #{desc}")
- events.control_group_started(desc)
- end
- end
-
- def stop(notification)
- Chef::Log.info("Successfully executed all `control_group` blocks and contained examples")
- notification.examples.each do |example|
- control_group_name, control_data = build_control_from(example)
- e = example.exception
- if e
- events.control_example_failure(control_group_name, control_data, e)
- else
- events.control_example_success(control_group_name, control_data)
- end
- end
- end
-
- private
-
- def build_control_from(example)
- described_class = example.metadata[:described_class]
- if described_class
- resource_type = described_class.class.name.split(":")[-1]
- resource_name = described_class.name
- end
-
- # The following code builds up the context - the list of wrapping `describe` or `control` blocks
- describe_groups = []
- group = example.metadata[:example_group]
- # If the innermost block has a resource instead of a string, don't include it in context
- describe_groups.unshift(group[:description]) if described_class.nil?
- group = group[:parent_example_group]
- until group.nil?
- describe_groups.unshift(group[:description])
- group = group[:parent_example_group]
- end
-
- # We know all of our examples each live in a top-level `control_group` block - get this name now
- outermost_group_desc = describe_groups.shift
-
- [outermost_group_desc, {
- name: example.description,
- desc: example.full_description,
- resource_type: resource_type,
- resource_name: resource_name,
- context: describe_groups,
- line_number: example.metadata[:line_number],
- }]
- end
-
- end
- end
-end
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb
deleted file mode 100644
index 40f1f9ffd7..0000000000
--- a/lib/chef/audit/audit_reporter.rb
+++ /dev/null
@@ -1,176 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-#
-# Copyright:: Copyright 2014-2018, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "chef/event_dispatch/base"
-require "chef/audit/control_group_data"
-require "time"
-
-class Chef
- class Audit
- class AuditReporter < EventDispatch::Base
-
- attr_reader :rest_client, :audit_data, :ordered_control_groups, :run_status
- private :rest_client, :audit_data, :ordered_control_groups, :run_status
-
- PROTOCOL_VERSION = "0.1.1".freeze
-
- def initialize(rest_client)
- @rest_client = rest_client
- # Ruby 1.9.3 and above "enumerate their values in the order that the corresponding keys were inserted."
- @ordered_control_groups = Hash.new
- @audit_phase_error = nil
- end
-
- def run_context
- run_status.run_context
- end
-
- def audit_phase_start(run_status)
- Chef::Log.trace("Audit Reporter starting")
- @audit_data = AuditData.new(run_status.node.name, run_status.run_id)
- @run_status = run_status
- end
-
- def audit_phase_complete(audit_output)
- Chef::Log.trace("Audit Reporter completed successfully without errors.")
- ordered_control_groups.each_value do |control_group|
- audit_data.add_control_group(control_group)
- end
- end
-
- # If the audit phase failed, its because there was some kind of error in the framework
- # that runs tests - normal errors are interpreted as EXAMPLE failures and captured.
- # We still want to send available audit information to the server so we process the
- # known control groups.
- def audit_phase_failed(error, audit_output)
- # The stacktrace information has already been logged elsewhere
- @audit_phase_error = error
- Chef::Log.trace("Audit Reporter failed.")
- ordered_control_groups.each_value do |control_group|
- audit_data.add_control_group(control_group)
- end
- end
-
- def run_completed(node)
- post_auditing_data
- end
-
- def run_failed(error)
- # Audit phase errors are captured when audit_phase_failed gets called.
- # The error passed here isn't relevant to auditing, so we ignore it.
- post_auditing_data
- end
-
- def control_group_started(name)
- if ordered_control_groups.key?(name)
- raise Chef::Exceptions::AuditControlGroupDuplicate.new(name)
- end
- metadata = run_context.audits[name].metadata
- ordered_control_groups.store(name, ControlGroupData.new(name, metadata))
- end
-
- def control_example_success(control_group_name, example_data)
- control_group = ordered_control_groups[control_group_name]
- control_group.example_success(example_data)
- end
-
- def control_example_failure(control_group_name, example_data, error)
- control_group = ordered_control_groups[control_group_name]
- control_group.example_failure(example_data, error.message)
- end
-
- # If @audit_enabled is nil or true, we want to run audits
- def auditing_enabled?
- Chef::Config[:audit_mode] != :disabled
- end
-
- private
-
- def post_auditing_data
- unless auditing_enabled?
- Chef::Log.trace("Audit Reports are disabled. Skipping sending reports.")
- return
- end
-
- unless run_status
- Chef::Log.trace("Run failed before audit mode was initialized, not sending audit report to server")
- return
- end
-
- audit_data.start_time = iso8601ify(run_status.start_time)
- audit_data.end_time = iso8601ify(run_status.end_time)
-
- audit_history_url = "controls"
- Chef::Log.trace("Sending audit report (run-id: #{audit_data.run_id})")
- run_data = audit_data.to_h
-
- if @audit_phase_error
- error_info = "#{@audit_phase_error.class}: #{@audit_phase_error.message}"
- error_info << "\n#{@audit_phase_error.backtrace.join("\n")}" if @audit_phase_error.backtrace
- run_data[:error] = error_info
- end
-
- Chef::Log.trace "Audit Report:\n#{Chef::JSONCompat.to_json_pretty(run_data)}"
- begin
- rest_client.post(audit_history_url, run_data, headers)
- rescue StandardError => e
- if e.respond_to? :response
- # 404 error code is OK. This means the version of server we're running against doesn't support
- # audit reporting. Don't alarm failure in this case.
- if e.response.code == "404"
- Chef::Log.trace("Server doesn't support audit reporting. Skipping report.")
- return
- else
- # Save the audit report to local disk
- error_file = "failed-audit-data.json"
- Chef::FileCache.store(error_file, Chef::JSONCompat.to_json_pretty(run_data), 0640)
- if Chef::Config.chef_zero.enabled
- Chef::Log.trace("Saving audit report to #{Chef::FileCache.load(error_file, false)}")
- else
- Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}")
- end
- end
- else
- Chef::Log.error("Failed to post audit report to server (#{e})")
- end
-
- if Chef::Config[:enable_reporting_url_fatals]
- Chef::Log.error("Reporting fatals enabled. Aborting run.")
- raise
- end
- end
- end
-
- def headers(additional_headers = {})
- options = { "X-Ops-Audit-Report-Protocol-Version" => PROTOCOL_VERSION }
- options.merge(additional_headers)
- end
-
- def encode_gzip(data)
- "".tap do |out|
- Zlib::GzipWriter.wrap(StringIO.new(out)) { |gz| gz << data }
- end
- end
-
- def iso8601ify(time)
- time.utc.iso8601.to_s
- end
- end
- end
-end
diff --git a/lib/chef/audit/control_group_data.rb b/lib/chef/audit/control_group_data.rb
deleted file mode 100644
index 63f301da02..0000000000
--- a/lib/chef/audit/control_group_data.rb
+++ /dev/null
@@ -1,145 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-#
-# Copyright:: Copyright 2014-2018, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "securerandom"
-
-class Chef
- class Audit
- class AuditData
- attr_reader :node_name, :run_id, :control_groups
- attr_accessor :start_time, :end_time
-
- def initialize(node_name, run_id)
- @node_name = node_name
- @run_id = run_id
- @control_groups = []
- end
-
- def add_control_group(control_group)
- control_groups << control_group
- end
-
- def to_h
- {
- node_name: node_name,
- run_id: run_id,
- start_time: start_time,
- end_time: end_time,
- control_groups: control_groups.collect { |c| c.to_h },
- }
- end
-
- alias_method :to_hash, :to_h
- end
-
- class ControlGroupData
- attr_reader :name, :status, :number_succeeded, :number_failed, :controls, :metadata
-
- def initialize(name, metadata = {})
- @status = "success"
- @controls = []
- @number_succeeded = 0
- @number_failed = 0
- @name = name
- @metadata = metadata
- end
-
- def example_success(control_data)
- @number_succeeded += 1
- control = create_control(control_data)
- control.status = "success"
- controls << control
- control
- end
-
- def example_failure(control_data, details)
- @number_failed += 1
- @status = "failure"
- control = create_control(control_data)
- control.details = details if details
- control.status = "failure"
- controls << control
- control
- end
-
- def to_h
- # We sort it so the examples appear in the output in the same order
- # they appeared in the recipe
- controls.sort! { |x, y| x.line_number <=> y.line_number }
- h = {
- name: name,
- status: status,
- number_succeeded: number_succeeded,
- number_failed: number_failed,
- controls: controls.collect { |c| c.to_h },
- }
- # If there is a duplicate key, metadata will overwrite it
- add_display_only_data(h).merge(metadata)
- end
-
- alias_method :to_hash, :to_h
-
- private
-
- def create_control(control_data)
- ControlData.new(control_data)
- end
-
- # The id and control sequence number are ephemeral data - they are not needed
- # to be persisted and can be regenerated at will. They are only needed
- # for display purposes.
- def add_display_only_data(group)
- group[:id] = SecureRandom.uuid
- group[:controls].collect!.with_index do |c, i|
- # i is zero-indexed, and we want the display one-indexed
- c[:sequence_number] = i + 1
- c
- end
- group
- end
-
- end
-
- class ControlData
- attr_reader :name, :resource_type, :resource_name, :context, :line_number
- attr_accessor :status, :details
-
- def initialize(control_data = {})
- control_data.each do |k, v|
- instance_variable_set("@#{k}", v)
- end
- end
-
- def to_h
- h = {
- name: name,
- status: status,
- details: details,
- resource_type: resource_type,
- resource_name: resource_name,
- }
- h[:context] = context || []
- h
- end
-
- alias_method :to_hash, :to_h
- end
-
- end
-end
diff --git a/lib/chef/audit/logger.rb b/lib/chef/audit/logger.rb
deleted file mode 100644
index 759683ccc8..0000000000
--- a/lib/chef/audit/logger.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "stringio"
-
-class Chef
- class Audit
- class Logger
- def self.puts(message = "")
- @buffer ||= StringIO.new
- @buffer.puts(message)
-
- Chef::Log.info(message)
- end
-
- def self.read_buffer
- return "" if @buffer.nil?
- @buffer.string
- end
- end
- end
-end
diff --git a/lib/chef/audit/rspec_formatter.rb b/lib/chef/audit/rspec_formatter.rb
deleted file mode 100644
index 234202b684..0000000000
--- a/lib/chef/audit/rspec_formatter.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# Author:: Serdar Sutay (<serdar@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "rspec/core"
-
-class Chef
- class Audit
- class RspecFormatter < RSpec::Core::Formatters::DocumentationFormatter
- RSpec::Core::Formatters.register self, :close
-
- # @api public
- #
- # Invoked at the very end, `close` allows the formatter to clean
- # up resources, e.g. open streams, etc.
- #
- # @param _notification [NullNotification] (Ignored)
- def close(_notification)
- # Normally Rspec closes the streams it's given. We don't want it for Chef.
- end
- end
- end
-end
diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb
deleted file mode 100644
index 847d5efbd5..0000000000
--- a/lib/chef/audit/runner.rb
+++ /dev/null
@@ -1,196 +0,0 @@
-#
-# Author:: Claire McQuin (<claire@chef.io>)
-# Copyright:: Copyright 2014-2018, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "chef/audit/logger"
-
-class Chef
- class Audit
- class Runner
-
- attr_reader :run_context
- private :run_context
-
- def initialize(run_context)
- @run_context = run_context
- end
-
- def run
- setup
- register_control_groups
- do_run
- end
-
- def failed?
- RSpec.world.reporter.failed_examples.size > 0
- end
-
- def num_failed
- RSpec.world.reporter.failed_examples.size
- end
-
- def num_total
- RSpec.world.reporter.examples.size
- end
-
- def exclusion_pattern
- Regexp.new(".+[\\\/]lib[\\\/]chef[\\\/]")
- end
-
- private
-
- # Prepare to run audits:
- # - Require files
- # - Configure RSpec
- # - Configure Specinfra/Serverspec
- def setup
- require_deps
- configure_rspec
- configure_specinfra
- end
-
- # RSpec uses a global configuration object, RSpec.configuration. We found
- # there was interference between the configuration for audit-mode and
- # the configuration for our own spec tests in these cases:
- # 1. Specinfra and Serverspec modify RSpec.configuration when loading.
- # 2. Setting output/error streams.
- # 3. Adding formatters.
- # 4. Defining example group aliases.
- #
- # Moreover, Serverspec loads its DSL methods into the global namespace,
- # which causes conflicts with the Chef namespace for resources and packages.
- #
- # We wait until we're in the audit-phase of the chef-client run to load
- # these files. This helps with the namespacing problems we saw, and
- # prevents Specinfra and Serverspec from modifying the RSpec configuration
- # used by our spec tests.
- def require_deps
- require "rspec"
- require "rspec/its"
- require "specinfra"
- require "specinfra/helper"
- require "specinfra/helper/set"
- require "serverspec/helper"
- require "serverspec/matcher"
- require "serverspec/subject"
- require "chef/audit/audit_event_proxy"
- require "chef/audit/rspec_formatter"
-
- Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
- end
-
- # Configure RSpec just the way we like it:
- # - Set location of error and output streams
- # - Add custom audit-mode formatters
- # - Explicitly disable :should syntax
- # - Set :color option according to chef config
- # - Disable exposure of global DSL
- def configure_rspec
- set_streams
- add_formatters
- disable_should_syntax
-
- RSpec.configure do |c|
- c.color = Chef::Config[:color]
- c.expose_dsl_globally = false
- c.project_source_dirs = Array(Chef::Config[:cookbook_path])
- c.backtrace_exclusion_patterns << exclusion_pattern
- end
- end
-
- # Set the error and output streams which audit-mode will use to report
- # human-readable audit information.
- #
- # This should always be called before #add_formatters. RSpec won't allow
- # the output stream to be changed for a formatter once the formatter has
- # been added.
- def set_streams
- RSpec.configuration.output_stream = Chef::Audit::Logger
- RSpec.configuration.error_stream = Chef::Audit::Logger
- end
-
- # Add formatters which we use to
- # 1. Output human-readable data to the output stream,
- # 2. Collect JSON data to send back to the analytics server.
- def add_formatters
- RSpec.configuration.add_formatter(Chef::Audit::AuditEventProxy)
- RSpec.configuration.add_formatter(Chef::Audit::RspecFormatter)
- Chef::Audit::AuditEventProxy.events = run_context.events
- end
-
- # Audit-mode uses RSpec 3. :should syntax is deprecated by default in
- # RSpec 3, so we explicitly disable it here.
- #
- # This can be removed once :should is removed from RSpec.
- def disable_should_syntax
- RSpec.configure do |config|
- config.expect_with :rspec do |c|
- c.syntax = :expect
- end
- end
- end
-
- # Set up the backend for Specinfra/Serverspec. :exec is the local system; on Windows, it is :cmd
- def configure_specinfra
- if Chef::Platform.windows?
- Specinfra.configuration.backend = :cmd
- Specinfra.configuration.os = { family: "windows" }
- else
- Specinfra.configuration.backend = :exec
- end
- end
-
- # Iterates through the control groups registered to this run_context, builds an
- # example group (RSpec::Core::ExampleGroup) object per control group, and
- # registers the group with the RSpec.world.
- #
- # We could just store an array of example groups and not use RSpec.world,
- # but it may be useful later if we decide to apply our own ordering scheme
- # or use example group filters.
- def register_control_groups
- add_example_group_methods
- run_context.audits.each do |name, group| # rubocop:disable Performance/HashEachMethods
- ctl_grp = RSpec::Core::ExampleGroup.__control_group__(*group.args, &group.block)
- RSpec.world.record(ctl_grp)
- end
- end
-
- # Add example group method aliases to RSpec.
- #
- # __control_group__: Used internally to create example groups from the control
- # groups saved in the run_context.
- # control: Used within the context of a control group block, like RSpec's
- # describe or context.
- def add_example_group_methods
- RSpec::Core::ExampleGroup.define_example_group_method :__control_group__
- RSpec::Core::ExampleGroup.define_example_group_method :control
- end
-
- # Run the audits!
- def do_run
- # RSpec::Core::Runner wants to be initialized with an
- # RSpec::Core::ConfigurationOptions object, which is used to process
- # command line configuration arguments. We directly fiddle with the
- # internal RSpec configuration object, so we give nil here and let
- # RSpec pick up its own configuration and world.
- runner = RSpec::Core::Runner.new(nil)
- runner.run_specs(RSpec.world.ordered_example_groups)
- end
-
- end
- end
-end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index 0dd6b2666f..459ce77306 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -26,7 +26,6 @@ require "chef/deprecated"
require "chef/server_api"
require "chef/api_client"
require "chef/api_client/registration"
-require "chef/audit/runner"
require "chef/node"
require "chef/role"
require "chef/file_cache"
@@ -48,7 +47,6 @@ require "chef/version"
require "chef/action_collection"
require "chef/resource_reporter"
require "chef/data_collector"
-require "chef/audit/audit_reporter"
require "chef/run_lock"
require "chef/policy_builder"
require "chef/request_id"
@@ -219,30 +217,11 @@ class Chef
# @see #converge_and_save
# @see Chef::Runner
#
- # Phase 4: Audit
- # --------------
- # Runs 'control_group' audits in recipes. This entire section can be enabled or disabled with config.
- #
- # 1. 'control_group' DSL collects audits during Phase 2
- # 2. Audits are run using RSpec
- # 3. Errors are collected and reported using the formatters
- #
- # @see #run_audits
- # @see Chef::Audit::Runner#run
- #
- # @raise [Chef::Exceptions::RunFailedWrappingError] If converge or audit failed.
- #
- # @see Chef::Config#enforce_path_sanity
- # @see Chef::Config#solo
- # @see Chef::Config#audit_mode
- #
# @return Always returns true.
#
def run
start_profiling
- run_error = nil
-
runlock = RunLock.new(Chef::Config.lockfile)
# TODO feels like acquire should have its own block arg for this
runlock.acquire
@@ -284,19 +263,7 @@ class Chef
load_required_recipe(@rest, run_context) unless Chef::Config[:solo_legacy_mode]
- if Chef::Config[:audit_mode] != :audit_only
- converge_error = converge_and_save(run_context)
- end
-
- if Chef::Config[:why_run] == true
- # why_run should probably be renamed to why_converge
- logger.debug("Not running controls in 'why-run' mode - this mode is used to see potential converge changes")
- elsif Chef::Config[:audit_mode] != :disabled
- audit_error = run_audits(run_context)
- end
-
- # Raise converge_error so run_failed reporters/events are processed.
- raise converge_error if converge_error
+ converge_and_save(run_context)
run_status.stop_clock
logger.info("Chef Run complete in #{run_status.elapsed_time} seconds")
@@ -318,38 +285,20 @@ class Chef
run_failed
end
events.run_failed(run_error, run_status)
+ Chef::Application.debug_stacktrace(run_error)
+ raise run_error
ensure
Chef::RequestID.instance.reset_request_id
@run_status = nil
runlock.release
end
- # Raise audit, converge, and other errors here so that we exit
- # with the proper exit status code and everything gets raised
- # as a RunFailedWrappingError
- if run_error || converge_error || audit_error
- error = if Chef::Config[:audit_mode] == :disabled
- run_error || converge_error
- else
- e = if run_error == converge_error
- Chef::Exceptions::RunFailedWrappingError.new(converge_error, audit_error)
- else
- Chef::Exceptions::RunFailedWrappingError.new(run_error, converge_error, audit_error)
- end
- e.fill_backtrace
- e
- end
-
- Chef::Application.debug_stacktrace(error)
- raise error
- end
-
true
end
#
# Private API
- # TODO make this stuff protected or private
+ # @todo make this stuff protected or private
#
# @api private
@@ -412,18 +361,6 @@ class Chef
signing_key_filename: config[:client_key], validate_utf8: false)
end
- # Resource reporters send event information back to the chef server for
- # processing. Can only be called after we have a @rest object
- # @api private
- def register_reporters
- [
- Chef::ResourceReporter.new(rest_clean),
- Chef::Audit::AuditReporter.new(rest_clean),
- ].each do |r|
- events.register(r)
- end
- end
-
#
# Callback to fire notifications that the Chef run is starting
#
@@ -675,7 +612,9 @@ class Chef
signing_key_filename: config[:client_key])
# force initialization of the rest_clean API object
rest_clean(client_name, config)
- register_reporters
+ # FIXME: we could initialize rest_clean much earlier and hang it off of the run_status and then
+ # have the ResourceReporter pull it off of the run_status and eliminate this tight coupling.
+ events.register(Chef::ResourceReporter.new(rest_clean))
rescue Exception => e
# TODO this should probably only ever fire if we *started* registration.
# Move it to the block above.
@@ -695,14 +634,9 @@ class Chef
#
# @param run_context The run context.
#
- # @return The thrown exception, if we are in audit mode. `nil` means the
- # converge was successful or ended early.
- #
- # @raise Any converge exception, unless we are in audit mode, in which case
- # we *return* the exception.
+ # @raise Any converge exception
#
# @see Chef::Runner#converge
- # @see Chef::Config#audit_mode
# @see Chef::EventDispatch#converge_start
# @see Chef::EventDispatch#converge_complete
# @see Chef::EventDispatch#converge_failed
@@ -710,7 +644,6 @@ class Chef
# @api private
#
def converge(run_context)
- converge_exception = nil
catch(:end_client_run_early) do
begin
events.converge_start(run_context)
@@ -720,83 +653,23 @@ class Chef
events.converge_complete
rescue Exception => e
events.converge_failed(e)
- raise e if Chef::Config[:audit_mode] == :disabled
- converge_exception = e
+ raise e
end
end
- converge_exception
end
- #
# Converge the node via and then save it if successful.
#
- # @param run_context The run context.
- #
- # @return The thrown exception, if we are in audit mode. `nil` means the
- # converge was successful or ended early.
+ # If converge() raises it is important that save_updated_node is bypassed.
#
- # @raise Any converge or node save exception, unless we are in audit mode,
- # in which case we *return* the exception.
- #
- # @see #converge
- # @see #save_updated_mode
- # @see Chef::Config#audit_mode
+ # @param run_context [Chef::RunContext] The run context.
+ # @raise Any converge or node save exception
#
# @api private
#
- # We don't want to change the old API on the `converge` method to have it perform
- # saving. So we wrap it in this method.
- # TODO given this seems to be pretty internal stuff, how badly do we need to
- # split this stuff up?
- #
def converge_and_save(run_context)
- converge_exception = converge(run_context)
- unless converge_exception
- begin
- save_updated_node
- rescue Exception => e
- raise e if Chef::Config[:audit_mode] == :disabled
- converge_exception = e
- end
- end
- converge_exception
- end
-
- #
- # Run the audit phase.
- #
- # Triggers the audit_phase_start, audit_phase_complete and
- # audit_phase_failed events.
- #
- # @param run_context The run context.
- #
- # @return Any thrown exceptions. `nil` if successful.
- #
- # @see Chef::Audit::Runner#run
- # @see Chef::EventDispatch#audit_phase_start
- # @see Chef::EventDispatch#audit_phase_complete
- # @see Chef::EventDispatch#audit_phase_failed
- #
- # @api private
- #
- def run_audits(run_context)
- begin
- events.audit_phase_start(run_status)
- logger.info("Starting audit phase")
- auditor = Chef::Audit::Runner.new(run_context)
- auditor.run
- if auditor.failed?
- audit_exception = Chef::Exceptions::AuditsFailed.new(auditor.num_failed, auditor.num_total)
- @events.audit_phase_failed(audit_exception, Chef::Audit::Logger.read_buffer)
- else
- @events.audit_phase_complete(Chef::Audit::Logger.read_buffer)
- end
- rescue Exception => e
- logger.error("Audit phase failed with error message: #{e.message}")
- @events.audit_phase_failed(e, Chef::Audit::Logger.read_buffer)
- audit_exception = e
- end
- audit_exception
+ converge(run_context)
+ save_updated_node
end
#
diff --git a/lib/chef/dsl/audit.rb b/lib/chef/dsl/audit.rb
deleted file mode 100644
index 927523e976..0000000000
--- a/lib/chef/dsl/audit.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "chef/exceptions"
-
-class Chef
- module DSL
- module Audit
-
- # Can encompass tests in a `control` block or `describe` block
- # Adds the controls group and block (containing controls to execute) to the runner's list of pending examples
- def control_group(*args, &block)
- raise Chef::Exceptions::NoAuditsProvided unless block
-
- name = args[0]
- if name.nil? || name.empty?
- raise Chef::Exceptions::AuditNameMissing
- elsif run_context.audits.key?(name)
- raise Chef::Exceptions::AuditControlGroupDuplicate.new(name)
- end
-
- # This DSL will only work in the Recipe class because that exposes the cookbook_name
- cookbook_name = self.cookbook_name
- metadata = {
- cookbook_name: cookbook_name,
- cookbook_version: run_context.cookbook_collection[cookbook_name].version,
- recipe_name: recipe_name,
- line_number: block.source_location[1],
- }
-
- run_context.audits[name] = Struct.new(:args, :block, :metadata).new(args, block, metadata)
- end
-
- end
- end
-end
diff --git a/lib/chef/dsl/recipe.rb b/lib/chef/dsl/recipe.rb
index 9da812cec0..4d68a36a81 100644
--- a/lib/chef/dsl/recipe.rb
+++ b/lib/chef/dsl/recipe.rb
@@ -24,7 +24,6 @@ require "chef/dsl/data_query"
require "chef/dsl/include_recipe"
require "chef/dsl/registry_helper"
require "chef/dsl/reboot_pending"
-require "chef/dsl/audit"
require "chef/dsl/powershell"
require "chef/dsl/core"
require "chef/mixin/lazy_module_include"
@@ -55,7 +54,6 @@ class Chef
include Chef::DSL::IncludeRecipe
include Chef::DSL::RegistryHelper
include Chef::DSL::RebootPending
- include Chef::DSL::Audit
include Chef::DSL::Powershell
include Chef::DSL::Resources
include Chef::DSL::Definitions
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb
index 3b0b70c9b9..be51cf362f 100644
--- a/lib/chef/event_dispatch/base.rb
+++ b/lib/chef/event_dispatch/base.rb
@@ -292,37 +292,6 @@ class Chef
def converge_failed(exception)
end
- ##################################
- # Audit Mode Events
- # This phase is currently experimental and these event APIs are subject to change
- ##################################
-
- # Called before audit phase starts
- def audit_phase_start(run_status)
- end
-
- # Called when audit phase successfully finishes
- def audit_phase_complete(audit_output)
- end
-
- # Called if there is an uncaught exception during the audit phase. The audit runner should
- # be catching and handling errors from the examples, so this is only uncaught errors (like
- # bugs in our handling code)
- def audit_phase_failed(exception, audit_output)
- end
-
- # Signifies the start of a `control_group` block with a defined name
- def control_group_started(name)
- end
-
- # An example in a `control_group` block completed successfully
- def control_example_success(control_group_name, example_data)
- end
-
- # An example in a `control_group` block failed with the provided error
- def control_example_failure(control_group_name, example_data, error)
- end
-
# TODO: need events for notification resolve?
# def notifications_resolved
# end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 41e0cdb33e..0a6c7dc635 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -443,26 +443,7 @@ class Chef
end
end
- class AuditError < RuntimeError; end
-
- class AuditControlGroupDuplicate < AuditError
- def initialize(name)
- super "Control group with name '#{name}' has already been defined"
- end
- end
- class AuditNameMissing < AuditError; end
- class NoAuditsProvided < AuditError
- def initialize
- super "You must provide a block with controls"
- end
- end
- class AuditsFailed < AuditError
- def initialize(num_failed, num_total)
- super "Audit phase found failures - #{num_failed}/#{num_total} controls failed"
- end
- end
-
- # If a converge or audit fails, we want to wrap the output from those errors into 1 error so we can
+ # If a converge fails, we want to wrap the output from those errors into 1 error so we can
# see both issues in the output. It is possible that nil will be provided. You must call `fill_backtrace`
# to correctly populate the backtrace with the wrapped backtraces.
class RunFailedWrappingError < RuntimeError
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index 936738f147..0b0a589d56 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -8,8 +8,7 @@ class Chef
# show context.
class Doc < Formatters::Base
- attr_reader :start_time, :end_time, :successful_audits, :failed_audits
- private :successful_audits, :failed_audits
+ attr_reader :start_time, :end_time
cli_name(:doc)
@@ -18,8 +17,6 @@ class Chef
@updated_resources = 0
@up_to_date_resources = 0
- @successful_audits = 0
- @failed_audits = 0
@start_time = Time.now
@end_time = @start_time
@skipped_resources = 0
@@ -51,10 +48,6 @@ class Chef
@up_to_date_resources + @updated_resources + @skipped_resources
end
- def total_audits
- successful_audits + failed_audits
- end
-
def run_completed(node)
@end_time = Time.now
# Print out deprecations.
@@ -85,9 +78,6 @@ class Chef
puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources would have been updated"
else
puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{pretty_elapsed_time}"
- if total_audits > 0
- puts_line " #{successful_audits}/#{total_audits} controls succeeded"
- end
end
end
@@ -97,9 +87,6 @@ class Chef
puts_line "Chef Client failed. #{@updated_resources} resources would have been updated"
else
puts_line "Chef Client failed. #{@updated_resources} resources updated in #{pretty_elapsed_time}"
- if total_audits > 0
- puts_line " #{successful_audits} controls succeeded"
- end
end
end
@@ -239,37 +226,6 @@ class Chef
converge_complete
end
- # Called before audit phase starts
- def audit_phase_start(run_status)
- puts_line "Starting audit phase"
- end
-
- def audit_phase_complete(audit_output)
- puts_line audit_output
- puts_line "Auditing complete"
- end
-
- def audit_phase_failed(error, audit_output)
- puts_line audit_output
- puts_line ""
- puts_line "Audit phase exception:"
- indent
- puts_line (error.message).to_s
- if error.backtrace
- error.backtrace.each do |l|
- puts_line l
- end
- end
- end
-
- def control_example_success(control_group_name, example_data)
- @successful_audits += 1
- end
-
- def control_example_failure(control_group_name, example_data, error)
- @failed_audits += 1
- end
-
# Called before action is executed on a resource.
def resource_action_start(resource, action, notification_type = nil, notifier = nil)
if resource.cookbook_name && resource.recipe_name
@@ -284,7 +240,7 @@ class Chef
@current_recipe = resource_recipe
indent
end
- # TODO: info about notifies
+ # @todo info about notifies
start_line "* #{resource} action #{action}", stream: resource
indent
end
diff --git a/lib/chef/mixin/properties.rb b/lib/chef/mixin/properties.rb
index f72a22db2d..e0b32d2b9d 100644
--- a/lib/chef/mixin/properties.rb
+++ b/lib/chef/mixin/properties.rb
@@ -83,7 +83,7 @@ class Chef
# is part of object identity. Defaults to `false`.
# @option options [Boolean] :sensitive `true` if this property could
# contain sensitive information and whose value should be redacted
- # in any resource reporting / auditing output. Defaults to `false`.
+ # in any resource reporting output. Defaults to `false`.
#
# @example Bare property
# property :x
@@ -176,9 +176,6 @@ class Chef
# by providing additional options for a package manager to use when
# installing a package.
#
- # This list is used by the Chef client auditing system to extract
- # information from resources to describe changes made to the system.
- #
# This method is unnecessary when declaring properties with `property`;
# properties are added to state_properties by default, and can be turned off
# with `desired_state: false`.
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index e407a0e7be..bba109360d 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -106,11 +106,6 @@ class Chef
attr_accessor :action_collection
#
- # The list of control groups to execute during the audit phase
- #
- attr_reader :audits
-
- #
# Pointer back to the Chef::Runner that created this
#
attr_accessor :runner
@@ -204,7 +199,6 @@ class Chef
# Initialize state that applies to both Chef::RunContext and Chef::ChildRunContext
#
def initialize_child_state
- @audits = {}
@resource_collection = Chef::ResourceCollection.new(self)
@before_notification_collection = Hash.new { |h, k| h[k] = [] }
@immediate_notification_collection = Hash.new { |h, k| h[k] = [] }
@@ -645,8 +639,6 @@ class Chef
end
CHILD_STATE = %w{
- audits
- audits=
create_child
add_delayed_action
delayed_actions
diff --git a/spec/functional/audit/rspec_formatter_spec.rb b/spec/functional/audit/rspec_formatter_spec.rb
deleted file mode 100644
index f30f7bbd8a..0000000000
--- a/spec/functional/audit/rspec_formatter_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@chef.io>)
-#
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "rspec/core/sandbox"
-require "chef/audit/runner"
-require "rspec/support/spec/in_sub_process"
-require "rspec/support/spec/stderr_splitter"
-require "chef/audit/rspec_formatter"
-
-describe Chef::Audit::RspecFormatter do
- include RSpec::Support::InSubProcess
-
- let(:events) { double("events").as_null_object }
- let(:audits) { {} }
- let(:run_context) { instance_double(Chef::RunContext, events: events, audits: audits) }
- let(:runner) { Chef::Audit::Runner.new(run_context) }
-
- let(:output) { double("output") }
- # aggressively define this so we can mock out the new call later
- let!(:formatter) { Chef::Audit::RspecFormatter.new(output) }
-
- around(:each) do |ex|
- RSpec::Core::Sandbox.sandboxed { ex.run }
- end
-
- it "should not close the output using our formatter" do
- in_sub_process do
- expect_any_instance_of(Chef::Audit::RspecFormatter).to receive(:new).and_return(formatter)
- expect(formatter).to receive(:close).and_call_original
- expect(output).to_not receive(:close)
-
- runner.run
- end
- end
-
-end
diff --git a/spec/functional/audit/runner_spec.rb b/spec/functional/audit/runner_spec.rb
deleted file mode 100644
index f80256fa5c..0000000000
--- a/spec/functional/audit/runner_spec.rb
+++ /dev/null
@@ -1,121 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "rspec/core/sandbox"
-require "chef/audit/runner"
-require "rspec/support/spec/in_sub_process"
-require "rspec/support/spec/stderr_splitter"
-require "tempfile"
-
-##
-# This functional test ensures that our runner can be setup to not interfere with existing RSpec
-# configuration and world objects. When normally running Chef, there is only 1 RSpec instance
-# so this isn't needed. In unit testing the Runner should be mocked appropriately.
-
-describe Chef::Audit::Runner do
-
- # The functional tests must be run in a sub_process. Including Serverspec includes the Serverspec DSL - this
- # conflicts with our `package` DSL (among others) when we try to test `package` inside an RSpec example.
- # Our DSL leverages `method_missing` while the Serverspec DSL defines a method on the RSpec::Core::ExampleGroup.
- # The defined method wins our and returns before our `method_missing` DSL can be called.
- #
- # Running in a sub_process means the serverspec libraries will only be included in a forked process, not the main one.
- include RSpec::Support::InSubProcess
-
- let(:events) { double("events").as_null_object }
- let(:runner) { Chef::Audit::Runner.new(run_context) }
- let(:stdout) { StringIO.new }
-
- around(:each) do |ex|
- RSpec::Core::Sandbox.sandboxed { ex.run }
- end
-
- describe "#run" do
-
- let(:audits) { {} }
- let(:run_context) { instance_double(Chef::RunContext, events: events, audits: audits) }
- let(:control_group_name) { "control_group_name" }
-
- # Set cookbook path to include our parent, so that it will recognize this
- # rspec file as one that should show up in the backtrace.
- before(:each) { Chef::Config[:cookbook_path] = File.dirname(__FILE__) }
-
- shared_context "passing audit" do
- let(:audits) do
- should_pass = lambda do
- it "should pass" do
- expect(2 - 2).to eq(0)
- end
- end
- { control_group_name => Struct.new(:args, :block).new([control_group_name], should_pass) }
- end
- end
-
- shared_context "failing audit" do
- let(:audits) do
- should_fail = lambda do
- it "should fail" do
- expect(2 - 1).to eq(0)
- end
- end
- { control_group_name => Struct.new(:args, :block).new([control_group_name], should_fail) }
- end
- end
-
- describe "log location is stdout" do
- before do
- allow(Chef::Log).to receive(:info) do |msg|
- stdout.puts(msg)
- end
- end
-
- it "Correctly runs an empty controls block" do
- in_sub_process do
- runner.run
- end
- end
-
- context "there is a single successful control" do
- include_context "passing audit"
- it "correctly runs" do
- in_sub_process do
- runner.run
-
- expect(stdout.string).to match(/1 example, 0 failures/)
- end
- end
- end
-
- context "there is a single failing control" do
- include_context "failing audit"
- it "correctly runs" do
- in_sub_process do
- runner.run
-
- expect(stdout.string).to match(/Failure\/Error: expect\(2 - 1\)\.to eq\(0\)/)
- expect(stdout.string).to match(/1 example, 1 failure/)
- expect(stdout.string).to match(/# control_group_name should fail/)
- end
- end
- end
- end
-
- end
-
-end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index d15a7d2afa..afe94f854e 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -407,45 +407,6 @@ describe "chef-client" do
end
end
- when_the_repository "has a cookbook with only an audit recipe" do
-
- before do
- file "config/client.rb", <<~EOM
- local_mode true
- cookbook_path "#{path_to('cookbooks')}"
- audit_mode :enabled
- EOM
- end
-
- it "should exit with a zero code when there is not an audit failure" do
- file "cookbooks/audit_test/recipes/succeed.rb", <<~RECIPE
- control_group "control group without top level control" do
- it "should succeed" do
- expect(2 - 2).to eq(0)
- end
- end
- RECIPE
-
- result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'audit_test::succeed' -l info", cwd: chef_dir)
- expect(result.error?).to be_falsey
- expect(result.stdout).to include("Successfully executed all `control_group` blocks and contained examples")
- end
-
- it "should exit with a non-zero code when there is an audit failure" do
- file "cookbooks/audit_test/recipes/fail.rb", <<~RECIPE
- control_group "control group without top level control" do
- it "should fail" do
- expect(2 - 2).to eq(1)
- end
- end
- RECIPE
-
- result = shell_out("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'audit_test::fail'", cwd: chef_dir)
- expect(result.error?).to be_truthy
- expect(result.stdout).to include("Failure/Error: expect(2 - 2).to eq(1)")
- end
- end
-
when_the_repository "has a cookbook that deploys a file" do
before do
file "cookbooks/x/recipes/default.rb", <<~RECIPE
diff --git a/spec/integration/client/exit_code_spec.rb b/spec/integration/client/exit_code_spec.rb
index a6e070f9a5..2e29502070 100644
--- a/spec/integration/client/exit_code_spec.rb
+++ b/spec/integration/client/exit_code_spec.rb
@@ -34,14 +34,6 @@ describe "chef-client" do
EOM
end
- def setup_client_rb_with_audit_mode
- file "config/client.rb", <<~EOM
- local_mode true
- cookbook_path "#{path_to('cookbooks')}"
- audit_mode :audit_only
- EOM
- end
-
def run_chef_client_and_expect_exit_code(exit_code)
shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'",
cwd: chef_dir,
@@ -63,25 +55,6 @@ describe "chef-client" do
end
end
- context "with an audit recipe" do
- context "which fails" do
- before do
- file "cookbooks/x/recipes/default.rb", <<~RECIPE
- control_group "control group without top level control" do
- it "should fail" do
- expect(4 - 4).to eq(1)
- end
- end
- RECIPE
- end
-
- it "exits with AUDIT_MODE_FAILURE, 42" do
- setup_client_rb_with_audit_mode
- run_chef_client_and_expect_exit_code 42
- end
- end
- end
-
context "with a recipe" do
context "which throws an error" do
before { file "cookbooks/x/recipes/default.rb", "raise 'BOOM'" }
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index 40f690abb1..f58d1ed079 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -337,75 +337,6 @@ Enable chef-client interval runs by setting `:client_fork = true` in your config
end
end
- describe "audit mode" do
- shared_examples "experimental feature" do
- before do
- allow(Chef::Log).to receive(:warn)
- end
- end
-
- shared_examples "unrecognized setting" do
- it "fatals with a message including the incorrect setting" do
- expect(Chef::Application).to receive(:fatal!).with(/Unrecognized setting #{mode} for audit mode/)
- app.reconfigure
- end
- end
-
- shared_context "set via config file" do
- before do
- Chef::Config[:audit_mode] = mode
- end
- end
-
- shared_context "set via command line" do
- before do
- ARGV.replace(["--audit-mode", mode])
- end
- end
-
- describe "enabled via config file" do
- include_context "set via config file" do
- let(:mode) { :enabled }
- include_examples "experimental feature"
- end
- end
-
- describe "enabled via command line" do
- include_context "set via command line" do
- let(:mode) { "enabled" }
- include_examples "experimental feature"
- end
- end
-
- describe "audit_only via config file" do
- include_context "set via config file" do
- let(:mode) { :audit_only }
- include_examples "experimental feature"
- end
- end
-
- describe "audit-only via command line" do
- include_context "set via command line" do
- let(:mode) { "audit-only" }
- include_examples "experimental feature"
- end
- end
-
- describe "unrecognized setting via config file" do
- include_context "set via config file" do
- let(:mode) { :derp }
- include_examples "unrecognized setting"
- end
- end
-
- describe "unrecognized setting via command line" do
- include_context "set via command line" do
- let(:mode) { "derp" }
- include_examples "unrecognized setting"
- end
- end
- end
-
describe "when both the pidfile and lockfile opts are set to the same value" do
before do
diff --git a/spec/unit/application/exit_code_spec.rb b/spec/unit/application/exit_code_spec.rb
index 7783cf3ed7..e8a0072ff3 100644
--- a/spec/unit/application/exit_code_spec.rb
+++ b/spec/unit/application/exit_code_spec.rb
@@ -49,10 +49,6 @@ describe Chef::Application::ExitCode do
expect(valid_rfc_exit_codes.include?(3)).to eq(true)
end
- it "validates a AUDIT_MODE_FAILURE return code of 42" do
- expect(valid_rfc_exit_codes.include?(42)).to eq(true)
- end
-
it "validates a REBOOT_SCHEDULED return code of 35" do
expect(valid_rfc_exit_codes.include?(35)).to eq(true)
end
@@ -98,12 +94,6 @@ describe Chef::Application::ExitCode do
expect(exit_codes.normalize_exit_code(Exception.new("BOOM"))).to eq(1)
end
- it "returns AUDIT_MODE_FAILURE when there is an audit error" do
- audit_error = Chef::Exceptions::AuditError.new("BOOM")
- runtime_error = Chef::Exceptions::RunFailedWrappingError.new(audit_error)
- expect(exit_codes.normalize_exit_code(runtime_error)).to eq(42)
- end
-
it "returns REBOOT_SCHEDULED when there is an reboot requested" do
reboot_error = Chef::Exceptions::Reboot.new("BOOM")
runtime_error = Chef::Exceptions::RunFailedWrappingError.new(reboot_error)
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index 3f7c203c67..939300b7e4 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -49,11 +49,6 @@ describe Chef::Application::Solo do
expect(Chef::Config[:solo]).to be_truthy
end
- it "should set audit-mode to :disabled" do
- app.reconfigure
- expect(Chef::Config[:audit_mode]).to be :disabled
- end
-
describe "when configured to not fork the client process" do
before do
Chef::Config[:client_fork] = false
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index b8d7242466..ef28dbb21b 100644
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -305,8 +305,8 @@ describe Chef::Application do
describe "when a standard exit code is supplied" do
it "should exit with the given exit code" do
- expect(Process).to receive(:exit).with(42).and_return(true)
- Chef::Application.fatal! "blah", 42
+ expect(Process).to receive(:exit).with(41).and_return(true)
+ Chef::Application.fatal! "blah", 41
end
end
diff --git a/spec/unit/audit/audit_event_proxy_spec.rb b/spec/unit/audit/audit_event_proxy_spec.rb
deleted file mode 100644
index a9b27f238e..0000000000
--- a/spec/unit/audit/audit_event_proxy_spec.rb
+++ /dev/null
@@ -1,318 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@chef.io>)
-#
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "chef/audit/audit_event_proxy"
-
-describe Chef::Audit::AuditEventProxy do
-
- let(:stdout) { StringIO.new }
- let(:events) { double("Chef::Events") }
- let(:audit_event_proxy) { Chef::Audit::AuditEventProxy.new(stdout) }
-
- before do
- Chef::Audit::AuditEventProxy.events = events
- end
-
- describe "#example_group_started" do
-
- let(:description) { "poots" }
- let(:group) do
- double("ExampleGroup", parent_groups: parents,
- description: description) end
- let(:notification) { double("Notification", group: group) }
-
- context "when notified from a top-level example group" do
-
- let(:parents) { [double("ExampleGroup")] }
-
- it "notifies control_group_started event" do
- expect(Chef::Log).to receive(:trace)
- .with("Entered \`control_group\` block named poots")
- expect(events).to receive(:control_group_started)
- .with(description)
- audit_event_proxy.example_group_started(notification)
- end
- end
-
- context "when notified from an inner-level example group" do
-
- let(:parents) { [double("ExampleGroup"), double("OuterExampleGroup")] }
-
- it "does nothing" do
- expect(events).to_not receive(:control_group_started)
- audit_event_proxy.example_group_started(notification)
- end
- end
- end
-
- describe "#stop" do
-
- let(:examples) { [] }
- let(:notification) { double("Notification", examples: examples) }
- let(:exception) { nil }
- let(:example) { double("Example", exception: exception) }
- let(:control_group_name) { "audit test" }
- let(:control_data) { double("ControlData") }
-
- before do
- allow(Chef::Log).to receive(:info) # silence messages to output stream
- end
-
- it "sends a message that audits completed" do
- expect(Chef::Log).to receive(:info).with("Successfully executed all \`control_group\` blocks and contained examples")
- audit_event_proxy.stop(notification)
- end
-
- context "when an example succeeded" do
-
- let(:examples) { [example] }
- let(:excpetion) { nil }
-
- before do
- allow(audit_event_proxy).to receive(:build_control_from)
- .with(example)
- .and_return([control_group_name, control_data])
- end
-
- it "notifies events" do
- expect(events).to receive(:control_example_success)
- .with(control_group_name, control_data)
- audit_event_proxy.stop(notification)
- end
- end
-
- context "when an example failed" do
-
- let(:examples) { [example] }
- let(:exception) { double("ExpectationNotMet") }
-
- before do
- allow(audit_event_proxy).to receive(:build_control_from)
- .with(example)
- .and_return([control_group_name, control_data])
- end
-
- it "notifies events" do
- expect(events).to receive(:control_example_failure)
- .with(control_group_name, control_data, exception)
- audit_event_proxy.stop(notification)
- end
- end
-
- describe "#build_control_from" do
-
- let(:examples) { [example] }
-
- let(:example) do
- double("Example", metadata: metadata,
- description: example_description,
- full_description: full_description, exception: nil) end
-
- let(:metadata) do
- {
- described_class: described_class,
- example_group: example_group,
- line_number: line,
- }
- end
-
- let(:example_group) do
- {
- description: group_description,
- parent_example_group: parent_group,
- }
- end
-
- let(:parent_group) do
- {
- description: control_group_name,
- parent_example_group: nil,
- }
- end
-
- let(:line) { 27 }
-
- let(:control_data) do
- {
- name: example_description,
- desc: full_description,
- resource_type: resource_type,
- resource_name: resource_name,
- context: context,
- line_number: line,
- }
- end
-
- shared_examples "built control" do
-
- before do
- if described_class
- allow(described_class).to receive(:instance_variable_get)
- .with(:@name)
- .and_return(resource_name)
- allow(described_class.class).to receive(:name)
- .and_return(described_class.class)
- end
- end
-
- it "returns the controls block name and example metadata for reporting" do
- expect(events).to receive(:control_example_success)
- .with(control_group_name, control_data)
- audit_event_proxy.stop(notification)
- end
- end
-
- describe "a top-level example" do
- # controls "port 111" do
- # it "has nobody listening" do
- # expect(port("111")).to_not be_listening
- # end
- # end
-
- # Description parts
- let(:group_description) { "port 111" }
- let(:example_description) { "has nobody listening" }
- let(:full_description) { group_description + " " + example_description }
-
- # Metadata fields
- let(:described_class) { nil }
-
- # Example group (metadata[:example_group]) fields
- let(:parent_group) { nil }
-
- # Expected returns
- let(:control_group_name) { group_description }
-
- # Control data fields
- let(:resource_type) { nil }
- let(:resource_name) { nil }
- let(:context) { [] }
-
- include_examples "built control"
- end
-
- describe "an example with an implicit subject" do
- # controls "application ports" do
- # control port(111) do
- # it { is_expected.to_not be_listening }
- # end
- # end
-
- # Description parts
- let(:control_group_name) { "application ports" }
- let(:group_description) { "#{resource_type} #{resource_name}" }
- let(:example_description) { "should not be listening" }
- let(:full_description) do
- [control_group_name, group_description,
- example_description].join(" ") end
-
- # Metadata fields
- let(:described_class) do
- double("Serverspec::Type::Port",
- class: "Serverspec::Type::Port", name: resource_name) end
-
- # Control data fields
- let(:resource_type) { "Port" }
- let(:resource_name) { "111" }
- let(:context) { [] }
-
- include_examples "built control"
- end
-
- describe "an example in a nested context" do
- # controls "application ports" do
- # control "port 111" do
- # it "is not listening" do
- # expect(port(111)).to_not be_listening
- # end
- # end
- # end
-
- # Description parts
- let(:control_group_name) { "application ports" }
- let(:group_description) { "port 111" }
- let(:example_description) { "is not listening" }
- let(:full_description) do
- [control_group_name, group_description,
- example_description].join(" ") end
-
- # Metadata fields
- let(:described_class) { nil }
-
- # Control data fields
- let(:resource_type) { nil }
- let(:resource_name) { nil }
- let(:context) { [group_description] }
-
- include_examples "built control"
- end
-
- describe "an example in a nested context including Serverspec" do
- # controls "application directory" do
- # control file("/tmp/audit") do
- # describe file("/tmp/audit/test_file") do
- # it "is a file" do
- # expect(subject).to be_file
- # end
- # end
- # end
- # end
-
- # Description parts
- let(:control_group_name) { "application directory" }
- let(:outer_group_description) { "File \"tmp/audit\"" }
- let(:group_description) { "#{resource_type} #{resource_name}" }
- let(:example_description) { "is a file" }
- let(:full_description) do
- [control_group_name, outer_group_description,
- group_description, example_description].join(" ") end
-
- # Metadata parts
- let(:described_class) do
- double("Serverspec::Type::File",
- class: "Serverspec::Type::File", name: resource_name) end
-
- # Example group parts
- let(:parent_group) do
- {
- description: outer_group_description,
- parent_example_group: control_group,
- }
- end
-
- let(:control_group) do
- {
- description: control_group_name,
- parent_example_group: nil,
- }
- end
-
- # Control data parts
- let(:resource_type) { "File" }
- let(:resource_name) { "/tmp/audit/test_file" }
- let(:context) { [outer_group_description] }
-
- include_examples "built control"
- end
- end
- end
-
-end
diff --git a/spec/unit/audit/audit_reporter_spec.rb b/spec/unit/audit/audit_reporter_spec.rb
deleted file mode 100644
index 0a023babd0..0000000000
--- a/spec/unit/audit/audit_reporter_spec.rb
+++ /dev/null
@@ -1,435 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@chef.io>)
-#
-# Copyright:: Copyright 2014-2018, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-
-describe Chef::Audit::AuditReporter do
-
- let(:rest) { double("rest") }
- let(:reporter) { described_class.new(rest) }
- let(:node) { double("node", name: "sofreshsoclean") }
- let(:run_id) { 0 }
- let(:start_time) { Time.new(2014, 12, 3, 9, 31, 05, "-08:00") }
- let(:end_time) { Time.new(2014, 12, 3, 9, 36, 14, "-08:00") }
- let(:run_status) do
- instance_double(Chef::RunStatus, node: node, run_id: run_id,
- start_time: start_time, end_time: end_time) end
-
- describe "#audit_phase_start" do
-
- it "notifies audit phase start to trace log" do
- expect(Chef::Log).to receive(:trace).with(/Audit Reporter starting/)
- reporter.audit_phase_start(run_status)
- end
-
- it "initializes an AuditData object" do
- expect(Chef::Audit::AuditData).to receive(:new).with(run_status.node.name, run_status.run_id)
- reporter.audit_phase_start(run_status)
- end
-
- it "saves the run status" do
- reporter.audit_phase_start(run_status)
- expect(reporter.instance_variable_get(:@run_status)).to eq run_status
- end
- end
-
- describe "#run_completed" do
-
- let(:audit_data) { Chef::Audit::AuditData.new(node.name, run_id) }
- let(:run_data) { audit_data.to_h }
-
- before do
- allow(reporter).to receive(:auditing_enabled?).and_return(true)
- allow(reporter).to receive(:run_status).and_return(run_status)
- allow(rest).to receive(:post).and_return(true)
- allow(reporter).to receive(:audit_data).and_return(audit_data)
- allow(reporter).to receive(:run_status).and_return(run_status)
- allow(audit_data).to receive(:to_h).and_return(run_data)
- end
-
- describe "a successful run with auditing enabled" do
- it "sets run start and end times" do
- iso_start_time = "2014-12-03T17:31:05Z"
- iso_end_time = "2014-12-03T17:36:14Z"
-
- reporter.run_completed(node)
- expect(audit_data.start_time).to eq iso_start_time
- expect(audit_data.end_time).to eq iso_end_time
- end
-
- it "posts audit data to server endpoint" do
- headers = {
- "X-Ops-Audit-Report-Protocol-Version" => Chef::Audit::AuditReporter::PROTOCOL_VERSION,
- }
-
- expect(rest).to receive(:post)
- .with("controls", run_data, headers)
- reporter.run_completed(node)
- end
-
- context "when audit phase failed" do
-
- let(:audit_error) do
- double("AuditError", class: "Chef::Exceptions::AuditError",
- message: "Audit phase failed with error message: derpderpderp",
- backtrace: ["/path/recipe.rb:57", "/path/library.rb:106"]) end
-
- before do
- reporter.instance_variable_set(:@audit_phase_error, audit_error)
- end
-
- it "reports an error" do
- reporter.run_completed(node)
- expect(run_data).to have_key(:error)
- expect(run_data).to have_key(:error)
- expect(run_data[:error]).to eq <<~EOM.strip!
- Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
- /path/recipe.rb:57
- /path/library.rb:106
- EOM
- end
-
- end
-
- context "when unable to post to server" do
-
- let(:error) do
- e = StandardError.new
- e.set_backtrace(caller)
- e
- end
-
- before do
- expect(rest).to receive(:post).and_raise(error)
- allow(error).to receive(:respond_to?).and_call_original
- end
-
- context "the error is an http error" do
-
- let(:response) { double("response", code: code) }
-
- before do
- expect(Chef::Log).to receive(:trace).with(/Sending audit report/)
- expect(Chef::Log).to receive(:trace).with(/Audit Report/)
- allow(error).to receive(:response).and_return(response)
- expect(error).to receive(:respond_to?).with(:response).and_return(true)
- end
-
- context "when the code is 404" do
-
- let(:code) { "404" }
-
- it "logs that the server doesn't support audit reporting" do
- expect(Chef::Log).to receive(:trace).with(/Server doesn't support audit reporting/)
- reporter.run_completed(node)
- end
- end
-
- shared_examples "non-404 error code" do
-
- it "saves the error report" do
- expect(Chef::FileCache).to receive(:store)
- .with("failed-audit-data.json", an_instance_of(String), 0640)
- .and_return(true)
- expect(Chef::FileCache).to receive(:load)
- .with("failed-audit-data.json", false)
- .and_return(true)
- expect(Chef::Log).to receive(:error).with(/Failed to post audit report to server/)
- reporter.run_completed(node)
- end
-
- end
-
- context "when the code is not 404" do
- include_examples "non-404 error code" do
- let(:code) { "505" }
- end
- end
-
- context "when there is no code" do
- include_examples "non-404 error code" do
- let(:code) { nil }
- end
- end
-
- end
-
- context "the error is not an http error" do
-
- it "logs the error" do
- expect(error).to receive(:respond_to?).with(:response).and_return(false)
- expect(Chef::Log).to receive(:error).with(/Failed to post audit report to server/)
- reporter.run_completed(node)
- end
-
- end
-
- context "when reporting url fatals are enabled" do
-
- before do
- allow(Chef::Config).to receive(:[])
- .with(:enable_reporting_url_fatals)
- .and_return(true)
- end
-
- it "raises the error" do
- expect(error).to receive(:respond_to?).with(:response).and_return(false)
- allow(Chef::Log).to receive(:error).and_return(true)
- expect(Chef::Log).to receive(:error).with(/Reporting fatals enabled. Aborting run./)
- expect { reporter.run_completed(node) }.to raise_error(error)
- end
-
- end
- end
- end
-
- context "when auditing is not enabled" do
-
- before do
- allow(Chef::Log).to receive(:trace)
- end
-
- it "doesn't send reports" do
- expect(reporter).to receive(:auditing_enabled?).and_return(false)
- expect(Chef::Log).to receive(:trace).with("Audit Reports are disabled. Skipping sending reports.")
- reporter.run_completed(node)
- end
-
- end
-
- context "when the run fails before audits" do
-
- before do
- allow(Chef::Log).to receive(:trace)
- end
-
- it "doesn't send reports" do
- expect(reporter).to receive(:auditing_enabled?).and_return(true)
- expect(reporter).to receive(:run_status).and_return(nil)
- expect(Chef::Log).to receive(:trace).with("Run failed before audit mode was initialized, not sending audit report to server")
- reporter.run_completed(node)
- end
-
- end
- end
-
- describe "#run_failed" do
-
- let(:audit_data) { Chef::Audit::AuditData.new(node.name, run_id) }
- let(:run_data) { audit_data.to_h }
-
- let(:audit_error) do
- double("AuditError", class: "Chef::Exceptions::AuditError",
- message: "Audit phase failed with error message: derpderpderp",
- backtrace: ["/path/recipe.rb:57", "/path/library.rb:106"]) end
-
- let(:run_error) do
- double("RunError", class: "Chef::Exceptions::RunError",
- message: "This error shouldn't be reported.",
- backtrace: ["fix it", "fix it", "fix it"]) end
-
- before do
- allow(reporter).to receive(:auditing_enabled?).and_return(true)
- allow(reporter).to receive(:run_status).and_return(run_status)
- allow(reporter).to receive(:audit_data).and_return(audit_data)
- allow(audit_data).to receive(:to_h).and_return(run_data)
- end
-
- context "when no prior exception is stored" do
- it "reports no error" do
- expect(rest).to receive(:post)
- reporter.run_failed(run_error)
- expect(run_data).to_not have_key(:error)
- end
- end
-
- context "when some prior exception is stored" do
- before do
- reporter.instance_variable_set(:@audit_phase_error, audit_error)
- end
-
- it "reports the prior error" do
- expect(rest).to receive(:post)
- reporter.run_failed(run_error)
- expect(run_data).to have_key(:error)
- expect(run_data[:error]).to eq <<~EOM.strip!
- Chef::Exceptions::AuditError: Audit phase failed with error message: derpderpderp
- /path/recipe.rb:57
- /path/library.rb:106
- EOM
- end
- end
- end
-
- shared_context "audit data" do
-
- let(:control_group_foo) do
- instance_double(Chef::Audit::ControlGroupData,
- metadata: double("foo metadata")) end
- let(:control_group_bar) do
- instance_double(Chef::Audit::ControlGroupData,
- metadata: double("bar metadata")) end
-
- let(:ordered_control_groups) do
- {
- "foo" => control_group_foo,
- "bar" => control_group_bar,
- }
- end
-
- let(:audit_data) do
- instance_double(Chef::Audit::AuditData,
- add_control_group: true) end
-
- let(:run_context) do
- instance_double(Chef::RunContext,
- audits: ordered_control_groups) end
-
- before do
- allow(reporter).to receive(:ordered_control_groups).and_return(ordered_control_groups)
- allow(reporter).to receive(:audit_data).and_return(audit_data)
- allow(reporter).to receive(:run_status).and_return(run_status)
- allow(run_status).to receive(:run_context).and_return(run_context)
- end
- end
-
- describe "#audit_phase_complete" do
- include_context "audit data"
-
- it "notifies audit phase finished to trace log" do
- expect(Chef::Log).to receive(:trace).with(/Audit Reporter completed/)
- reporter.audit_phase_complete("Output from audit mode")
- end
-
- it "collects audit data" do
- ordered_control_groups.each_value do |group|
- expect(audit_data).to receive(:add_control_group).with(group)
- end
- reporter.audit_phase_complete("Output from audit mode")
- end
- end
-
- describe "#audit_phase_failed" do
- include_context "audit data"
-
- let(:error) { double("Exception") }
-
- it "notifies audit phase failed to trace log" do
- expect(Chef::Log).to receive(:trace).with(/Audit Reporter failed/)
- reporter.audit_phase_failed(error, "Output from audit mode")
- end
-
- it "collects audit data" do
- ordered_control_groups.each_value do |group|
- expect(audit_data).to receive(:add_control_group).with(group)
- end
- reporter.audit_phase_failed(error, "Output from audit mode")
- end
- end
-
- describe "#control_group_started" do
- include_context "audit data"
-
- let(:name) { "bat" }
- let(:control_group) do
- instance_double(Chef::Audit::ControlGroupData,
- metadata: double("metadata")) end
-
- before do
- allow(Chef::Audit::ControlGroupData).to receive(:new)
- .with(name, control_group.metadata)
- .and_return(control_group)
- end
-
- it "stores the control group" do
- expect(ordered_control_groups).to receive(:key?).with(name).and_return(false)
- allow(run_context.audits).to receive(:[]).with(name).and_return(control_group)
- expect(ordered_control_groups).to receive(:store)
- .with(name, control_group)
- .and_call_original
- reporter.control_group_started(name)
- expect(ordered_control_groups[name]).to eq control_group
- end
-
- context "when a control group with the same name has been seen" do
- it "raises an exception" do
- expect(ordered_control_groups).to receive(:key?).with(name).and_return(true)
- expect { reporter.control_group_started(name) }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
- end
- end
- end
-
- describe "#control_example_success" do
- include_context "audit data"
-
- let(:name) { "foo" }
- let(:example_data) { double("example data") }
-
- it "notifies the control group the example succeeded" do
- expect(control_group_foo).to receive(:example_success).with(example_data)
- reporter.control_example_success(name, example_data)
- end
- end
-
- describe "#control_example_failure" do
- include_context "audit data"
-
- let(:name) { "bar" }
- let(:example_data) { double("example data") }
- let(:error) { double("Exception", message: "oopsie") }
-
- it "notifies the control group the example failed" do
- expect(control_group_bar).to receive(:example_failure)
- .with(example_data, error.message)
- reporter.control_example_failure(name, example_data, error)
- end
- end
-
- describe "#auditing_enabled?" do
- shared_examples "enabled?" do |true_or_false|
-
- it "returns #{true_or_false}" do
- expect(Chef::Config).to receive(:[])
- .with(:audit_mode)
- .and_return(audit_setting)
- expect(reporter.auditing_enabled?).to be true_or_false
- end
- end
-
- context "when auditing is disabled" do
- include_examples "enabled?", false do
- let(:audit_setting) { :disabled }
- end
- end
-
- context "when auditing in audit-only mode" do
- include_examples "enabled?", true do
- let(:audit_setting) { :audit_only }
- end
- end
-
- context "when auditing is enabled" do
- include_examples "enabled?", true do
- let(:audit_setting) { :enabled }
- end
- end
- end
-
-end
diff --git a/spec/unit/audit/control_group_data_spec.rb b/spec/unit/audit/control_group_data_spec.rb
deleted file mode 100644
index e8af8be90d..0000000000
--- a/spec/unit/audit/control_group_data_spec.rb
+++ /dev/null
@@ -1,482 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@chef.io>)
-#
-# Copyright:: Copyright 2014-2018, Chef Software Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "securerandom"
-
-describe Chef::Audit::AuditData do
-
- let(:node_name) { "noodles" }
- let(:run_id) { SecureRandom.uuid }
- let(:audit_data) { described_class.new(node_name, run_id) }
-
- let(:control_group_1) { double("control group 1") }
- let(:control_group_2) { double("control group 2") }
-
- describe "#add_control_group" do
- context "when no control groups have been added" do
- it "stores the control group" do
- audit_data.add_control_group(control_group_1)
- expect(audit_data.control_groups).to include(control_group_1)
- end
-
- end
-
- context "when adding additional control groups" do
-
- before do
- audit_data.add_control_group(control_group_1)
- end
-
- it "stores the control group" do
- audit_data.add_control_group(control_group_2)
- expect(audit_data.control_groups).to include(control_group_2)
- end
-
- it "stores all control groups" do
- audit_data.add_control_group(control_group_2)
- expect(audit_data.control_groups).to include(control_group_1)
- end
- end
- end
-
- describe "#to_h" do
-
- let(:audit_data_hash) { audit_data.to_h }
-
- it "returns a hash" do
- expect(audit_data_hash).to be_a(Hash)
- end
-
- it "describes a Chef::Audit::AuditData object" do
- keys = [:node_name, :run_id, :start_time, :end_time, :control_groups]
- expect(audit_data_hash.keys).to match_array(keys)
- end
-
- describe ":control_groups" do
-
- let(:control_hash_1) { { name: "control group 1" } }
- let(:control_hash_2) { { name: "control group 2" } }
-
- let(:control_groups) { audit_data_hash[:control_groups] }
-
- context "with no control groups added" do
- it "is an empty list" do
- expect(control_groups).to eq []
- end
- end
-
- context "with one control group added" do
-
- before do
- allow(audit_data).to receive(:control_groups).and_return([control_group_1])
- end
-
- it "is a one-element list containing the control group hash" do
- expect(control_group_1).to receive(:to_h).once.and_return(control_hash_1)
- expect(control_groups.size).to eq 1
- expect(control_groups).to include(control_hash_1)
- end
- end
-
- context "with multiple control groups added" do
-
- before do
- allow(audit_data).to receive(:control_groups).and_return([control_group_1, control_group_2])
- end
-
- it "is a list of control group hashes" do
- expect(control_group_1).to receive(:to_h).and_return(control_hash_1)
- expect(control_group_2).to receive(:to_h).and_return(control_hash_2)
- expect(control_groups.size).to eq 2
- expect(control_groups).to include(control_hash_1)
- expect(control_groups).to include(control_hash_2)
- end
- end
- end
- end
-end
-
-describe Chef::Audit::ControlData do
-
- let(:name) { "ramen" }
- let(:resource_type) { double("Service") }
- let(:resource_name) { "mysql" }
- let(:context) { nil }
- let(:line_number) { 27 }
-
- let(:control_data) do
- described_class.new(name: name,
- resource_type: resource_type, resource_name: resource_name,
- context: context, line_number: line_number) end
-
- describe "#to_h" do
-
- let(:control_data_hash) { control_data.to_h }
-
- it "returns a hash" do
- expect(control_data_hash).to be_a(Hash)
- end
-
- it "describes a Chef::Audit::ControlData object" do
- keys = [:name, :resource_type, :resource_name, :context, :status, :details]
- expect(control_data_hash.keys).to match_array(keys)
- end
-
- context "when context is nil" do
-
- it "sets :context to an empty array" do
- expect(control_data_hash[:context]).to eq []
- end
-
- end
-
- context "when context is non-nil" do
-
- let(:context) { ["outer"] }
-
- it "sets :context to its value" do
- expect(control_data_hash[:context]).to eq context
- end
- end
- end
-end
-
-describe Chef::Audit::ControlGroupData do
-
- let(:name) { "balloon" }
- let(:control_group_data) { described_class.new(name) }
-
- shared_context "control data" do
-
- let(:name) { "" }
- let(:resource_type) { nil }
- let(:resource_name) { nil }
- let(:context) { nil }
- let(:line_number) { 0 }
-
- let(:control_data) do
- {
- name: name,
- resource_type: resource_type,
- resource_name: resource_name,
- context: context,
- line_number: line_number,
- }
- end
-
- end
-
- shared_context "control" do
- include_context "control data"
-
- let(:control) do
- Chef::Audit::ControlData.new(name: name,
- resource_type: resource_type, resource_name: resource_name,
- context: context, line_number: line_number) end
-
- before do
- allow(Chef::Audit::ControlData).to receive(:new)
- .with(name: name, resource_type: resource_type,
- resource_name: resource_name, context: context,
- line_number: line_number)
- .and_return(control)
- end
- end
-
- describe "#new" do
- it "has status \"success\"" do
- expect(control_group_data.status).to eq "success"
- end
- end
-
- describe "#example_success" do
- include_context "control"
-
- def notify_success
- control_group_data.example_success(control_data)
- end
-
- it "increments the number of successful audits" do
- num_success = control_group_data.number_succeeded
- notify_success
- expect(control_group_data.number_succeeded).to eq (num_success + 1)
- end
-
- it "does not increment the number of failed audits" do
- num_failed = control_group_data.number_failed
- notify_success
- expect(control_group_data.number_failed).to eq (num_failed)
- end
-
- it "marks the audit's status as success" do
- notify_success
- expect(control.status).to eq "success"
- end
-
- it "does not modify its own status" do
- expect(control_group_data).to_not receive(:status=)
- status = control_group_data.status
- notify_success
- expect(control_group_data.status).to eq status
- end
-
- it "saves the control" do
- controls = control_group_data.controls
- expect(controls).to_not include(control)
- notify_success
- expect(controls).to include(control)
- end
- end
-
- describe "#example_failure" do
- include_context "control"
-
- let(:details) { "poop" }
-
- def notify_failure
- control_group_data.example_failure(control_data, details)
- end
-
- it "does not increment the number of successful audits" do
- num_success = control_group_data.number_succeeded
- notify_failure
- expect(control_group_data.number_succeeded).to eq num_success
- end
-
- it "increments the number of failed audits" do
- num_failed = control_group_data.number_failed
- notify_failure
- expect(control_group_data.number_failed).to eq (num_failed + 1)
- end
-
- it "marks the audit's status as failure" do
- notify_failure
- expect(control.status).to eq "failure"
- end
-
- it "marks its own status as failure" do
- notify_failure
- expect(control_group_data.status).to eq "failure"
- end
-
- it "saves the control" do
- controls = control_group_data.controls
- expect(controls).to_not include(control)
- notify_failure
- expect(controls).to include(control)
- end
-
- context "when details are not provided" do
-
- let(:details) { nil }
-
- it "does not save details to the control" do
- default_details = control.details
- expect(control).to_not receive(:details=)
- notify_failure
- expect(control.details).to eq default_details
- end
- end
-
- context "when details are provided" do
-
- let(:details) { "yep that didn't work" }
-
- it "saves details to the control" do
- notify_failure
- expect(control.details).to eq details
- end
- end
- end
-
- shared_examples "multiple audits" do |success_or_failure|
- include_context "control"
-
- let(:num_success) { 0 }
- let(:num_failure) { 0 }
-
- before do
- if num_failure == 0
- num_success.times { control_group_data.example_success(control_data) }
- elsif num_success == 0
- num_failure.times { control_group_data.example_failure(control_data, nil) }
- end
- end
-
- it "counts the number of successful audits" do
- expect(control_group_data.number_succeeded).to eq num_success
- end
-
- it "counts the number of failed audits" do
- expect(control_group_data.number_failed).to eq num_failure
- end
-
- it "marks its status as \"#{success_or_failure}\"" do
- expect(control_group_data.status).to eq success_or_failure
- end
- end
-
- context "when all audits pass" do
- include_examples "multiple audits", "success" do
- let(:num_success) { 3 }
- end
- end
-
- context "when one audit fails" do
- shared_examples "mixed audit results" do
- include_examples "multiple audits", "failure" do
-
- let(:audit_results) { [] }
- let(:num_success) { audit_results.count("success") }
- let(:num_failure) { 1 }
-
- before do
- audit_results.each do |result|
- if result == "success"
- control_group_data.example_success(control_data)
- else
- control_group_data.example_failure(control_data, nil)
- end
- end
- end
- end
- end
-
- context "and it's the first audit" do
- include_examples "mixed audit results" do
- let(:audit_results) { %w{failure success success} }
- end
- end
-
- context "and it's an audit in the middle" do
- include_examples "mixed audit results" do
- let(:audit_results) { %w{success failure success} }
- end
- end
-
- context "and it's the last audit" do
- include_examples "mixed audit results" do
- let(:audit_results) { %w{success success failure} }
- end
- end
- end
-
- context "when all audits fail" do
- include_examples "multiple audits", "failure" do
- let(:num_failure) { 3 }
- end
- end
-
- describe "#to_h" do
-
- let(:control_group_data_hash) { control_group_data.to_h }
-
- it "returns a hash" do
- expect(control_group_data_hash).to be_a(Hash)
- end
-
- it "describes a Chef::Audit::ControlGroupData object" do
- keys = [:name, :status, :number_succeeded, :number_failed,
- :controls, :id]
- expect(control_group_data_hash.keys).to match_array(keys)
- end
-
- describe ":controls" do
-
- let(:control_group_controls) { control_group_data_hash[:controls] }
-
- context "with no controls added" do
- it "is an empty list" do
- expect(control_group_controls).to eq []
- end
- end
-
- context "with one control added" do
- include_context "control"
-
- let(:control_list) { [control_data] }
- let(:control_hash) { control.to_h }
-
- before do
- expect(control_group_data).to receive(:controls).twice.and_return(control_list)
- expect(control_data).to receive(:to_h).and_return(control_hash)
- end
-
- it "is a one-element list containing the control hash" do
- expect(control_group_controls.size).to eq 1
- expect(control_group_controls).to include(control_hash)
- end
-
- it "adds a sequence number to the control" do
- control_group_data.to_h
- expect(control_hash).to have_key(:sequence_number)
- end
-
- end
-
- context "with multiple controls added" do
-
- let(:control_hash_1) { { line_number: 27 } }
- let(:control_hash_2) { { line_number: 13 } }
- let(:control_hash_3) { { line_number: 35 } }
-
- let(:control_1) do
- double("control 1",
- line_number: control_hash_1[:line_number],
- to_h: control_hash_1) end
- let(:control_2) do
- double("control 2",
- line_number: control_hash_2[:line_number],
- to_h: control_hash_2) end
- let(:control_3) do
- double("control 3",
- line_number: control_hash_3[:line_number],
- to_h: control_hash_3) end
-
- let(:control_list) { [control_1, control_2, control_3] }
- let(:ordered_control_hashes) { [control_hash_2, control_hash_1, control_hash_3] }
-
- before do
- # Another way to do this would be to call #example_success
- # or #example_failure per control hash, but we'd have to
- # then stub #create_control and it's a lot of extra stubbing work.
- # We can't stub the controls reader to return a list of
- # controls because of the call to sort! and the following
- # reading of controls.
- control_group_data.instance_variable_set(:@controls, control_list)
- end
-
- it "is a list of control group hashes ordered by line number" do
- expect(control_group_controls.size).to eq 3
- expect(control_group_controls).to eq ordered_control_hashes
- end
-
- it "assigns sequence numbers in order" do
- control_group_data.to_h
- ordered_control_hashes.each_with_index do |control_hash, idx|
- expect(control_hash[:sequence_number]).to eq idx + 1
- end
- end
- end
- end
- end
-
-end
diff --git a/spec/unit/audit/logger_spec.rb b/spec/unit/audit/logger_spec.rb
deleted file mode 100644
index 51a32d906e..0000000000
--- a/spec/unit/audit/logger_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-
-describe Chef::Audit::Logger do
-
- before(:each) do
- Chef::Audit::Logger.instance_variable_set(:@buffer, nil)
- end
-
- it "calling puts creates @buffer and adds the message" do
- Chef::Audit::Logger.puts("Output message")
- expect(Chef::Audit::Logger.read_buffer).to eq("Output message\n")
- end
-
- it "calling puts multiple times adds to the message" do
- Chef::Audit::Logger.puts("Output message")
- Chef::Audit::Logger.puts("Output message")
- Chef::Audit::Logger.puts("Output message")
- expect(Chef::Audit::Logger.read_buffer).to eq("Output message\nOutput message\nOutput message\n")
- end
-
- it "calling it before @buffer is set returns an empty string" do
- expect(Chef::Audit::Logger.read_buffer).to eq("")
- end
-
-end
diff --git a/spec/unit/audit/rspec_formatter_spec.rb b/spec/unit/audit/rspec_formatter_spec.rb
deleted file mode 100644
index 8c266fbb8b..0000000000
--- a/spec/unit/audit/rspec_formatter_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Author:: Claire McQuin (<claire@chef.io>)
-#
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "chef/audit/rspec_formatter"
-
-describe Chef::Audit::RspecFormatter do
- let(:formatter) { Chef::Audit::RspecFormatter.new(nil) }
- it "should respond to close" do
- expect(formatter).to respond_to(:close)
- end
-end
diff --git a/spec/unit/audit/runner_spec.rb b/spec/unit/audit/runner_spec.rb
deleted file mode 100644
index 902ede62ed..0000000000
--- a/spec/unit/audit/runner_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-#
-# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
-# License:: Apache License, Version 2.0
-#
-# 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.
-#
-
-require "spec_helper"
-require "rspec/core/sandbox"
-require "chef/audit/runner"
-require "chef/audit/audit_event_proxy"
-require "chef/audit/rspec_formatter"
-require "rspec/support/spec/in_sub_process"
-require "rspec/support/spec/stderr_splitter"
-
-describe Chef::Audit::Runner do
- include RSpec::Support::InSubProcess
-
- let(:events) { double("events") }
- let(:run_context) { instance_double(Chef::RunContext, events: events) }
- let(:runner) { Chef::Audit::Runner.new(run_context) }
-
- around(:each) do |ex|
- RSpec::Core::Sandbox.sandboxed { ex.run }
- end
-
- context "when we run in audit mode" do
- let(:paths) { [ "/opt/chef/lib/chef/", 'C:\windows/here/lib/chef/' , "/opt/chef/extra/folders/lib/chef/"] }
- it "excludes the current path from backtrace" do
- paths.each do |path|
- expect(runner.exclusion_pattern).to match(path)
- end
- end
- end
-
- describe "#initialize" do
- it "correctly sets the run_context during initialization" do
- expect(runner.instance_variable_get(:@run_context)).to eq(run_context)
- end
- end
-
- context "during #run" do
-
- describe "#setup" do
- let(:log_location) { File.join(Dir.tmpdir, "audit_log") }
- let(:color) { false }
-
- before do
- Chef::Config[:log_location] = log_location
- Chef::Config[:color] = color
- end
-
- it "sets all the config values" do
- # This runs the Serverspec includes - we don't want these hanging around in all subsequent tests so
- # we run this in a forked process. Keeps Serverspec files from getting loaded into main process.
- in_sub_process do
- runner.send(:setup)
-
- expect(RSpec.configuration.output_stream).to eq(Chef::Audit::Logger)
- expect(RSpec.configuration.error_stream).to eq(Chef::Audit::Logger)
-
- expect(RSpec.configuration.formatters.size).to eq(2)
- expect(RSpec.configuration.formatters).to include(instance_of(Chef::Audit::AuditEventProxy))
- expect(RSpec.configuration.formatters).to include(instance_of(Chef::Audit::RspecFormatter))
- expect(Chef::Audit::AuditEventProxy.class_variable_get(:@@events)).to eq(run_context.events)
-
- expect(RSpec.configuration.expectation_frameworks).to eq([RSpec::Matchers])
- expect(RSpec::Matchers.configuration.syntax).to eq([:expect])
-
- expect(RSpec.configuration.color).to eq(color)
- expect(RSpec.configuration.expose_dsl_globally?).to eq(false)
- expect(RSpec.configuration.backtrace_exclusion_patterns).to include(runner.exclusion_pattern)
-
- expect(Specinfra.configuration.backend).to eq(:exec)
- end
- end
- end
-
- describe "#register_control_groups" do
- let(:audits) { [] }
- let(:run_context) { instance_double(Chef::RunContext, audits: audits) }
-
- it "adds the control group aliases" do
- runner.send(:register_control_groups)
-
- expect(RSpec::Core::DSL.example_group_aliases).to include(:__control_group__)
- expect(RSpec::Core::DSL.example_group_aliases).to include(:control)
- end
-
- context "audits exist" do
- let(:audits) { { "audit_name" => group } }
- let(:group) { Struct.new(:args, :block).new(["group_name"], nil) }
-
- it "sends the audits to the world" do
- runner.send(:register_control_groups)
-
- expect(RSpec.world.example_groups.size).to eq(1)
- # For whatever reason, `kind_of` is not working
- # expect(RSpec.world.example_groups).to include(kind_of(RSpec::Core::ExampleGroup)) => FAIL
- g = RSpec.world.example_groups[0]
- expect(g.ancestors).to include(RSpec::Core::ExampleGroup)
- expect(g.description).to eq("group_name")
- end
- end
- end
-
- describe "#do_run" do
- let(:rspec_runner) { instance_double(RSpec::Core::Runner) }
-
- it "executes the runner" do
- expect(RSpec::Core::Runner).to receive(:new).with(nil).and_return(rspec_runner)
- expect(rspec_runner).to receive(:run_specs).with([])
-
- runner.send(:do_run)
- end
- end
- end
-
- describe "counters" do
- it "correctly calculates failed?" do
- expect(runner.failed?).to eq(false)
- end
-
- it "correctly calculates num_failed" do
- expect(runner.num_failed).to eq(0)
- end
-
- it "correctly calculates num_total" do
- expect(runner.num_total).to eq(0)
- end
- end
-
-end
diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb
index 370d5d34e7..6fb5a7df64 100644
--- a/spec/unit/client_spec.rb
+++ b/spec/unit/client_spec.rb
@@ -108,8 +108,7 @@ shared_context "a client run" do
let(:http_node_save) { double("Chef::ServerAPI (node save)") }
let(:reporting_rest_client) { double("Chef::ServerAPI (reporting client)") }
- let(:runner) { instance_double("Chef::Runner") }
- let(:audit_runner) { instance_double("Chef::Audit::Runner", failed?: false) }
+ let(:runner) { instance_double("Chef::Runner") }
def stub_for_register
# --Client.register
@@ -131,7 +130,6 @@ shared_context "a client run" do
expect(client.events).to receive(:register).with(instance_of(Chef::DataCollector::Reporter))
expect(client.events).to receive(:register).with(instance_of(Chef::ResourceReporter))
expect(client.events).to receive(:register).with(instance_of(Chef::ActionCollection))
- expect(client.events).to receive(:register).with(instance_of(Chef::Audit::AuditReporter))
end
def stub_for_node_load
@@ -174,10 +172,6 @@ shared_context "a client run" do
# define me
end
- def stub_for_audit
- # define me
- end
-
def stub_for_node_save
# define me
end
@@ -190,7 +184,6 @@ shared_context "a client run" do
Chef::Config[:client_fork] = enable_fork
Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef"
Chef::Config[:why_run] = false
- Chef::Config[:audit_mode] = :enabled
Chef::Config[:chef_guid] = "default-guid"
stub_rest_clean
@@ -200,7 +193,6 @@ shared_context "a client run" do
stub_for_sync_cookbooks
stub_for_required_recipe
stub_for_converge
- stub_for_audit
stub_for_node_save
expect_any_instance_of(Chef::RunLock).to receive(:acquire)
@@ -248,52 +240,6 @@ shared_context "converge failed" do
end
end
-shared_context "audit phase completed" do
- def stub_for_audit
- # -- Client#run_audits
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(audit_runner).to receive(:run).and_return(true)
- expect(client.events).to receive(:audit_phase_complete)
- end
-end
-
-shared_context "audit phase failed with error" do
- let(:audit_error) do
- err = RuntimeError.new("Unexpected audit error")
- err.set_backtrace([ "/path/recipe.rb:57", "/path/recipe.rb:55" ])
- err
- end
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
- expect(audit_runner).to receive(:run).and_raise(audit_error)
- expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
- end
-end
-
-shared_context "audit phase completed with failed controls" do
- let(:audit_runner) do
- instance_double("Chef::Audit::Runner", failed?: true,
- num_failed: 1, num_total: 3) end
-
- let(:audit_error) do
- err = Chef::Exceptions::AuditsFailed.new(audit_runner.num_failed, audit_runner.num_total)
- err.set_backtrace([ "/path/recipe.rb:108", "/path/recipe.rb:103" ])
- err
- end
-
- def stub_for_audit
- expect(Chef::Audit::Runner).to receive(:new).and_return(audit_runner)
- expect(Chef::Audit::Logger).to receive(:read_buffer).and_return("Audit mode output!")
- expect(audit_runner).to receive(:run)
- expect(Chef::Exceptions::AuditsFailed).to receive(:new).with(
- audit_runner.num_failed, audit_runner.num_total
- ).and_return(audit_error)
- expect(client.events).to receive(:audit_phase_failed).with(audit_error, "Audit mode output!")
- end
-end
-
shared_context "run completed" do
def stub_for_run
expect(client).to receive(:run_completed_successfully)
@@ -306,7 +252,7 @@ shared_context "run failed" do
end
before do
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
+ expect(Chef::Application).to receive(:debug_stacktrace).with(converge_error)
end
end
@@ -318,7 +264,7 @@ end
shared_examples "a completed run" do
include_context "run completed"
- it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges, and runs audits" do
+ it "runs ohai, sets up authentication, loads node state, synchronizes policy, converges" do
# This is what we're testing.
expect(client.run).to be true
@@ -328,39 +274,11 @@ shared_examples "a completed run" do
end
end
-shared_examples "a completed run with audit failure" do
- include_context "run completed"
-
- before do
- expect(Chef::Application).to receive(:debug_stacktrace).with an_instance_of(Chef::Exceptions::RunFailedWrappingError)
- end
-
- it "converges, runs audits, saves the node and raises the error in a wrapping error" do
- expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq(run_errors.size)
- run_errors.each do |run_error|
- expect(error.wrapped_errors).to include(run_error)
- expect(error.backtrace).to include(*run_error.backtrace)
- end
- end
-
- # fork is stubbed, so we can see the outcome of the run
- expect(node.automatic_attrs[:platform]).to eq(platform)
- expect(node.automatic_attrs[:platform_version]).to eq(platform_version)
- end
-end
-
shared_examples "a failed run" do
include_context "run failed"
it "skips node save and raises the error in a wrapping error" do
- expect { client.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq(run_errors.size)
- run_errors.each do |run_error|
- expect(error.wrapped_errors).to include(run_error)
- expect(error.backtrace).to include(*run_error.backtrace)
- end
- end
+ expect { client.run }.to raise_error(converge_error)
end
end
@@ -497,7 +415,6 @@ describe Chef::Client do
shared_examples_for "a successful client run" do
include_context "a client run"
include_context "converge completed"
- include_context "audit phase completed"
include_examples "a completed run"
end
@@ -577,51 +494,13 @@ describe Chef::Client do
describe "when converge completes successfully" do
include_context "a client run"
include_context "converge completed"
- context "when audit mode is enabled" do
- describe "when audit phase errors" do
- include_context "audit phase failed with error"
- include_examples "a completed run with audit failure" do
- let(:run_errors) { [audit_error] }
- end
- end
-
- describe "when audit phase completed" do
- include_context "audit phase completed"
- include_examples "a completed run"
- end
-
- describe "when audit phase completed with failed controls" do
- include_context "audit phase completed with failed controls"
- include_examples "a completed run with audit failure" do
- let(:run_errors) { [audit_error] }
- end
- end
- end
end
describe "when converge errors" do
include_context "a client run"
include_context "converge failed"
-
- describe "when audit phase errors" do
- include_context "audit phase failed with error"
- include_examples "a failed run" do
- let(:run_errors) { [converge_error, audit_error] }
- end
- end
-
- describe "when audit phase completed" do
- include_context "audit phase completed"
- include_examples "a failed run" do
- let(:run_errors) { [converge_error] }
- end
- end
-
- describe "when audit phase completed with failed controls" do
- include_context "audit phase completed with failed controls"
- include_examples "a failed run" do
- let(:run_errors) { [converge_error, audit_error] }
- end
+ include_examples "a failed run" do
+ let(:run_errors) { [converge_error] }
end
end
end
@@ -903,28 +782,5 @@ describe Chef::Client do
# fail on the first thing in begin block
allow_any_instance_of(Chef::RunLock).to receive(:save_pid).and_raise(NoMethodError)
end
-
- context "when audit mode is enabled" do
- before do
- Chef::Config[:audit_mode] = :enabled
- end
- it "should run exception handlers on early fail" do
- expect(subject).to receive(:run_failed)
- expect { subject.run }.to raise_error(Chef::Exceptions::RunFailedWrappingError) do |error|
- expect(error.wrapped_errors.size).to eq 1
- expect(error.wrapped_errors).to include(NoMethodError)
- end
- end
- end
-
- context "when audit mode is disabled" do
- before do
- Chef::Config[:audit_mode] = :disabled
- end
- it "should run exception handlers on early fail" do
- expect(subject).to receive(:run_failed)
- expect { subject.run }.to raise_error(NoMethodError)
- end
- end
end
end
diff --git a/spec/unit/dsl/audit_spec.rb b/spec/unit/dsl/audit_spec.rb
deleted file mode 100644
index e24fbc4589..0000000000
--- a/spec/unit/dsl/audit_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-
-require "spec_helper"
-require "chef/dsl/audit"
-
-class AuditDSLTester < Chef::Recipe
- include Chef::DSL::Audit
-end
-
-class BadAuditDSLTester
- include Chef::DSL::Audit
-end
-
-describe Chef::DSL::Audit do
- let(:auditor) { AuditDSLTester.new("cookbook_name", "recipe_name", run_context) }
- let(:run_context) { instance_double(Chef::RunContext, audits: audits, cookbook_collection: cookbook_collection) }
- let(:audits) { {} }
- let(:cookbook_collection) { {} }
-
- it "raises an error when a block of audits is not provided" do
- expect { auditor.control_group "name" }.to raise_error(Chef::Exceptions::NoAuditsProvided)
- end
-
- it "raises an error when no audit name is given" do
- expect { auditor.control_group {} }.to raise_error(Chef::Exceptions::AuditNameMissing)
- end
-
- context "audits already populated" do
- let(:audits) { { "unique" => {} } }
-
- it "raises an error if the audit name is a duplicate" do
- expect { auditor.control_group("unique") {} }.to raise_error(Chef::Exceptions::AuditControlGroupDuplicate)
- end
- end
-
- context "included in a class without recipe DSL" do
- let(:auditor) { BadAuditDSLTester.new }
-
- it "fails because it relies on the recipe DSL existing" do
- expect { auditor.control_group("unique") {} }.to raise_error(NoMethodError, /undefined method `cookbook_name'/)
- end
- end
-
-end
diff --git a/spec/unit/recipe_spec.rb b/spec/unit/recipe_spec.rb
index 2d5bb81c95..1bc84745ad 100644
--- a/spec/unit/recipe_spec.rb
+++ b/spec/unit/recipe_spec.rb
@@ -577,11 +577,6 @@ describe Chef::Recipe do
end
describe "included DSL" do
- it "should include features from Chef::DSL::Audit" do
- expect(recipe.singleton_class.included_modules).to include(Chef::DSL::Audit)
- expect(recipe.respond_to?(:control_group)).to be true
- end
-
it "should respond to :ps_credential from Chef::DSL::Powershell" do
expect(recipe.respond_to?(:ps_credential)).to be true
end
diff --git a/spec/unit/run_context/child_run_context_spec.rb b/spec/unit/run_context/child_run_context_spec.rb
index be45aaa1cc..a5a4aea4a1 100644
--- a/spec/unit/run_context/child_run_context_spec.rb
+++ b/spec/unit/run_context/child_run_context_spec.rb
@@ -44,13 +44,6 @@ describe Chef::RunContext::ChildRunContext do
expect(child.parent_run_context).to eq run_context
end
- it "audits is not the same as the parent" do
- expect(child.audits.object_id).not_to eq run_context.audits.object_id
- child.audits["hi"] = "lo"
- expect(child.audits["hi"]).to eq("lo")
- expect(run_context.audits["hi"]).not_to eq("lo")
- end
-
it "resource_collection is not the same as the parent" do
expect(child.resource_collection.object_id).not_to eq run_context.resource_collection.object_id
f = Chef::Resource::File.new("hi", child)