Skip to content

Commit

Permalink
Merge code from Hunner's policy compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
raphink committed Oct 30, 2014
1 parent 997b7d1 commit 668dbd1
Showing 1 changed file with 57 additions and 22 deletions.
79 changes: 57 additions & 22 deletions lib/puppet/indirector/catalog/compiler_spec.rb
Original file line number Diff line number Diff line change
@@ -1,43 +1,78 @@
require 'puppet/node'
require 'puppet/resource/catalog'
require 'puppet/indirector/catalog/compiler'
require 'rubygems'
require 'rspec'
require 'rspec-puppet/errors'
require 'rspec-puppet/matchers'
require 'stringio'
require Puppet.settings[:libdir] + '/spec/catalog'

class Puppet::Resource::Catalog::CompilerSpec < Puppet::Resource::Catalog::Compiler
def compiler
@compiler ||= indirection.terminus(:compiler)
## RSpec catalog helper module to provide `subject` method for specs
module RSpec::Puppet::CatalogExampleGroup
include RSpec::Puppet::ManifestMatchers

def subject
RSpec.configuration.catalog
end

def facts
RSpec.configuration.facts
end
end

class Puppet::Resource::Catalog::CompilerSpec < Puppet::Resource::Catalog::Compiler
desc "Puppet's catalog policy enforcement compiler"

def find(request)
return nil unless catalog = compiler.find(request)
node = node_from_request(request)
manifestdir = Puppet.settings.value(:manifestdir, node.environment)
## Call normal catalog compiler and grab the facts
catalog = super
facts = Puppet::Node::Facts.convert_from(request.options[:facts_format], CGI.unescape(request.options[:facts])).values

# We put specs in the parent directory of :manifestdir
spec_dir = File.join(manifestdir, '..', 'policy/catalog')
spec_dir = File.join(Puppet[:confdir], 'policy/catalog')

RSpec::configure do |c|
c.include(RSpec::Puppet::ManifestMatchers)
end
# Send catalog down the rabbit hole
PuppetSpec::Catalog.setup(catalog)
# Test by classes, including $certname
spec_dirs = []
catalog.classes.each do |c|
class_dir = c.gsub(/:/, '_')
class_path = File.join(spec_dir, "class/#{class_dir}")
spec_dirs << class_path if File.directory? class_path
end
# Use something else than stdout/stderr to get reports?
out = StringIO.new
unless RSpec::Core::Runner::run(["-r#{Puppet.settings[:libdir]}/policy/catalog", spec_dirs], $stderr, out) == 0
raise Puppet::Error, "Unit tests failed:\n#{out.string}"

## Check policy failures and return catalog if there were no failures
if (failed_policies = policy_check(catalog, facts, spec_dirs)).empty?
catalog
else
raise Puppet::Error, "Catalog failed to pass security policies:\n" + failed_policies.join("\n")
end
catalog
end

def policy_check(catalog, facts, dirs)
## Configure RSpec with catalog spec helper and compiled catalog data
RSpec.configuration.color = true
RSpec.configure do |c|
c.add_formatter(:progress)
c.add_formatter(:json)
c.add_setting :catalog, :default => catalog
c.add_setting :facts, :default => facts
c.backtrace_exclusion_patterns = [
/\/puppet\/(lib|bin)\//,
/\/ruby\//,
]
c.include RSpec::Puppet::CatalogExampleGroup
c.extend RSpec::Puppet::CatalogExampleGroup
end

## Configure JSON RSpec reporting formatter
config = RSpec.configuration
progress_formatter = RSpec::Core::Formatters::ProgressFormatter.new($stdout)
json_formatter = RSpec::Core::Formatters::JsonFormatter.new(config.out)
reporter = RSpec::Core::Reporter.new(progress_formatter, json_formatter)
config.instance_variable_set(:@reporter, reporter)

## Run RSpec on the policies directory
Puppet.info("Performing policy rspec-puppet checks")
RSpec::Core::Runner.run(dirs)

## Return an array of failed policy descriptions
json_formatter.output_hash[:examples].collect do |policy|
"-- Failed policy: #{policy[:exception][:message]}" if policy[:status] == 'failed'
end.compact
end
end

0 comments on commit 668dbd1

Please sign in to comment.