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.