mirror of
https://github.com/inspec/inspec
synced 2024-11-10 15:14:23 +00:00
feature: add rule hierarchy with include and require rules
include_rules 'vulcanosec/ssh' this will include all rules defined in vulcanosec/ssh require_rules 'vulcanosec/linux' this will not include any rules yet, but you may choose what you want to pull in. both have a block attached which will allow you to choose rules (for require_rules) and redefined/change existing rules as you like. small example: require_rules 'vulcanosec/linux' do rule fs-3 do impact 1.0 end end Signed-off-by: Dominik Richter <dominik@vulcanosec.com>
This commit is contained in:
parent
a6748e2418
commit
2e1106b933
2 changed files with 99 additions and 21 deletions
|
@ -3,12 +3,15 @@
|
|||
# license: All rights reserved
|
||||
|
||||
class VulcanoBaseRule
|
||||
def initialize(id, &block)
|
||||
def initialize(id, opts, &block)
|
||||
@id = id
|
||||
@impact = nil
|
||||
@title = nil
|
||||
@desc = nil
|
||||
|
||||
# not changeable by the user:
|
||||
@profile_id = nil
|
||||
@checks = []
|
||||
# evaluate the given definition
|
||||
self.instance_eval(&block) if block_given?
|
||||
end
|
||||
|
||||
|
@ -31,4 +34,28 @@ class VulcanoBaseRule
|
|||
@desc = v unless v.nil?
|
||||
@desc
|
||||
end
|
||||
|
||||
def self.merge dst, src
|
||||
if src.id != dst.id
|
||||
# TODO: register an error, this case should not happen
|
||||
return
|
||||
end
|
||||
sp = src.instance_variable_get(:@profile_id)
|
||||
dp = dst.instance_variable_get(:@profile_id)
|
||||
if sp != dp
|
||||
# TODO: register an error, this case should not happen
|
||||
return
|
||||
end
|
||||
# merge all fields
|
||||
dst.impact(src.impact) if src.impact != nil
|
||||
dst.title(src.title) if src.title != nil
|
||||
dst.desc(src.desc) if src.desc != nil
|
||||
# merge indirect fields
|
||||
# checks defined in the source will completely eliminate
|
||||
# all checks that were defined in the destination
|
||||
sc = src.instance_variable_get(:@checks)
|
||||
unless sc.nil? || sc.empty?
|
||||
dst.instance_variable_set(:@checks, sc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,6 @@ module Vulcano
|
|||
# IDs to each example group
|
||||
# TODO: remove this once IDs are in rspec-core
|
||||
def describe(sth, &block)
|
||||
@checks ||= []
|
||||
@checks.push(['describe', [sth], block])
|
||||
end
|
||||
|
||||
|
@ -28,11 +27,7 @@ end
|
|||
|
||||
module Vulcano::DSL
|
||||
def rule id, opts = {}, &block
|
||||
__register_rule Vulcano::Rule.new(id, &block)
|
||||
end
|
||||
|
||||
def __register_rule r
|
||||
@rules.push(r)
|
||||
__register_rule Vulcano::Rule.new(id, opts, &block)
|
||||
end
|
||||
|
||||
def require_rules id, &block
|
||||
|
@ -59,6 +54,12 @@ module Vulcano::DSL
|
|||
|
||||
private
|
||||
|
||||
# merge two rules completely; all defined
|
||||
# fields from src will be overwritten in dst
|
||||
def self.merge_rules dst, src
|
||||
VulcanoBaseRule::merge dst, src
|
||||
end
|
||||
|
||||
# Attach an ID attribute to the
|
||||
# metadata of all examples
|
||||
# TODO: remove this once IDs are in rspec-core
|
||||
|
@ -71,28 +72,50 @@ module Vulcano::DSL
|
|||
}
|
||||
end
|
||||
|
||||
def self.load_spec_file_for_profile id, file
|
||||
def self.load_spec_file_for_profile profile_id, file, rule_registry
|
||||
raw = File::read(file)
|
||||
# TODO: error-handling
|
||||
|
||||
ctx = Vulcano::ProfileContext.new(id)
|
||||
ctx = Vulcano::ProfileContext.new(profile_id, rule_registry)
|
||||
ctx.instance_eval(raw, file, 1)
|
||||
return ctx.instance_variable_get(:@rules)
|
||||
end
|
||||
|
||||
def self.load_spec_files_for_profile bind_context, id, include_all, &block
|
||||
def self.load_spec_files_for_profile bind_context, profile_id, include_all, &block
|
||||
# get all spec files
|
||||
files = get_spec_files_for_profile id
|
||||
files = get_spec_files_for_profile profile_id
|
||||
# load all rules from spec files
|
||||
rules = files.map do |file|
|
||||
load_spec_file_for_profile(id, file)
|
||||
end.flatten.compact
|
||||
rule_registry = {}
|
||||
files.each do |file|
|
||||
load_spec_file_for_profile(profile_id, file, rule_registry)
|
||||
end
|
||||
|
||||
# TODO: interpret the block and make adjustments
|
||||
# (ie include rule, adjust rule, etc...)
|
||||
# interpret the block and create a set of rules from it
|
||||
block_registry = {}
|
||||
if block_given?
|
||||
ctx = Vulcano::ProfileContext.new(profile_id, block_registry)
|
||||
ctx.instance_eval(&block)
|
||||
end
|
||||
|
||||
# if all rules are not included, select only the ones
|
||||
# that were defined in the block
|
||||
unless include_all
|
||||
remove = rule_registry.keys - block_registry.keys
|
||||
remove.each{|key| rule_registry.delete(key)}
|
||||
end
|
||||
|
||||
# merge the rules in the block_registry (adjustments) with
|
||||
# the rules in the rule_registry (included)
|
||||
block_registry.each do |id,r|
|
||||
org = rule_registry[id]
|
||||
if org.nil?
|
||||
# TODO: print error because we write alter a rule that doesn't exist
|
||||
else
|
||||
merge_rules(org, r)
|
||||
end
|
||||
end
|
||||
|
||||
# finally register all combined rules
|
||||
rules.each do |rule|
|
||||
rule_registry.each do |id, rule|
|
||||
bind_context.__register_rule rule
|
||||
end
|
||||
end
|
||||
|
@ -117,11 +140,39 @@ end
|
|||
|
||||
module Vulcano
|
||||
class ProfileContext
|
||||
|
||||
include Vulcano::DSL
|
||||
def initialize profile_id
|
||||
def initialize profile_id, profile_registry
|
||||
@profile_id = profile_id
|
||||
@rules = []
|
||||
@rules = profile_registry
|
||||
end
|
||||
|
||||
def __register_rule r
|
||||
# Profile registry consists of profile_id + rule_id
|
||||
# As the profile context is exclusively pulled with a
|
||||
# profile ID, attach it to the rule if necessary.
|
||||
rid = r.instance_variable_get(:@id)
|
||||
if rid.nil?
|
||||
# TODO: Message about skipping this rule
|
||||
# due to missing ID
|
||||
return
|
||||
end
|
||||
pid = r.instance_variable_get(:@profile_id)
|
||||
if pid.nil?
|
||||
r.instance_variable_set(:@profile_id, @profile_id)
|
||||
pid = @profile_id
|
||||
end
|
||||
full_id = pid + "/" + rid
|
||||
|
||||
# add the rule to the registry
|
||||
existing = @rules[full_id]
|
||||
if existing.nil?
|
||||
@rules[full_id] = r
|
||||
else
|
||||
VulcanoBaseRule::merge(existing, r)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue