class Chef::Audit::Runner

Attributes

run_context[R]

Public Class Methods

new(run_context) click to toggle source
# File lib/chef/audit/runner.rb, line 28
def initialize(run_context)
  @run_context = run_context
end

Public Instance Methods

exclusion_pattern() click to toggle source
# File lib/chef/audit/runner.rb, line 50
def exclusion_pattern
  Regexp.new(".+[\\\/]lib[\\\/]chef[\\\/]")
end
failed?() click to toggle source
# File lib/chef/audit/runner.rb, line 38
def failed?
  RSpec.world.reporter.failed_examples.size > 0
end
num_failed() click to toggle source
# File lib/chef/audit/runner.rb, line 42
def num_failed
  RSpec.world.reporter.failed_examples.size
end
num_total() click to toggle source
# File lib/chef/audit/runner.rb, line 46
def num_total
  RSpec.world.reporter.examples.size
end
run() click to toggle source
# File lib/chef/audit/runner.rb, line 32
def run
  setup
  register_control_groups
  do_run
end

Private Instance Methods

add_example_group_methods() click to toggle source

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.
# File lib/chef/audit/runner.rb, line 178
def add_example_group_methods
  RSpec::Core::ExampleGroup.define_example_group_method :__control_group__
  RSpec::Core::ExampleGroup.define_example_group_method :control
end
add_formatters() click to toggle source

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.
# File lib/chef/audit/runner.rb, line 129
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
configure_rspec() click to toggle source

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
# File lib/chef/audit/runner.rb, line 102
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
configure_specinfra() click to toggle source

Set up the backend for Specinfra/Serverspec. :exec is the local system; on Windows, it is :cmd

# File lib/chef/audit/runner.rb, line 148
def configure_specinfra
  if Chef::Platform.windows?
    Specinfra.configuration.backend = :cmd
    Specinfra.configuration.os = { :family => "windows" }
  else
    Specinfra.configuration.backend = :exec
  end
end
disable_should_syntax() click to toggle source

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.

# File lib/chef/audit/runner.rb, line 139
def disable_should_syntax
  RSpec.configure do |config|
    config.expect_with :rspec do |c|
      c.syntax = :expect
    end
  end
end
do_run() click to toggle source

Run the audits!

# File lib/chef/audit/runner.rb, line 184
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
register_control_groups() click to toggle source

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.

# File lib/chef/audit/runner.rb, line 164
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
require_deps() click to toggle source

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.

# File lib/chef/audit/runner.rb, line 81
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
set_streams() click to toggle source

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.

# File lib/chef/audit/runner.rb, line 121
def set_streams
  RSpec.configuration.output_stream = Chef::Audit::Logger
  RSpec.configuration.error_stream = Chef::Audit::Logger
end
setup() click to toggle source

Prepare to run audits:

- Require files
- Configure RSpec
- Configure Specinfra/Serverspec
# File lib/chef/audit/runner.rb, line 60
def setup
  require_deps
  configure_rspec
  configure_specinfra
end