mirror of
https://github.com/inspec/inspec
synced 2024-11-27 15:10:44 +00:00
138 lines
4.4 KiB
Ruby
138 lines
4.4 KiB
Ruby
# encoding: utf-8
|
|
# Copyright 2015 Dominik Richter. All rights reserved.
|
|
# author: Dominik Richter
|
|
# author: Christoph Hartmann
|
|
|
|
require 'inspec/metadata'
|
|
|
|
module Inspec
|
|
class Profile # rubocop:disable Metrics/ClassLength
|
|
def self.from_path(path, options = nil)
|
|
opt = {}
|
|
options.each { |k, v| opt[k.to_sym] = v } unless options.nil?
|
|
opt[:path] = path
|
|
Profile.new(opt)
|
|
end
|
|
|
|
attr_reader :params
|
|
attr_reader :metadata
|
|
|
|
def initialize(options = nil)
|
|
@options = options || {}
|
|
@profile_id = options[:id] || nil
|
|
@params = {}
|
|
@logger = options[:logger] || Logger.new(nil)
|
|
|
|
@path = @options[:path]
|
|
fail 'Cannot read an empty path.' if @path.nil? || @path.empty?
|
|
fail "Cannot find directory #{@path}" unless File.directory?(@path)
|
|
|
|
@metadata = read_metadata
|
|
@params = @metadata.params unless @metadata.nil?
|
|
|
|
@params[:rules] = rules = {}
|
|
@runner = Runner.new(
|
|
id: @profile_id,
|
|
backend: :mock,
|
|
)
|
|
@runner.add_tests([@path])
|
|
@runner.rules.each do |id, rule|
|
|
file = rule.instance_variable_get(:@__file)
|
|
rules[file] ||= {}
|
|
rules[file][id] = {
|
|
title: rule.title,
|
|
desc: rule.desc,
|
|
impact: rule.impact,
|
|
checks: rule.instance_variable_get(:@checks),
|
|
code: rule.instance_variable_get(:@__code),
|
|
group_title: rule.instance_variable_get(:@__group_title),
|
|
}
|
|
end
|
|
end
|
|
|
|
def info
|
|
res = @params.dup
|
|
rules = {}
|
|
res[:rules].each do |gid, group|
|
|
next if gid.to_s.empty?
|
|
path = gid.sub(File.join(@path, ''), '')
|
|
rules[path] = { title: path, rules: {} }
|
|
group.each do |id, rule|
|
|
next if id.to_s.empty?
|
|
data = rule.dup
|
|
data.delete(:checks)
|
|
data[:impact] ||= 0.5
|
|
data[:impact] = 1.0 if data[:impact] > 1.0
|
|
data[:impact] = 0.0 if data[:impact] < 0.0
|
|
rules[path][:rules][id] = data
|
|
# TODO: temporarily flatten the group down; replace this with
|
|
# proper hierarchy later on
|
|
rules[path][:title] = data[:group_title]
|
|
end
|
|
end
|
|
res[:rules] = rules
|
|
res
|
|
end
|
|
|
|
# Check if the profile is internall well-structured. The logger will be
|
|
# used to print information on errors and warnings which are found.
|
|
#
|
|
# @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
|
|
}
|
|
error = lambda { |msg|
|
|
@logger.error(msg)
|
|
no_warnings = no_errors = false
|
|
}
|
|
|
|
@logger.info "Checking profile in #{@path}"
|
|
|
|
if @params[:name].to_s.empty?
|
|
error.call('No profile name defined')
|
|
elsif !(@params[:name].to_s =~ %r{^\S+\/\S+$})
|
|
error.call('Profile name must be defined as: OWNER/ID')
|
|
end
|
|
|
|
warn.call('No version defined') if @params[:name].to_s.empty?
|
|
warn.call('No title defined') if @params[:name].to_s.empty?
|
|
warn.call('No maintainer defined') if @params[:name].to_s.empty?
|
|
warn.call('No supports defined') if @params[:name].empty?
|
|
@logger.info 'Metadata OK.' if no_warnings
|
|
|
|
no_warnings = true
|
|
if @params[:name].empty?
|
|
warn.call('No rules were found.')
|
|
else
|
|
@logger.debug "Found #{@params[:name].length} rules."
|
|
end
|
|
|
|
# iterate over hash of groups
|
|
@params[:rules].each do |group, rules_array|
|
|
@logger.debug "Verify all rules in #{group}"
|
|
rules_array.each do |id, rule|
|
|
error.call('Avoid rules with empty IDs') if id.nil? or id.empty?
|
|
warn.call("Rule #{id} has no title") if rule[:title].to_s.empty?
|
|
warn.call("Rule #{id} has no description") if rule[:desc].to_s.empty?
|
|
warn.call("Rule #{id} has impact > 1.0") if rule[:impact].to_f > 1.0
|
|
warn.call("Rule #{id} has impact < 0.0") if rule[:impact].to_f < 0.0
|
|
warn.call("Rule #{id} has no tests defined") if rule[:checks].nil? or rule[:checks].empty?
|
|
end
|
|
end
|
|
|
|
@logger.info 'Rule definitions OK.' if no_warnings
|
|
no_errors
|
|
end
|
|
|
|
private
|
|
|
|
def read_metadata
|
|
mpath = File.join(@path, 'metadata.rb')
|
|
@metadata = Metadata.from_file(mpath, @profile_id, @logger)
|
|
end
|
|
end
|
|
end
|