generate hash output for check and use it in inspec cli

This commit is contained in:
Christoph Hartmann 2016-02-03 18:53:39 +01:00
parent 6b7e5818fb
commit 1796c3271b
2 changed files with 95 additions and 31 deletions

View file

@ -54,9 +54,9 @@ class InspecCLI < Thor # rubocop:disable Metrics/ClassLength
desc: 'Save the created profile to a path'
def json(path)
diagnose
o = opts.dup
o[:ignore_supports] = true
profile = Inspec::Profile.from_path(path, o)
dst = o[:output].to_s
if dst.empty?
@ -75,21 +75,33 @@ class InspecCLI < Thor # rubocop:disable Metrics/ClassLength
desc 'check PATH', 'verify all tests at the specified PATH'
option :format, type: :string
def check(path)
diagnose
o = opts.dup
# configure_logger(o) # we do not need a logger for check yet
o[:ignore_supports] = true # we check for integrity only
o[:logger] = Logger.new(STDOUT)
o[:logger].level = get_log_level(o.log_level)
# output json if we have activated the json formatter
if opts['format'] == 'json'
o[:logger].formatter = Logger::JSONFormatter.new
else
diagnose
end
# run check
profile = Inspec::Profile.from_path(path, o)
exit 1 unless profile.check
success, result = profile.check
if opts['format'] == 'json'
puts JSON.generate(result)
else
headline('Summary')
%w{location profile controls timestamp valid}.each { |item|
puts "#{mark_text(item.to_s.capitalize + ':')} #{result[:summary][item.to_sym]}"
}
newline
%w{errors warnings}.each { |list|
headline(list.to_s.capitalize)
result[list.to_sym].each { |item|
puts "#{item[:file]}:#{item[:line]}:#{item[:column]}: #{item[:msg]} "
}
newline
}
end
exit 1 unless success
end
desc 'archive PATH', 'archive a profile to tar.gz (default) or zip'
@ -188,6 +200,15 @@ class InspecCLI < Thor # rubocop:disable Metrics/ClassLength
@json ||= conffile ? read_config(conffile) : {}
end
def configure_logger(o)
o[:logger] = Logger.new(STDOUT)
# output json if we have activated the json formatter
if opts['log-format'] == 'json'
o[:logger].formatter = Logger::JSONFormatter.new
end
o[:logger].level = get_log_level(o.log_level)
end
# get the log level
# DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
def get_log_level(level)
@ -215,5 +236,19 @@ class InspecCLI < Thor # rubocop:disable Metrics/ClassLength
puts "Failed to load JSON configuration: #{e}\nConfig was: #{config.inspect}"
exit 1
end
def mark_text(text)
"\e[0;32m#{text}\e[0m"
end
def headline(title)
puts title
title.each_char {|c| print '-' }
newline
end
def newline
print "\n"
end
end
InspecCLI.start(ARGV)

View file

@ -55,6 +55,7 @@ module Inspec
impact: rule.impact,
checks: rule.instance_variable_get(:@checks),
code: rule.instance_variable_get(:@__code),
source_location: rule.instance_variable_get(:@__source_location),
group_title: rule.instance_variable_get(:@__group_title),
}
end
@ -89,32 +90,59 @@ module Inspec
#
# @return [Boolean] true if no errors were found, false otherwise
def check # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
no_errors = true
no_warnings = true
warn = lambda { |msg|
@logger.warn(msg)
no_warnings = false
# initial values for response object
result = {
:summary => {
:valid => false,
:timestamp => Time.now.iso8601,
:location => @path,
:profile => nil,
:controls => 0,
},
:errors => [],
:warnings => [],
}
error = lambda { |msg|
entry = lambda { |file, line, column, control, msg|
{
:file => file,
:line => line,
:column => column,
:control_id => control,
:msg => msg,
}
}
warn = lambda { |file, line, column, control, msg|
@logger.warn(msg)
result[:warnings].push(entry.call(file, line, column, control, msg))
}
error = lambda { |file, line, column, control, msg|
@logger.error(msg)
no_warnings = no_errors = false
result[:errors].push(entry.call(file, line, column, control, msg))
}
@logger.info "Checking profile in #{@path}"
@logger.info 'Metadata OK.' if @metadata.valid?
if @content.any? { |h| h[:type] == :metadata && h[:ref] =~ /metadata\.rb$/ }
warn.call('The use of `metadata.rb` is deprecated. Use `inspec.yml`.')
warn.call(Pathname.new(path).join('metadata.rb'), 0,0,nil, 'The use of `metadata.rb` is deprecated. Use `inspec.yml`.')
end
@logger.info 'Metadata OK.' if @metadata.valid?
result[:summary][:profile] = @metadata.params[:name]
# check if the profile is using the old test directory instead of the
# new controls directory
if @content.any? { |h| h[:type] == :test && h[:ref] =~ %r{test/[^/]+$} }
warn.call('Profile uses deprecated `test` directory, rename it to `controls`.')
warn.call(Pathname.new(path).join('test'), 0,0,nil, 'Profile uses deprecated `test` directory, rename it to `controls`.')
end
count = rules_count
result[:summary][:controls] = count
if count == 0
warn.call('No controls or tests were defined.')
warn.call(nil, nil, nil, nil, 'No controls or tests were defined.')
else
@logger.info("Found #{count} controls.")
end
@ -123,18 +151,19 @@ module Inspec
@params[:rules].each { |group, controls|
@logger.info "Verify all controls in #{group}"
controls.each { |id, control|
error.call('Avoid controls with empty IDs') if id.nil? or id.empty?
sfile, sline = control[:source_location]
error.call(sfile, sline, nil, id, 'Avoid controls with empty IDs') if id.nil? or id.empty?
next if id.start_with? '(generated '
warn.call("Control #{id} has no title") if control[:title].to_s.empty?
warn.call("Control #{id} has no description") if control[:desc].to_s.empty?
warn.call("Control #{id} has impact > 1.0") if control[:impact].to_f > 1.0
warn.call("Control #{id} has impact < 0.0") if control[:impact].to_f < 0.0
warn.call("Control #{id} has no tests defined") if control[:checks].nil? or control[:checks].empty?
warn.call(sfile, sline, nil, id, "Control #{id} has no title") if control[:title].to_s.empty?
warn.call(sfile, sline, nil, id, "Control #{id} has no description") if control[:desc].to_s.empty?
warn.call(sfile, sline, nil, id, "Control #{id} has impact > 1.0") if control[:impact].to_f > 1.0
warn.call(sfile, sline, nil, id, "Control #{id} has impact < 0.0") if control[:impact].to_f < 0.0
warn.call(sfile, sline, nil, id, "Control #{id} has no tests defined") if control[:checks].nil? or control[:checks].empty?
}
}
@logger.info 'Control definitions OK.' if no_warnings
no_errors
@logger.info 'Control definitions OK.' if result[:warnings].empty?
[result[:errors].empty?, result]
end
def rules_count