Class: SuperAuth::Resource
- Inherits:
-
Object
- Object
- SuperAuth::Resource
- Includes:
- Nestable
- Defined in:
- lib/super_auth/resource.rb
Class Method Summary collapse
-
.assert_compilable! ⇒ Object
"Type-level nodes are flat." compile! calls this before touching the compiled table, so a refused compile leaves the previous rows in place.
-
.descend_from(parent) ⇒ Object
The recursive step of descendant_pairs stops at a type-level node.
-
.record(type, id) ⇒ Object
The node registered for one record: the pair every host helper looks up before it grants, revokes or labels.
-
.wildcards ⇒ Object
A node with an external_type and no external_id is a type-level (wildcard) node: at runtime it means every record of that type, present and future (the ByCurrentUser type_level branch, the policy's
resource_external_id IS NULL ORclause).
Methods included from Nestable
#before_destroy, included, #validate
Class Method Details
.assert_compilable! ⇒ Object
"Type-level nodes are flat." compile! calls this before touching the compiled table, so a refused compile leaves the previous rows in place. The walk and the join above make the shape harmless; this makes it loud, because nobody means it. A type-level node with a parent looks like a container grant that reaches every record of a type, and one with children looks like a container whose children can only be reached through a grant that already covers them. One query: the type-level nodes that have a parent, or that some node names as its parent.
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/super_auth/resource.rb', line 61 def assert_compilable! parents = dataset.exclude(parent_id: nil).select(:parent_id) nested = wildcards.where(Sequel.|(Sequel.~(parent_id: nil), { id: parents })).select_order_map(:id) return if nested.empty? raise SuperAuth::Error, "Wildcard resource nodes must be flat, but wildcard node(s) #{nested.join(', ')} " \ "have a parent or children. A resource node with an external_type and no external_id is a wildcard " \ "for every record of that type, not a container: nested in the tree it would compile to a row that " \ "reaches every record of its type through the tree. Move each to the root with no children, or give " \ "it an external_id." end |
.descend_from(parent) ⇒ Object
The recursive step of descendant_pairs stops at a type-level node. A per-record node nested under one would otherwise receive the type-level node's grants: one accidental parent_id, and a grant on "every Claim" also compiled a row for every claim node beneath it, on every path that reads the walk — including a host that reads Edge.authorizations directly and never calls compile!, where assert_compilable! does not run. The walk still anchors on the node a grant names, so a granted type-level node yields its own (type, NULL) row and nothing else; join_resource_subtree drops the other direction, a type-level node reached as a descendant.
48 49 50 |
# File 'lib/super_auth/resource.rb', line 48 def descend_from(parent) Sequel.|({ Sequel[parent][:external_type] => nil }, Sequel.~(Sequel[parent][:external_id] => nil)) end |
.record(type, id) ⇒ Object
The node registered for one record: the pair every host helper looks up before it grants, revokes or labels. It refuses a nil id rather than answering, because where(external_type: type, external_id: nil) is not "no node" — it IS the type-level node for that type, and a helper called with an unset foreign key would otherwise act on the grant that covers every record of the type.
28 29 30 31 32 33 34 35 36 |
# File 'lib/super_auth/resource.rb', line 28 def record(type, id) if id.nil? raise SuperAuth::Error, "SuperAuth::Resource.record(#{type.to_s.inspect}, nil): the id is nil. " \ "A node with an external_type and no external_id is the type-level node for every #{type} record, " \ "not the node for one of them; pass the record's id, or use wildcards for the type-level node." end first(external_type: type.to_s, external_id: id) end |
.wildcards ⇒ Object
A node with an external_type and no external_id is a type-level
(wildcard) node: at runtime it means every record of that type, present
and future (the ByCurrentUser type_level branch, the policy's
resource_external_id IS NULL OR clause). A node with neither is a
container. The type-level grant is a supported, permanent primitive —
"this principal may act on every record of a type" has no cheaper
spelling — and it is flat: what it may not do is join the tree.
18 19 20 |
# File 'lib/super_auth/resource.rb', line 18 def wildcards exclude(external_type: nil).where(external_id: nil) end |