lib/conjur/policy/resolver.rb in conjur-asset-policy-0.8.0 vs lib/conjur/policy/resolver.rb in conjur-asset-policy-0.8.1

- old
+ new

@@ -4,11 +4,11 @@ attr_reader :account, :ownerid, :namespace class << self # Resolve records to the specified owner id and namespace. def resolve records, account, ownerid, namespace = nil - resolver_classes = [ AccountResolver, IdResolver, OwnerResolver, FlattenResolver ] + resolver_classes = [ AccountResolver, IdResolver, OwnerResolver, FlattenResolver, DuplicateResolver ] resolver_classes.each do |cls| resolver = cls.new account, ownerid, namespace records = resolver.resolve records end records @@ -77,11 +77,11 @@ def resolve_id record, visited if record.respond_to?(:id) && record.respond_to?(:id=) id = record.id if id.blank? - raise "#{record.to_s} has no id, and no namespace is available to populate it" unless namespace + raise "#{record.class.simple_name} has no id" unless namespace id = namespace elsif id[0] == '/' id = id[1..-1] else id = [ namespace, id ].compact.join('/') @@ -155,11 +155,14 @@ @referenced_record_index[obj] = obj.referenced_records.select{|r| r.respond_to?(:roleid)}.map(&:roleid) end @result.flatten.sort do |a,b| score = sort_score(a) - sort_score(b) if score == 0 - if a.respond_to?(:roleid) && @referenced_record_index[b].member?(a.roleid) + if a.respond_to?(:roleid) && @referenced_record_index[b].member?(a.roleid) && + b.respond_to?(:roleid) && @referenced_record_index[a].member?(b.roleid) + raise "Dependency cycle encountered between #{a} and #{b}" + elsif a.respond_to?(:roleid) && @referenced_record_index[b].member?(a.roleid) score = -1 elsif b.respond_to?(:roleid) && @referenced_record_index[a].member?(b.roleid) score = 1 else score = @stable_index[a] - @stable_index[b] @@ -169,19 +172,10 @@ end end protected - # Select things uniquely by class and id, in this resolver. - def id_of record - if record.respond_to?(:id) - [ record.id, record.class.name ].join("@") - else - super - end - end - # Sort "Create" and "Record" objects to the front. def sort_score record if record.is_a?(Types::Create) || record.is_a?(Types::Record) -1 else @@ -197,9 +191,21 @@ # Recurse on the policy body records. def on_resolve_policy policy, visited body = policy.body policy.remove_instance_variable "@body" traverse body, visited, method(:resolve_record), method(:on_resolve_policy) + end + end + + # Raises an exception if the same record is declared more than once. + class DuplicateResolver < Resolver + def resolve records + seen = Set.new + Array(records).flatten.each do |record| + if record.respond_to?(:id) && !seen.add?([ record.class.short_name, record.id ]) + raise "#{record} is declared more than once" + end + end end end # Unsets attributes that make for more verbose YAML output. This class is used to # compact YAML expectations in test cases. It expects pre-flattened input.