github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/namespace/aliasing.go (about) 1 package namespace 2 3 import ( 4 "sort" 5 6 "github.com/authzed/spicedb/pkg/typesystem" 7 ) 8 9 // computePermissionAliases computes a map of aliases between the various permissions in a 10 // namespace. A permission is considered an alias if it *directly* refers to another permission 11 // or relation without any other form of expression. 12 func computePermissionAliases(typeSystem *typesystem.ValidatedNamespaceTypeSystem) (map[string]string, error) { 13 aliases := map[string]string{} 14 done := map[string]struct{}{} 15 unresolvedAliases := map[string]string{} 16 17 for _, rel := range typeSystem.Namespace().Relation { 18 // Ensure the relation has a rewrite... 19 if rel.GetUsersetRewrite() == nil { 20 done[rel.Name] = struct{}{} 21 continue 22 } 23 24 // ... with a union ... 25 union := rel.GetUsersetRewrite().GetUnion() 26 if union == nil { 27 done[rel.Name] = struct{}{} 28 continue 29 } 30 31 // ... with a single child ... 32 if len(union.Child) != 1 { 33 done[rel.Name] = struct{}{} 34 continue 35 } 36 37 // ... that is a computed userset. 38 computedUserset := union.Child[0].GetComputedUserset() 39 if computedUserset == nil { 40 done[rel.Name] = struct{}{} 41 continue 42 } 43 44 // If the aliased item is a relation, then we've found the alias target. 45 aliasedPermOrRel := computedUserset.GetRelation() 46 if !typeSystem.IsPermission(aliasedPermOrRel) { 47 done[rel.Name] = struct{}{} 48 aliases[rel.Name] = aliasedPermOrRel 49 continue 50 } 51 52 // Otherwise, add the permission to the working set. 53 unresolvedAliases[rel.Name] = aliasedPermOrRel 54 } 55 56 for len(unresolvedAliases) > 0 { 57 startingCount := len(unresolvedAliases) 58 for relName, aliasedPermission := range unresolvedAliases { 59 if _, ok := done[aliasedPermission]; ok { 60 done[relName] = struct{}{} 61 62 if alias, ok := aliases[aliasedPermission]; ok { 63 aliases[relName] = alias 64 } else { 65 aliases[relName] = aliasedPermission 66 } 67 delete(unresolvedAliases, relName) 68 continue 69 } 70 } 71 if len(unresolvedAliases) == startingCount { 72 keys := make([]string, 0, len(unresolvedAliases)) 73 for key := range unresolvedAliases { 74 keys = append(keys, key) 75 } 76 sort.Strings(keys) 77 return nil, NewPermissionsCycleErr(typeSystem.Namespace().Name, keys) 78 } 79 } 80 81 return aliases, nil 82 }