github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/namespace/builder.go (about) 1 package namespace 2 3 import ( 4 "github.com/authzed/spicedb/pkg/caveats" 5 core "github.com/authzed/spicedb/pkg/proto/core/v1" 6 iv1 "github.com/authzed/spicedb/pkg/proto/impl/v1" 7 "github.com/authzed/spicedb/pkg/spiceerrors" 8 ) 9 10 // Namespace creates a namespace definition with one or more defined relations. 11 func Namespace(name string, relations ...*core.Relation) *core.NamespaceDefinition { 12 return &core.NamespaceDefinition{ 13 Name: name, 14 Relation: relations, 15 } 16 } 17 18 // WithComment creates a namespace definition with one or more defined relations. 19 func WithComment(name string, comment string, relations ...*core.Relation) *core.NamespaceDefinition { 20 nd := Namespace(name, relations...) 21 nd.Metadata, _ = AddComment(nd.Metadata, comment) 22 return nd 23 } 24 25 // MustRelation creates a relation definition with an optional rewrite definition. 26 func MustRelation(name string, rewrite *core.UsersetRewrite, allowedDirectRelations ...*core.AllowedRelation) *core.Relation { 27 r, err := Relation(name, rewrite, allowedDirectRelations...) 28 if err != nil { 29 panic(err) 30 } 31 return r 32 } 33 34 // Relation creates a relation definition with an optional rewrite definition. 35 func Relation(name string, rewrite *core.UsersetRewrite, allowedDirectRelations ...*core.AllowedRelation) (*core.Relation, error) { 36 var typeInfo *core.TypeInformation 37 if len(allowedDirectRelations) > 0 { 38 typeInfo = &core.TypeInformation{ 39 AllowedDirectRelations: allowedDirectRelations, 40 } 41 } 42 43 rel := &core.Relation{ 44 Name: name, 45 UsersetRewrite: rewrite, 46 TypeInformation: typeInfo, 47 } 48 49 switch { 50 case rewrite != nil && len(allowedDirectRelations) == 0: 51 if err := SetRelationKind(rel, iv1.RelationMetadata_PERMISSION); err != nil { 52 return nil, spiceerrors.MustBugf("failed to set relation kind: %s", err.Error()) 53 } 54 55 case rewrite == nil && len(allowedDirectRelations) > 0: 56 if err := SetRelationKind(rel, iv1.RelationMetadata_RELATION); err != nil { 57 return nil, spiceerrors.MustBugf("failed to set relation kind: %s", err.Error()) 58 } 59 60 default: 61 // By default we do not set a relation kind on the relation. Relations without any 62 // information, or relations with both rewrites and types are legacy relations from 63 // before the DSL schema and, as such, do not have a defined "kind". 64 } 65 66 return rel, nil 67 } 68 69 // MustRelationWithComment creates a relation definition with an optional rewrite definition. 70 func MustRelationWithComment(name string, comment string, rewrite *core.UsersetRewrite, allowedDirectRelations ...*core.AllowedRelation) *core.Relation { 71 rel := MustRelation(name, rewrite, allowedDirectRelations...) 72 rel.Metadata, _ = AddComment(rel.Metadata, comment) 73 return rel 74 } 75 76 // AllowedRelation creates a relation reference to an allowed relation. 77 func AllowedRelation(namespaceName string, relationName string) *core.AllowedRelation { 78 return &core.AllowedRelation{ 79 Namespace: namespaceName, 80 RelationOrWildcard: &core.AllowedRelation_Relation{ 81 Relation: relationName, 82 }, 83 } 84 } 85 86 // AllowedRelationWithCaveat creates a relation reference to an allowed relation. 87 func AllowedRelationWithCaveat(namespaceName string, relationName string, withCaveat *core.AllowedCaveat) *core.AllowedRelation { 88 return &core.AllowedRelation{ 89 Namespace: namespaceName, 90 RelationOrWildcard: &core.AllowedRelation_Relation{ 91 Relation: relationName, 92 }, 93 RequiredCaveat: withCaveat, 94 } 95 } 96 97 // AllowedPublicNamespace creates a relation reference to an allowed public namespace. 98 func AllowedPublicNamespace(namespaceName string) *core.AllowedRelation { 99 return &core.AllowedRelation{ 100 Namespace: namespaceName, 101 RelationOrWildcard: &core.AllowedRelation_PublicWildcard_{ 102 PublicWildcard: &core.AllowedRelation_PublicWildcard{}, 103 }, 104 } 105 } 106 107 // AllowedCaveat creates a caveat reference. 108 func AllowedCaveat(name string) *core.AllowedCaveat { 109 return &core.AllowedCaveat{ 110 CaveatName: name, 111 } 112 } 113 114 // CaveatDefinition returns a new caveat definition. 115 func CaveatDefinition(env *caveats.Environment, name string, expr string) (*core.CaveatDefinition, error) { 116 compiled, err := caveats.CompileCaveatWithName(env, expr, name) 117 if err != nil { 118 return nil, err 119 } 120 return CompiledCaveatDefinition(env, name, compiled) 121 } 122 123 // CompiledCaveatDefinition returns a new caveat definition. 124 func CompiledCaveatDefinition(env *caveats.Environment, name string, compiled *caveats.CompiledCaveat) (*core.CaveatDefinition, error) { 125 if compiled == nil { 126 return nil, spiceerrors.MustBugf("compiled caveat is nil") 127 } 128 129 serialized, err := compiled.Serialize() 130 if err != nil { 131 return nil, err 132 } 133 return &core.CaveatDefinition{ 134 Name: name, 135 SerializedExpression: serialized, 136 ParameterTypes: env.EncodedParametersTypes(), 137 }, nil 138 } 139 140 // MustCaveatDefinition returns a new caveat definition. 141 func MustCaveatDefinition(env *caveats.Environment, name string, expr string) *core.CaveatDefinition { 142 cd, err := CaveatDefinition(env, name, expr) 143 if err != nil { 144 panic(err) 145 } 146 return cd 147 } 148 149 // MustCaveatDefinitionWithComment returns a new caveat definition. 150 func MustCaveatDefinitionWithComment(env *caveats.Environment, name string, comment string, expr string) *core.CaveatDefinition { 151 cd, err := CaveatDefinition(env, name, expr) 152 if err != nil { 153 panic(err) 154 } 155 cd.Metadata, _ = AddComment(cd.Metadata, comment) 156 return cd 157 } 158 159 // AllowedPublicNamespaceWithCaveat creates a relation reference to an allowed public namespace. 160 func AllowedPublicNamespaceWithCaveat(namespaceName string, withCaveat *core.AllowedCaveat) *core.AllowedRelation { 161 return &core.AllowedRelation{ 162 Namespace: namespaceName, 163 RelationOrWildcard: &core.AllowedRelation_PublicWildcard_{ 164 PublicWildcard: &core.AllowedRelation_PublicWildcard{}, 165 }, 166 RequiredCaveat: withCaveat, 167 } 168 } 169 170 // RelationReference creates a relation reference. 171 func RelationReference(namespaceName string, relationName string) *core.RelationReference { 172 return &core.RelationReference{ 173 Namespace: namespaceName, 174 Relation: relationName, 175 } 176 } 177 178 // Union creates a rewrite definition that combines/considers usersets in all children. 179 func Union(firstChild *core.SetOperation_Child, rest ...*core.SetOperation_Child) *core.UsersetRewrite { 180 return &core.UsersetRewrite{ 181 RewriteOperation: &core.UsersetRewrite_Union{ 182 Union: setOperation(firstChild, rest), 183 }, 184 } 185 } 186 187 // Intersection creates a rewrite definition that returns/considers only usersets present in all children. 188 func Intersection(firstChild *core.SetOperation_Child, rest ...*core.SetOperation_Child) *core.UsersetRewrite { 189 return &core.UsersetRewrite{ 190 RewriteOperation: &core.UsersetRewrite_Intersection{ 191 Intersection: setOperation(firstChild, rest), 192 }, 193 } 194 } 195 196 // Exclusion creates a rewrite definition that starts with the usersets of the first child 197 // and iteratively removes usersets that appear in the remaining children. 198 func Exclusion(firstChild *core.SetOperation_Child, rest ...*core.SetOperation_Child) *core.UsersetRewrite { 199 return &core.UsersetRewrite{ 200 RewriteOperation: &core.UsersetRewrite_Exclusion{ 201 Exclusion: setOperation(firstChild, rest), 202 }, 203 } 204 } 205 206 func setOperation(firstChild *core.SetOperation_Child, rest []*core.SetOperation_Child) *core.SetOperation { 207 children := append([]*core.SetOperation_Child{firstChild}, rest...) 208 return &core.SetOperation{ 209 Child: children, 210 } 211 } 212 213 // Nil creates a child for a set operation that references the empty set. 214 func Nil() *core.SetOperation_Child { 215 return &core.SetOperation_Child{ 216 ChildType: &core.SetOperation_Child_XNil{}, 217 } 218 } 219 220 // ComputesUserset creates a child for a set operation that follows a relation on the given starting object. 221 func ComputedUserset(relation string) *core.SetOperation_Child { 222 return &core.SetOperation_Child{ 223 ChildType: &core.SetOperation_Child_ComputedUserset{ 224 ComputedUserset: &core.ComputedUserset{ 225 Relation: relation, 226 }, 227 }, 228 } 229 } 230 231 // MustComputesUsersetWithSourcePosition creates a child for a set operation that follows a relation on the given starting object. 232 func MustComputesUsersetWithSourcePosition(relation string, lineNumber uint64) *core.SetOperation_Child { 233 cu := &core.ComputedUserset{ 234 Relation: relation, 235 } 236 cu.SourcePosition = &core.SourcePosition{ 237 ZeroIndexedLineNumber: lineNumber, 238 ZeroIndexedColumnPosition: 0, 239 } 240 241 return &core.SetOperation_Child{ 242 ChildType: &core.SetOperation_Child_ComputedUserset{ 243 ComputedUserset: cu, 244 }, 245 } 246 } 247 248 // TupleToUserset creates a child which first loads all tuples with the specific relation, 249 // and then unions all children on the usersets found by following a relation on those loaded 250 // tuples. 251 func TupleToUserset(tuplesetRelation, usersetRelation string) *core.SetOperation_Child { 252 return &core.SetOperation_Child{ 253 ChildType: &core.SetOperation_Child_TupleToUserset{ 254 TupleToUserset: &core.TupleToUserset{ 255 Tupleset: &core.TupleToUserset_Tupleset{ 256 Relation: tuplesetRelation, 257 }, 258 ComputedUserset: &core.ComputedUserset{ 259 Relation: usersetRelation, 260 Object: core.ComputedUserset_TUPLE_USERSET_OBJECT, 261 }, 262 }, 263 }, 264 } 265 } 266 267 // Rewrite wraps a rewrite as a set operation child of another rewrite. 268 func Rewrite(rewrite *core.UsersetRewrite) *core.SetOperation_Child { 269 return &core.SetOperation_Child{ 270 ChildType: &core.SetOperation_Child_UsersetRewrite{ 271 UsersetRewrite: rewrite, 272 }, 273 } 274 }