class Kitchen::Verifier::InspecKerberos

InSpec verifier for Kitchen.

@author Fletcher Nichol <fnichol@chef.io>

Public Instance Methods

call(state) click to toggle source

(see Base#call)

# File lib/kitchen/verifier/inspec_kerberos.rb, line 64
def call(state)
  logger.debug("Initialize InSpec")

  # gather connection options
  opts = runner_options(instance.transport, state, instance.platform.name, instance.suite.name)

  # add attributes
  opts[:attrs] = config[:attrs]
  opts[:attributes] = Hashie.stringify_keys config[:attributes] unless config[:attributes].nil?

  # setup logger
  ::Inspec::Log.init(STDERR)
  ::Inspec::Log.level = Kitchen::Util.from_logger_level(logger.level)

  # initialize runner
  runner = ::Inspec::Runner.new(opts)

  # add each profile to runner
  tests = collect_tests
  profile_ctx = nil
  tests.each do |target|
    profile_ctx = runner.add_target(target, opts)
  end

  profile_ctx ||= []
  profile_ctx.each do |profile|
    logger.info("Loaded #{profile.name} ")
  end

  exit_code = runner.run
  return if exit_code == 0
  raise ActionFailed, "Inspec Runner returns #{exit_code}"
end
finalize_config!(instance) click to toggle source

A lifecycle method that should be invoked when the object is about ready to be used. A reference to an Instance is required as configuration dependant data may be access through an Instance. This also acts as a hook point where the object may wish to perform other last minute checks, validations, or configuration expansions.

@param instance [Instance] an associated instance @return [self] itself, for use in chaining @raise [ClientError] if instance parameter is nil

Calls superclass method
# File lib/kitchen/verifier/inspec_kerberos.rb, line 47
def finalize_config!(instance)
  super

  # We want to switch kitchen-inspec to look for its tests in
  # `cookbook_dir/test/recipes` instead of `cookbook_dir/test/integration`
  # Unfortunately there is no way to read `test_base_path` from the
  # .kitchen.yml, it can only be provided on the CLI.
  # See https://github.com/test-kitchen/test-kitchen/issues/1077
  inspec_test_dir = File.join(config[:kitchen_root], "test", "recipes")
  if File.directory?(inspec_test_dir)
    config[:test_base_path] = inspec_test_dir
  end

  self
end

Private Instance Methods

collect_tests() click to toggle source

Returns an array of test profiles @return [Array<String>] array of suite directories or remote urls @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 164
def collect_tests
  # get local tests and get run list of profiles
  (local_suite_files + resolve_config_inspec_tests).compact.uniq
end
load_needed_dependencies!() click to toggle source

(see Base#load_needed_dependencies!)

# File lib/kitchen/verifier/inspec_kerberos.rb, line 103
def load_needed_dependencies!
  require "inspec"
  # TODO: this should be easier. I would expect to load a single class here
  # load supermarket plugin, this is part of the inspec gem
  require "bundles/inspec-supermarket/api"
  require "bundles/inspec-supermarket/target"

  # load the compliance plugin
  require "bundles/inspec-compliance/configuration"
  require "bundles/inspec-compliance/support"
  require "bundles/inspec-compliance/http"
  require "bundles/inspec-compliance/api"
  require "bundles/inspec-compliance/target"
end
local_suite_files() click to toggle source

Returns an Array of test suite filenames for the related suite currently residing on the local workstation. Any special provisioner-specific directories (such as a Chef roles/ directory) are excluded.

we support the base directories

  • test/integration

  • test/integration/inspec (prefered if used with other test environments)

we do not filter for specific directories, this is core of inspec

@return [Array<String>] array of suite directories @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 130
def local_suite_files
  base = File.join(config[:test_base_path], config[:suite_name])
  legacy_mode = false
  # check for testing frameworks, we may need to add more
  %w{inspec serverspec bats pester rspec cucumber minitest bash}.each do |fw|
    if Pathname.new(File.join(base, fw)).exist?
      logger.info("Detected alternative framework tests for `#{fw}`")
      legacy_mode = true
    end
  end

  base = File.join(base, "inspec") if legacy_mode

  # only return the directory if it exists
  Pathname.new(base).exist? ? [{ :path => base }] : []
end
resolve_config_inspec_tests() click to toggle source

Takes config and modifies any value with a key of :path by adding the full path @return [Array] array of modified hashes @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 150
def resolve_config_inspec_tests
  config[:inspec_tests].map do |test_hash|
    if test_hash.is_a? Hash
      test_hash = { :path => config[:kitchen_root] + "/" + test_hash[:path] } if test_hash.has_key?(:path)
      test_hash
    else
      test_hash # if it's not a hash, just return it as is
    end
  end
end
runner_options(transport, state = {}, platform = nil, suite = nil) click to toggle source

Returns a configuration Hash that can be passed to a `Inspec::Runner`.

@return [Hash] a configuration hash of string-based keys @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 173
def runner_options(transport, state = {}, platform = nil, suite = nil) # rubocop:disable Metrics/AbcSize
  transport_data = transport.diagnose.merge(state)
  if defined?(Kitchen::Transport::Kerberos) && transport.is_a?(Kitchen::Transport::Kerberos)
    runner_options_for_ssh(transport_data, 'kerberos')
  elsif transport.is_a?(Kitchen::Transport::Ssh)
    runner_options_for_ssh(transport_data, 'ssh')
  elsif transport.is_a?(Kitchen::Transport::Winrm)
    runner_options_for_winrm(transport_data)
  # optional transport which is not in core test-kitchen
  elsif defined?(Kitchen::Transport::Dokken) && transport.is_a?(Kitchen::Transport::Dokken)
    runner_options_for_docker(transport_data)
  else
    raise Kitchen::UserError, "Verifier #{name} does not support the #{transport.name} Transport"
  end.tap do |runner_options|
    # default color to true to match InSpec behavior
    runner_options["color"] = (config[:color].nil? ? true : config[:color])
    runner_options["format"] = config[:format] unless config[:format].nil?
    runner_options["output"] = config[:output] % { platform: platform, suite: suite } unless config[:output].nil?
    runner_options["profiles_path"] = config[:profiles_path] unless config[:profiles_path].nil?
    runner_options[:controls] = config[:controls]
  end
end
runner_options_for_docker(config_data) click to toggle source

Returns a configuration Hash that can be passed to a `Inspec::Runner`.

@return [Hash] a configuration hash of string-based keys @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 251
def runner_options_for_docker(config_data)
  kitchen = instance.transport.send(:connection_options, config_data).dup
  #
  # Note: kitchen-dokken uses two containers the
  #  - config_data[:data_container][:Id] : (hosts chef-client)
  #  - config_data[:runner_container][:Id] : (the kitchen-container)
  opts = {
    "backend" => "docker",
    "logger" => logger,
    "host" => config_data[:runner_container][:Id],
    "connection_timeout" => kitchen[:timeout],
    "connection_retries" => kitchen[:connection_retries],
    "connection_retry_sleep" => kitchen[:connection_retry_sleep],
    "max_wait_until_ready" => kitchen[:max_wait_until_ready],
  }
  logger.debug "Connect to Container: #{opts['host']}"
  opts
end
runner_options_for_ssh(config_data, backend = 'ssh') click to toggle source

Returns a configuration Hash that can be passed to a `Inspec::Runner`.

@return [Hash] a configuration hash of string-based keys @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 200
def runner_options_for_ssh(config_data, backend = 'ssh')
  kitchen = instance.transport.send(:connection_options, config_data).dup
  opts = {
    "backend" => backend,
    "logger" => logger,
    # pass-in sudo config from kitchen verifier
    "sudo" => config[:sudo],
    "sudo_command" => config[:sudo_command],
    "sudo_options" => config[:sudo_options],
    "host" => config[:host] || kitchen[:hostname],
    "port" => config[:port] || kitchen[:port],
    "user" => kitchen[:username],
    "keepalive" => kitchen[:keepalive],
    "keepalive_interval" => kitchen[:keepalive_interval],
    "connection_timeout" => kitchen[:timeout],
    "connection_retries" => kitchen[:connection_retries],
    "connection_retry_sleep" => kitchen[:connection_retry_sleep],
    "max_wait_until_ready" => kitchen[:max_wait_until_ready],
    "compression" => kitchen[:compression],
    "compression_level" => kitchen[:compression_level],
    "keys_only" => true,
  }
  opts["key_files"] = kitchen[:keys] unless kitchen[:keys].nil?
  opts["password"] = kitchen[:password] unless kitchen[:password].nil?
  opts
end
runner_options_for_winrm(config_data) click to toggle source

Returns a configuration Hash that can be passed to a `Inspec::Runner`.

@return [Hash] a configuration hash of string-based keys @api private

# File lib/kitchen/verifier/inspec_kerberos.rb, line 231
def runner_options_for_winrm(config_data)
  kitchen = instance.transport.send(:connection_options, config_data).dup
  opts = {
    "backend" => "winrm",
    "logger" => logger,
    "host" => config[:host] || URI(kitchen[:endpoint]).hostname,
    "port" => config[:port] || URI(kitchen[:endpoint]).port,
    "user" => kitchen[:user],
    "password" => kitchen[:password] || kitchen[:pass],
    "connection_retries" => kitchen[:connection_retries],
    "connection_retry_sleep" => kitchen[:connection_retry_sleep],
    "max_wait_until_ready" => kitchen[:max_wait_until_ready],
  }
  opts
end