github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/developmentmembership/foundsubject.go (about) 1 package developmentmembership 2 3 import ( 4 "sort" 5 "strings" 6 7 core "github.com/authzed/spicedb/pkg/proto/core/v1" 8 9 "github.com/authzed/spicedb/pkg/tuple" 10 ) 11 12 // NewFoundSubject creates a new FoundSubject for a subject and a set of its resources. 13 func NewFoundSubject(subject *core.DirectSubject, resources ...*core.ObjectAndRelation) FoundSubject { 14 return FoundSubject{subject.Subject, nil, subject.CaveatExpression, tuple.NewONRSet(resources...)} 15 } 16 17 // FoundSubject contains a single found subject and all the relationships in which that subject 18 // is a member which were found via the ONRs expansion. 19 type FoundSubject struct { 20 // subject is the subject found. 21 subject *core.ObjectAndRelation 22 23 // excludedSubjects are any subjects excluded. Only should be set if subject is a wildcard. 24 excludedSubjects []FoundSubject 25 26 // caveatExpression is the conditional expression on the found subject. 27 caveatExpression *core.CaveatExpression 28 29 // relations are the relations under which the subject lives that informed the locating 30 // of this subject for the root ONR. 31 relationships *tuple.ONRSet 32 } 33 34 // GetSubjectId is named to match the Subject interface for the BaseSubjectSet. 35 // 36 //nolint:all 37 func (fs FoundSubject) GetSubjectId() string { 38 return fs.subject.ObjectId 39 } 40 41 func (fs FoundSubject) GetCaveatExpression() *core.CaveatExpression { 42 return fs.caveatExpression 43 } 44 45 func (fs FoundSubject) GetExcludedSubjects() []FoundSubject { 46 return fs.excludedSubjects 47 } 48 49 // Subject returns the Subject of the FoundSubject. 50 func (fs FoundSubject) Subject() *core.ObjectAndRelation { 51 return fs.subject 52 } 53 54 // WildcardType returns the object type for the wildcard subject, if this is a wildcard subject. 55 func (fs FoundSubject) WildcardType() (string, bool) { 56 if fs.subject.ObjectId == tuple.PublicWildcard { 57 return fs.subject.Namespace, true 58 } 59 60 return "", false 61 } 62 63 // ExcludedSubjectsFromWildcard returns those subjects excluded from the wildcard subject. 64 // If not a wildcard subject, returns false. 65 func (fs FoundSubject) ExcludedSubjectsFromWildcard() ([]FoundSubject, bool) { 66 if fs.subject.ObjectId == tuple.PublicWildcard { 67 return fs.excludedSubjects, true 68 } 69 70 return nil, false 71 } 72 73 // Relationships returns all the relationships in which the subject was found as per the expand. 74 func (fs FoundSubject) Relationships() []*core.ObjectAndRelation { 75 return fs.relationships.AsSlice() 76 } 77 78 func (fs FoundSubject) excludedSubjectStrings() []string { 79 excludedStrings := make([]string, 0, len(fs.excludedSubjects)) 80 for _, excludedSubject := range fs.excludedSubjects { 81 excludedSubjectString := tuple.StringONR(excludedSubject.subject) 82 if excludedSubject.GetCaveatExpression() != nil { 83 excludedSubjectString += "[...]" 84 } 85 excludedStrings = append(excludedStrings, excludedSubjectString) 86 } 87 88 sort.Strings(excludedStrings) 89 return excludedStrings 90 } 91 92 // ToValidationString returns the FoundSubject in a format that is consumable by the validationfile 93 // package. 94 func (fs FoundSubject) ToValidationString() string { 95 onrString := tuple.StringONR(fs.Subject()) 96 validationString := onrString 97 if fs.caveatExpression != nil { 98 validationString = validationString + "[...]" 99 } 100 101 excluded, isWildcard := fs.ExcludedSubjectsFromWildcard() 102 if isWildcard && len(excluded) > 0 { 103 validationString = validationString + " - {" + strings.Join(fs.excludedSubjectStrings(), ", ") + "}" 104 } 105 106 return validationString 107 } 108 109 func (fs FoundSubject) String() string { 110 return fs.ToValidationString() 111 } 112 113 // FoundSubjects contains the subjects found for a specific ONR. 114 type FoundSubjects struct { 115 // subjects is a map from the Subject ONR (as a string) to the FoundSubject information. 116 subjects *TrackingSubjectSet 117 } 118 119 // ListFound returns a slice of all the FoundSubject's. 120 func (fs FoundSubjects) ListFound() []FoundSubject { 121 return fs.subjects.ToSlice() 122 } 123 124 // LookupSubject returns the FoundSubject for a matching subject, if any. 125 func (fs FoundSubjects) LookupSubject(subject *core.ObjectAndRelation) (FoundSubject, bool) { 126 return fs.subjects.Get(subject) 127 }