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  }