summaryrefslogtreecommitdiff
path: root/vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go')
-rw-r--r--vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go b/vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go
new file mode 100644
index 0000000..adbaa94
--- /dev/null
+++ b/vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go
@@ -0,0 +1,82 @@
+package namespace
+
+import (
+ "sort"
+
+ "github.com/authzed/spicedb/pkg/schema"
+)
+
+// computePermissionAliases computes a map of aliases between the various permissions in a
+// namespace. A permission is considered an alias if it *directly* refers to another permission
+// or relation without any other form of expression.
+func computePermissionAliases(typeDefinition *schema.ValidatedDefinition) (map[string]string, error) {
+ aliases := map[string]string{}
+ done := map[string]struct{}{}
+ unresolvedAliases := map[string]string{}
+
+ for _, rel := range typeDefinition.Namespace().Relation {
+ // Ensure the relation has a rewrite...
+ if rel.GetUsersetRewrite() == nil {
+ done[rel.Name] = struct{}{}
+ continue
+ }
+
+ // ... with a union ...
+ union := rel.GetUsersetRewrite().GetUnion()
+ if union == nil {
+ done[rel.Name] = struct{}{}
+ continue
+ }
+
+ // ... with a single child ...
+ if len(union.Child) != 1 {
+ done[rel.Name] = struct{}{}
+ continue
+ }
+
+ // ... that is a computed userset.
+ computedUserset := union.Child[0].GetComputedUserset()
+ if computedUserset == nil {
+ done[rel.Name] = struct{}{}
+ continue
+ }
+
+ // If the aliased item is a relation, then we've found the alias target.
+ aliasedPermOrRel := computedUserset.GetRelation()
+ if !typeDefinition.IsPermission(aliasedPermOrRel) {
+ done[rel.Name] = struct{}{}
+ aliases[rel.Name] = aliasedPermOrRel
+ continue
+ }
+
+ // Otherwise, add the permission to the working set.
+ unresolvedAliases[rel.Name] = aliasedPermOrRel
+ }
+
+ for len(unresolvedAliases) > 0 {
+ startingCount := len(unresolvedAliases)
+ for relName, aliasedPermission := range unresolvedAliases {
+ if _, ok := done[aliasedPermission]; ok {
+ done[relName] = struct{}{}
+
+ if alias, ok := aliases[aliasedPermission]; ok {
+ aliases[relName] = alias
+ } else {
+ aliases[relName] = aliasedPermission
+ }
+ delete(unresolvedAliases, relName)
+ continue
+ }
+ }
+ if len(unresolvedAliases) == startingCount {
+ keys := make([]string, 0, len(unresolvedAliases))
+ for key := range unresolvedAliases {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ return nil, NewPermissionsCycleErr(typeDefinition.Namespace().Name, keys)
+ }
+ }
+
+ return aliases, nil
+}