diff options
Diffstat (limited to 'vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go')
| -rw-r--r-- | vendor/github.com/authzed/spicedb/internal/namespace/aliasing.go | 82 |
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 +} |
