github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datasets/basesubjectset.go (about)

     1  package datasets
     2  
     3  import (
     4  	"golang.org/x/exp/maps"
     5  
     6  	"github.com/authzed/spicedb/internal/caveats"
     7  	core "github.com/authzed/spicedb/pkg/proto/core/v1"
     8  	"github.com/authzed/spicedb/pkg/spiceerrors"
     9  	"github.com/authzed/spicedb/pkg/tuple"
    10  )
    11  
    12  var (
    13  	caveatAnd        = caveats.And
    14  	caveatOr         = caveats.Or
    15  	caveatInvert     = caveats.Invert
    16  	shortcircuitedOr = caveats.ShortcircuitedOr
    17  )
    18  
    19  // Subject is a subject that can be placed into a BaseSubjectSet. It is defined in a generic
    20  // manner to allow implementations that wrap BaseSubjectSet to add their own additional bookkeeping
    21  // to the base implementation.
    22  type Subject[T any] interface {
    23  	// GetSubjectId returns the ID of the subject. For wildcards, this should be `*`.
    24  	GetSubjectId() string
    25  
    26  	// GetCaveatExpression returns the caveat expression for this subject, if it is conditional.
    27  	GetCaveatExpression() *core.CaveatExpression
    28  
    29  	// GetExcludedSubjects returns the list of subjects excluded. Must only have values
    30  	// for wildcards and must never be nested.
    31  	GetExcludedSubjects() []T
    32  }
    33  
    34  // BaseSubjectSet defines a set that tracks accessible subjects, their exclusions (if wildcards),
    35  // and all conditional expressions applied due to caveats.
    36  //
    37  // It is generic to allow other implementations to define the kind of tracking information
    38  // associated with each subject.
    39  //
    40  // NOTE: Unlike a traditional set, unions between wildcards and a concrete subject will result
    41  // in *both* being present in the set, to maintain the proper set semantics around wildcards.
    42  type BaseSubjectSet[T Subject[T]] struct {
    43  	constructor constructor[T]
    44  	concrete    map[string]T
    45  	wildcard    *handle[T]
    46  }
    47  
    48  // NewBaseSubjectSet creates a new base subject set for use underneath well-typed implementation.
    49  //
    50  // The constructor function returns a new instance of type T for a particular subject ID.
    51  func NewBaseSubjectSet[T Subject[T]](constructor constructor[T]) BaseSubjectSet[T] {
    52  	return BaseSubjectSet[T]{
    53  		constructor: constructor,
    54  		concrete:    map[string]T{},
    55  		wildcard:    newHandle[T](),
    56  	}
    57  }
    58  
    59  // constructor defines a function for constructing a new instance of the Subject type T for
    60  // a subject ID, its (optional) conditional expression, any excluded subjects, and any sources
    61  // for bookkeeping. The sources are those other subjects that were combined to create the current
    62  // subject.
    63  type constructor[T Subject[T]] func(subjectID string, conditionalExpression *core.CaveatExpression, excludedSubjects []T, sources ...T) T
    64  
    65  // MustAdd adds the found subject to the set. This is equivalent to a Union operation between the
    66  // existing set of subjects and a set containing the single subject, but modifies the set
    67  // *in place*.
    68  func (bss BaseSubjectSet[T]) MustAdd(foundSubject T) {
    69  	err := bss.Add(foundSubject)
    70  	if err != nil {
    71  		panic(err)
    72  	}
    73  }
    74  
    75  // Add adds the found subject to the set. This is equivalent to a Union operation between the
    76  // existing set of subjects and a set containing the single subject, but modifies the set
    77  // *in place*.
    78  func (bss BaseSubjectSet[T]) Add(foundSubject T) error {
    79  	if foundSubject.GetSubjectId() == tuple.PublicWildcard {
    80  		existing := bss.wildcard.getOrNil()
    81  		updated, err := unionWildcardWithWildcard(existing, foundSubject, bss.constructor)
    82  		if err != nil {
    83  			return err
    84  		}
    85  
    86  		bss.wildcard.setOrNil(updated)
    87  
    88  		for _, concrete := range bss.concrete {
    89  			updated = unionWildcardWithConcrete(updated, concrete, bss.constructor)
    90  		}
    91  		bss.wildcard.setOrNil(updated)
    92  		return nil
    93  	}
    94  
    95  	var updatedOrNil *T
    96  	if updated, ok := bss.concrete[foundSubject.GetSubjectId()]; ok {
    97  		updatedOrNil = &updated
    98  	}
    99  	bss.setConcrete(foundSubject.GetSubjectId(), unionConcreteWithConcrete(updatedOrNil, &foundSubject, bss.constructor))
   100  
   101  	wildcard := bss.wildcard.getOrNil()
   102  	wildcard = unionWildcardWithConcrete(wildcard, foundSubject, bss.constructor)
   103  	bss.wildcard.setOrNil(wildcard)
   104  	return nil
   105  }
   106  
   107  func (bss BaseSubjectSet[T]) setConcrete(subjectID string, subjectOrNil *T) {
   108  	if subjectOrNil == nil {
   109  		delete(bss.concrete, subjectID)
   110  		return
   111  	}
   112  
   113  	subject := *subjectOrNil
   114  	bss.concrete[subject.GetSubjectId()] = subject
   115  }
   116  
   117  // Subtract subtracts the given subject found the set.
   118  func (bss BaseSubjectSet[T]) Subtract(toRemove T) {
   119  	if toRemove.GetSubjectId() == tuple.PublicWildcard {
   120  		for _, concrete := range bss.concrete {
   121  			bss.setConcrete(concrete.GetSubjectId(), subtractWildcardFromConcrete(concrete, toRemove, bss.constructor))
   122  		}
   123  
   124  		existing := bss.wildcard.getOrNil()
   125  		updatedWildcard, concretesToAdd := subtractWildcardFromWildcard(existing, toRemove, bss.constructor)
   126  		bss.wildcard.setOrNil(updatedWildcard)
   127  		for _, concrete := range concretesToAdd {
   128  			concrete := concrete
   129  			bss.setConcrete(concrete.GetSubjectId(), &concrete)
   130  		}
   131  		return
   132  	}
   133  
   134  	if existing, ok := bss.concrete[toRemove.GetSubjectId()]; ok {
   135  		bss.setConcrete(toRemove.GetSubjectId(), subtractConcreteFromConcrete(existing, toRemove, bss.constructor))
   136  	}
   137  
   138  	wildcard, ok := bss.wildcard.get()
   139  	if ok {
   140  		bss.wildcard.setOrNil(subtractConcreteFromWildcard(wildcard, toRemove, bss.constructor))
   141  	}
   142  }
   143  
   144  // SubtractAll subtracts the other set of subjects from this set of subtracts, modifying this
   145  // set *in place*.
   146  func (bss BaseSubjectSet[T]) SubtractAll(other BaseSubjectSet[T]) {
   147  	for _, otherSubject := range other.AsSlice() {
   148  		bss.Subtract(otherSubject)
   149  	}
   150  }
   151  
   152  // MustIntersectionDifference performs an intersection between this set and the other set, modifying
   153  // this set *in place*.
   154  func (bss BaseSubjectSet[T]) MustIntersectionDifference(other BaseSubjectSet[T]) {
   155  	err := bss.IntersectionDifference(other)
   156  	if err != nil {
   157  		panic(err)
   158  	}
   159  }
   160  
   161  // IntersectionDifference performs an intersection between this set and the other set, modifying
   162  // this set *in place*.
   163  func (bss BaseSubjectSet[T]) IntersectionDifference(other BaseSubjectSet[T]) error {
   164  	// Intersect the wildcards of the sets, if any.
   165  	existingWildcard := bss.wildcard.getOrNil()
   166  	otherWildcard := other.wildcard.getOrNil()
   167  
   168  	intersection, err := intersectWildcardWithWildcard(existingWildcard, otherWildcard, bss.constructor)
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	bss.wildcard.setOrNil(intersection)
   174  
   175  	// Intersect the concretes of each set, as well as with the wildcards.
   176  	updatedConcretes := make(map[string]T, len(bss.concrete))
   177  
   178  	for _, concreteSubject := range bss.concrete {
   179  		var otherConcreteOrNil *T
   180  		if otherConcrete, ok := other.concrete[concreteSubject.GetSubjectId()]; ok {
   181  			otherConcreteOrNil = &otherConcrete
   182  		}
   183  
   184  		concreteIntersected := intersectConcreteWithConcrete(concreteSubject, otherConcreteOrNil, bss.constructor)
   185  		otherWildcardIntersected, err := intersectConcreteWithWildcard(concreteSubject, otherWildcard, bss.constructor)
   186  		if err != nil {
   187  			return err
   188  		}
   189  
   190  		result := unionConcreteWithConcrete(concreteIntersected, otherWildcardIntersected, bss.constructor)
   191  		if result != nil {
   192  			updatedConcretes[concreteSubject.GetSubjectId()] = *result
   193  		}
   194  	}
   195  
   196  	if existingWildcard != nil {
   197  		for _, otherSubject := range other.concrete {
   198  			existingWildcardIntersect, err := intersectConcreteWithWildcard(otherSubject, existingWildcard, bss.constructor)
   199  			if err != nil {
   200  				return err
   201  			}
   202  
   203  			if existingUpdated, ok := updatedConcretes[otherSubject.GetSubjectId()]; ok {
   204  				result := unionConcreteWithConcrete(&existingUpdated, existingWildcardIntersect, bss.constructor)
   205  				updatedConcretes[otherSubject.GetSubjectId()] = *result
   206  			} else if existingWildcardIntersect != nil {
   207  				updatedConcretes[otherSubject.GetSubjectId()] = *existingWildcardIntersect
   208  			}
   209  		}
   210  	}
   211  
   212  	clear(bss.concrete)
   213  	maps.Copy(bss.concrete, updatedConcretes)
   214  	return nil
   215  }
   216  
   217  // UnionWith adds the given subjects to this set, via a union call.
   218  func (bss BaseSubjectSet[T]) UnionWith(foundSubjects []T) error {
   219  	for _, fs := range foundSubjects {
   220  		err := bss.Add(fs)
   221  		if err != nil {
   222  			return err
   223  		}
   224  	}
   225  	return nil
   226  }
   227  
   228  // UnionWithSet performs a union operation between this set and the other set, modifying this
   229  // set *in place*.
   230  func (bss BaseSubjectSet[T]) UnionWithSet(other BaseSubjectSet[T]) error {
   231  	return bss.UnionWith(other.AsSlice())
   232  }
   233  
   234  // MustUnionWithSet performs a union operation between this set and the other set, modifying this
   235  // set *in place*.
   236  func (bss BaseSubjectSet[T]) MustUnionWithSet(other BaseSubjectSet[T]) {
   237  	err := bss.UnionWithSet(other)
   238  	if err != nil {
   239  		panic(err)
   240  	}
   241  }
   242  
   243  // Get returns the found subject with the given ID in the set, if any.
   244  func (bss BaseSubjectSet[T]) Get(id string) (T, bool) {
   245  	if id == tuple.PublicWildcard {
   246  		return bss.wildcard.get()
   247  	}
   248  
   249  	found, ok := bss.concrete[id]
   250  	return found, ok
   251  }
   252  
   253  // IsEmpty returns whether the subject set is empty.
   254  func (bss BaseSubjectSet[T]) IsEmpty() bool {
   255  	return bss.wildcard.getOrNil() == nil && len(bss.concrete) == 0
   256  }
   257  
   258  // AsSlice returns the contents of the subject set as a slice of found subjects.
   259  func (bss BaseSubjectSet[T]) AsSlice() []T {
   260  	values := maps.Values(bss.concrete)
   261  	if wildcard, ok := bss.wildcard.get(); ok {
   262  		values = append(values, wildcard)
   263  	}
   264  	return values
   265  }
   266  
   267  // SubjectCount returns the number of subjects in the set.
   268  func (bss BaseSubjectSet[T]) SubjectCount() int {
   269  	if bss.HasWildcard() {
   270  		return bss.ConcreteSubjectCount() + 1
   271  	}
   272  	return bss.ConcreteSubjectCount()
   273  }
   274  
   275  // ConcreteSubjectCount returns the number of concrete subjects in the set.
   276  func (bss BaseSubjectSet[T]) ConcreteSubjectCount() int {
   277  	return len(bss.concrete)
   278  }
   279  
   280  // HasWildcard returns true if the subject set contains the specialized wildcard subject.
   281  func (bss BaseSubjectSet[T]) HasWildcard() bool {
   282  	_, ok := bss.wildcard.get()
   283  	return ok
   284  }
   285  
   286  // Clone returns a clone of this subject set. Note that this is a shallow clone.
   287  // NOTE: Should only be used when performance is not a concern.
   288  func (bss BaseSubjectSet[T]) Clone() BaseSubjectSet[T] {
   289  	return BaseSubjectSet[T]{
   290  		constructor: bss.constructor,
   291  		concrete:    maps.Clone(bss.concrete),
   292  		wildcard:    bss.wildcard.clone(),
   293  	}
   294  }
   295  
   296  // UnsafeRemoveExact removes the *exact* matching subject, with no wildcard handling.
   297  // This should ONLY be used for testing.
   298  func (bss BaseSubjectSet[T]) UnsafeRemoveExact(foundSubject T) {
   299  	if foundSubject.GetSubjectId() == tuple.PublicWildcard {
   300  		bss.wildcard.clear()
   301  		return
   302  	}
   303  
   304  	delete(bss.concrete, foundSubject.GetSubjectId())
   305  }
   306  
   307  // WithParentCaveatExpression returns a copy of the subject set with the parent caveat expression applied
   308  // to all members of this set.
   309  func (bss BaseSubjectSet[T]) WithParentCaveatExpression(parentCaveatExpr *core.CaveatExpression) BaseSubjectSet[T] {
   310  	clone := bss.Clone()
   311  
   312  	// Apply the parent caveat expression to the wildcard, if any.
   313  	if wildcard, ok := clone.wildcard.get(); ok {
   314  		constructed := bss.constructor(
   315  			tuple.PublicWildcard,
   316  			caveatAnd(parentCaveatExpr, wildcard.GetCaveatExpression()),
   317  			wildcard.GetExcludedSubjects(),
   318  			wildcard,
   319  		)
   320  		clone.wildcard.setOrNil(&constructed)
   321  	}
   322  
   323  	// Apply the parent caveat expression to each concrete.
   324  	for subjectID, concrete := range clone.concrete {
   325  		clone.concrete[subjectID] = bss.constructor(
   326  			subjectID,
   327  			caveatAnd(parentCaveatExpr, concrete.GetCaveatExpression()),
   328  			nil,
   329  			concrete,
   330  		)
   331  	}
   332  
   333  	return clone
   334  }
   335  
   336  // unionWildcardWithWildcard performs a union operation over two wildcards, returning the updated
   337  // wildcard (if any).
   338  func unionWildcardWithWildcard[T Subject[T]](existing *T, adding T, constructor constructor[T]) (*T, error) {
   339  	// If there is no existing wildcard, return the added one.
   340  	if existing == nil {
   341  		return &adding, nil
   342  	}
   343  
   344  	// Otherwise, union together the conditionals for the wildcards and *intersect* their exclusion
   345  	// sets.
   346  	existingWildcard := *existing
   347  	expression := shortcircuitedOr(existingWildcard.GetCaveatExpression(), adding.GetCaveatExpression())
   348  
   349  	// Exclusion sets are intersected because if an exclusion is missing from one wildcard
   350  	// but not the other, the missing element will be, by definition, in that other wildcard.
   351  	//
   352  	// Examples:
   353  	//
   354  	//	{*} + {*} => {*}
   355  	//	{* - {user:tom}} + {*} => {*}
   356  	//	{* - {user:tom}} + {* - {user:sarah}} => {*}
   357  	//	{* - {user:tom, user:sarah}} + {* - {user:sarah}} => {* - {user:sarah}}
   358  	//	{*}[c1] + {*} => {*}
   359  	//	{*}[c1] + {*}[c2] => {*}[c1 || c2]
   360  
   361  	// NOTE: since we're only using concretes here, it is safe to reuse the BaseSubjectSet itself.
   362  	exisingConcreteExclusions := NewBaseSubjectSet(constructor)
   363  	for _, excludedSubject := range existingWildcard.GetExcludedSubjects() {
   364  		if excludedSubject.GetSubjectId() == tuple.PublicWildcard {
   365  			return nil, spiceerrors.MustBugf("wildcards are not allowed in exclusions")
   366  		}
   367  
   368  		err := exisingConcreteExclusions.Add(excludedSubject)
   369  		if err != nil {
   370  			return nil, err
   371  		}
   372  	}
   373  
   374  	foundConcreteExclusions := NewBaseSubjectSet(constructor)
   375  	for _, excludedSubject := range adding.GetExcludedSubjects() {
   376  		if excludedSubject.GetSubjectId() == tuple.PublicWildcard {
   377  			return nil, spiceerrors.MustBugf("wildcards are not allowed in exclusions")
   378  		}
   379  
   380  		err := foundConcreteExclusions.Add(excludedSubject)
   381  		if err != nil {
   382  			return nil, err
   383  		}
   384  	}
   385  
   386  	err := exisingConcreteExclusions.IntersectionDifference(foundConcreteExclusions)
   387  	if err != nil {
   388  		return nil, err
   389  	}
   390  
   391  	constructed := constructor(
   392  		tuple.PublicWildcard,
   393  		expression,
   394  		exisingConcreteExclusions.AsSlice(),
   395  		*existing,
   396  		adding)
   397  	return &constructed, nil
   398  }
   399  
   400  // unionWildcardWithConcrete performs a union operation between a wildcard and a concrete subject
   401  // being added to the set, returning the updated wildcard (if applciable).
   402  func unionWildcardWithConcrete[T Subject[T]](existing *T, adding T, constructor constructor[T]) *T {
   403  	// If there is no existing wildcard, nothing more to do.
   404  	if existing == nil {
   405  		return nil
   406  	}
   407  
   408  	// If the concrete is in the exclusion set, remove it if not conditional. Otherwise, mark
   409  	// it as conditional.
   410  	//
   411  	// Examples:
   412  	//  {*} | {user:tom} => {*} (and user:tom in the concrete)
   413  	//  {* - {user:tom}} | {user:tom} => {*} (and user:tom in the concrete)
   414  	//  {* - {user:tom}[c1]} | {user:tom}[c2] => {* - {user:tom}[c1 && !c2]} (and user:tom in the concrete)
   415  	existingWildcard := *existing
   416  	updatedExclusions := make([]T, 0, len(existingWildcard.GetExcludedSubjects()))
   417  	for _, existingExclusion := range existingWildcard.GetExcludedSubjects() {
   418  		if existingExclusion.GetSubjectId() == adding.GetSubjectId() {
   419  			// If the conditional on the concrete is empty, then the concrete is always present, so
   420  			// we remove the exclusion entirely.
   421  			if adding.GetCaveatExpression() == nil {
   422  				continue
   423  			}
   424  
   425  			// Otherwise, the conditional expression for the new exclusion is the existing expression &&
   426  			// the *inversion* of the concrete's expression, as the exclusion will only apply if the
   427  			// concrete subject is not present and the exclusion's expression is true.
   428  			exclusionConditionalExpression := caveatAnd(
   429  				existingExclusion.GetCaveatExpression(),
   430  				caveatInvert(adding.GetCaveatExpression()),
   431  			)
   432  
   433  			updatedExclusions = append(updatedExclusions, constructor(
   434  				adding.GetSubjectId(),
   435  				exclusionConditionalExpression,
   436  				nil,
   437  				existingExclusion,
   438  				adding),
   439  			)
   440  		} else {
   441  			updatedExclusions = append(updatedExclusions, existingExclusion)
   442  		}
   443  	}
   444  
   445  	constructed := constructor(
   446  		tuple.PublicWildcard,
   447  		existingWildcard.GetCaveatExpression(),
   448  		updatedExclusions,
   449  		existingWildcard)
   450  	return &constructed
   451  }
   452  
   453  // unionConcreteWithConcrete performs a union operation between two concrete subjects and returns
   454  // the concrete subject produced, if any.
   455  func unionConcreteWithConcrete[T Subject[T]](existing *T, adding *T, constructor constructor[T]) *T {
   456  	// Check for union with other concretes.
   457  	if existing == nil {
   458  		return adding
   459  	}
   460  
   461  	if adding == nil {
   462  		return existing
   463  	}
   464  
   465  	existingConcrete := *existing
   466  	addingConcrete := *adding
   467  
   468  	// A union of a concrete subjects has the conditionals of each concrete merged.
   469  	constructed := constructor(
   470  		existingConcrete.GetSubjectId(),
   471  		shortcircuitedOr(
   472  			existingConcrete.GetCaveatExpression(),
   473  			addingConcrete.GetCaveatExpression(),
   474  		),
   475  		nil,
   476  		existingConcrete, addingConcrete)
   477  	return &constructed
   478  }
   479  
   480  // subtractWildcardFromWildcard performs a subtraction operation of wildcard from another, returning
   481  // the updated wildcard (if any), as well as any concrete subjects produced by the subtraction
   482  // operation due to exclusions.
   483  func subtractWildcardFromWildcard[T Subject[T]](existing *T, toRemove T, constructor constructor[T]) (*T, []T) {
   484  	// If there is no existing wildcard, nothing more to do.
   485  	if existing == nil {
   486  		return nil, nil
   487  	}
   488  
   489  	// If there is no condition on the wildcard and the new wildcard has no exclusions, then this wildcard goes away.
   490  	// Example: {*} - {*} => {}
   491  	if toRemove.GetCaveatExpression() == nil && len(toRemove.GetExcludedSubjects()) == 0 {
   492  		return nil, nil
   493  	}
   494  
   495  	// Otherwise, we construct a new wildcard and return any concrete subjects that might result from this subtraction.
   496  	existingWildcard := *existing
   497  	existingExclusions := exclusionsMapFor(existingWildcard)
   498  
   499  	// Calculate the exclusions which turn into concrete subjects.
   500  	// This occurs when a wildcard with exclusions is subtracted from a wildcard
   501  	// (with, or without *matching* exclusions).
   502  	//
   503  	// Example:
   504  	// Given the two wildcards `* - {user:sarah}` and `* - {user:tom, user:amy, user:sarah}`,
   505  	// the resulting concrete subjects are {user:tom, user:amy} because the first set contains
   506  	// `tom` and `amy` (but not `sarah`) and the second set contains all three.
   507  	resultingConcreteSubjects := make([]T, 0, len(toRemove.GetExcludedSubjects()))
   508  	for _, excludedSubject := range toRemove.GetExcludedSubjects() {
   509  		if existingExclusion, isExistingExclusion := existingExclusions[excludedSubject.GetSubjectId()]; !isExistingExclusion || existingExclusion.GetCaveatExpression() != nil {
   510  			// The conditional expression for the now-concrete subject type is the conditional on the provided exclusion
   511  			// itself.
   512  			//
   513  			// As an example, subtracting the wildcards
   514  			// {*[caveat1] - {user:tom}}
   515  			// -
   516  			// {*[caveat3] - {user:sarah[caveat4]}}
   517  			//
   518  			// the resulting expression to produce a *concrete* `user:sarah` is
   519  			// `caveat1 && caveat3 && caveat4`, because the concrete subject only appears if the first
   520  			// wildcard applies, the *second* wildcard applies and its exclusion applies.
   521  			exclusionConditionalExpression := caveatAnd(
   522  				caveatAnd(
   523  					existingWildcard.GetCaveatExpression(),
   524  					toRemove.GetCaveatExpression(),
   525  				),
   526  				excludedSubject.GetCaveatExpression(),
   527  			)
   528  
   529  			// If there is an existing exclusion, then its caveat expression is added as well, but inverted.
   530  			//
   531  			// As an example, subtracting the wildcards
   532  			// {*[caveat1] - {user:tom[caveat2]}}
   533  			// -
   534  			// {*[caveat3] - {user:sarah[caveat4]}}
   535  			//
   536  			// the resulting expression to produce a *concrete* `user:sarah` is
   537  			// `caveat1 && !caveat2 && caveat3 && caveat4`, because the concrete subject only appears
   538  			// if the first wildcard applies, the *second* wildcard applies, the first exclusion
   539  			// does *not* apply (ensuring the concrete is in the first wildcard) and the second exclusion
   540  			// *does* apply (ensuring it is not in the second wildcard).
   541  			if existingExclusion.GetCaveatExpression() != nil {
   542  				exclusionConditionalExpression = caveatAnd(
   543  					caveatAnd(
   544  						caveatAnd(
   545  							existingWildcard.GetCaveatExpression(),
   546  							toRemove.GetCaveatExpression(),
   547  						),
   548  						caveatInvert(existingExclusion.GetCaveatExpression()),
   549  					),
   550  					excludedSubject.GetCaveatExpression(),
   551  				)
   552  			}
   553  
   554  			resultingConcreteSubjects = append(resultingConcreteSubjects, constructor(
   555  				excludedSubject.GetSubjectId(),
   556  				exclusionConditionalExpression,
   557  				nil, excludedSubject))
   558  		}
   559  	}
   560  
   561  	// Create the combined conditional: the wildcard can only exist when it is present and the other wildcard is not.
   562  	combinedConditionalExpression := caveatAnd(existingWildcard.GetCaveatExpression(), caveatInvert(toRemove.GetCaveatExpression()))
   563  	if combinedConditionalExpression != nil {
   564  		constructed := constructor(
   565  			tuple.PublicWildcard,
   566  			combinedConditionalExpression,
   567  			existingWildcard.GetExcludedSubjects(),
   568  			existingWildcard,
   569  			toRemove)
   570  		return &constructed, resultingConcreteSubjects
   571  	}
   572  
   573  	return nil, resultingConcreteSubjects
   574  }
   575  
   576  // subtractWildcardFromConcrete subtracts a wildcard from a concrete element, returning the updated
   577  // concrete subject, if any.
   578  func subtractWildcardFromConcrete[T Subject[T]](existingConcrete T, wildcardToRemove T, constructor constructor[T]) *T {
   579  	// Subtraction of a wildcard removes *all* elements of the concrete set, except those that
   580  	// are found in the excluded list. If the wildcard *itself* is conditional, then instead of
   581  	// items being removed, they are made conditional on the inversion of the wildcard's expression,
   582  	// and the exclusion's conditional, if any.
   583  	//
   584  	// Examples:
   585  	//  {user:sarah, user:tom} - {*} => {}
   586  	//  {user:sarah, user:tom} - {*[somecaveat]} => {user:sarah[!somecaveat], user:tom[!somecaveat]}
   587  	//  {user:sarah, user:tom} - {* - {user:tom}} => {user:tom}
   588  	//  {user:sarah, user:tom} - {*[somecaveat] - {user:tom}} => {user:sarah[!somecaveat], user:tom}
   589  	//  {user:sarah, user:tom} - {* - {user:tom[c2]}}[somecaveat] => {user:sarah[!somecaveat], user:tom[c2]}
   590  	//  {user:sarah[c1], user:tom} - {*[somecaveat] - {user:tom}} => {user:sarah[c1 && !somecaveat], user:tom}
   591  	exclusions := exclusionsMapFor(wildcardToRemove)
   592  	exclusion, isExcluded := exclusions[existingConcrete.GetSubjectId()]
   593  	if !isExcluded {
   594  		// If the subject was not excluded within the wildcard, it is either removed directly
   595  		// (in the case where the wildcard is not conditional), or has its condition updated to
   596  		// reflect that it is only present when the condition for the wildcard is *false*.
   597  		if wildcardToRemove.GetCaveatExpression() == nil {
   598  			return nil
   599  		}
   600  
   601  		constructed := constructor(
   602  			existingConcrete.GetSubjectId(),
   603  			caveatAnd(existingConcrete.GetCaveatExpression(), caveatInvert(wildcardToRemove.GetCaveatExpression())),
   604  			nil,
   605  			existingConcrete)
   606  		return &constructed
   607  	}
   608  
   609  	// If the exclusion is not conditional, then the subject is always present.
   610  	if exclusion.GetCaveatExpression() == nil {
   611  		return &existingConcrete
   612  	}
   613  
   614  	// The conditional of the exclusion is that of the exclusion itself OR the caveatInverted case of
   615  	// the wildcard, which would mean the wildcard itself does not apply.
   616  	exclusionConditional := caveatOr(caveatInvert(wildcardToRemove.GetCaveatExpression()), exclusion.GetCaveatExpression())
   617  
   618  	constructed := constructor(
   619  		existingConcrete.GetSubjectId(),
   620  		caveatAnd(existingConcrete.GetCaveatExpression(), exclusionConditional),
   621  		nil,
   622  		existingConcrete)
   623  	return &constructed
   624  }
   625  
   626  // subtractConcreteFromConcrete subtracts a concrete subject from another concrete subject.
   627  func subtractConcreteFromConcrete[T Subject[T]](existingConcrete T, toRemove T, constructor constructor[T]) *T {
   628  	// Subtraction of a concrete type removes the entry from the concrete list
   629  	// *unless* the subtraction is conditional, in which case the conditional is updated
   630  	// to remove the element when it is true.
   631  	//
   632  	// Examples:
   633  	//  {user:sarah} - {user:tom} => {user:sarah}
   634  	//  {user:tom} - {user:tom} => {}
   635  	//  {user:tom[c1]} - {user:tom} => {user:tom}
   636  	//  {user:tom} - {user:tom[c2]} => {user:tom[!c2]}
   637  	//  {user:tom[c1]} - {user:tom[c2]} => {user:tom[c1 && !c2]}
   638  	if toRemove.GetCaveatExpression() == nil {
   639  		return nil
   640  	}
   641  
   642  	// Otherwise, adjust the conditional of the existing item to remove it if it is true.
   643  	expression := caveatAnd(
   644  		existingConcrete.GetCaveatExpression(),
   645  		caveatInvert(
   646  			toRemove.GetCaveatExpression(),
   647  		),
   648  	)
   649  
   650  	constructed := constructor(
   651  		existingConcrete.GetSubjectId(),
   652  		expression,
   653  		nil,
   654  		existingConcrete, toRemove)
   655  	return &constructed
   656  }
   657  
   658  // subtractConcreteFromWildcard subtracts a concrete element from a wildcard.
   659  func subtractConcreteFromWildcard[T Subject[T]](wildcard T, concreteToRemove T, constructor constructor[T]) *T {
   660  	// Subtracting a concrete type from a wildcard adds the concrete to the exclusions for the wildcard.
   661  	// Examples:
   662  	//  {*} - {user:tom} => {* - {user:tom}}
   663  	//  {*} - {user:tom[c1]} => {* - {user:tom[c1]}}
   664  	//  {* - {user:tom[c1]}} - {user:tom} => {* - {user:tom}}
   665  	//  {* - {user:tom[c1]}} - {user:tom[c2]} => {* - {user:tom[c1 || c2]}}
   666  	updatedExclusions := make([]T, 0, len(wildcard.GetExcludedSubjects())+1)
   667  	wasFound := false
   668  	for _, existingExclusion := range wildcard.GetExcludedSubjects() {
   669  		if existingExclusion.GetSubjectId() == concreteToRemove.GetSubjectId() {
   670  			// The conditional expression for the exclusion is a combination on the existing exclusion or
   671  			// the new expression. The caveat is short-circuited here because if either the exclusion or
   672  			// the concrete is non-caveated, then the whole exclusion is non-caveated.
   673  			exclusionConditionalExpression := shortcircuitedOr(
   674  				existingExclusion.GetCaveatExpression(),
   675  				concreteToRemove.GetCaveatExpression(),
   676  			)
   677  
   678  			updatedExclusions = append(updatedExclusions, constructor(
   679  				concreteToRemove.GetSubjectId(),
   680  				exclusionConditionalExpression,
   681  				nil,
   682  				existingExclusion,
   683  				concreteToRemove),
   684  			)
   685  			wasFound = true
   686  		} else {
   687  			updatedExclusions = append(updatedExclusions, existingExclusion)
   688  		}
   689  	}
   690  
   691  	if !wasFound {
   692  		updatedExclusions = append(updatedExclusions, concreteToRemove)
   693  	}
   694  
   695  	constructed := constructor(
   696  		tuple.PublicWildcard,
   697  		wildcard.GetCaveatExpression(),
   698  		updatedExclusions,
   699  		wildcard)
   700  	return &constructed
   701  }
   702  
   703  // intersectConcreteWithConcrete performs intersection between two concrete subjects, returning the
   704  // resolved concrete subject, if any.
   705  func intersectConcreteWithConcrete[T Subject[T]](first T, second *T, constructor constructor[T]) *T {
   706  	// Intersection of concrete subjects is a standard intersection operation, where subjects
   707  	// must be in both sets, with a combination of the two elements into one for conditionals.
   708  	// Otherwise, `and` together conditionals.
   709  	if second == nil {
   710  		return nil
   711  	}
   712  
   713  	secondConcrete := *second
   714  	constructed := constructor(
   715  		first.GetSubjectId(),
   716  		caveatAnd(first.GetCaveatExpression(), secondConcrete.GetCaveatExpression()),
   717  		nil,
   718  		first,
   719  		secondConcrete)
   720  
   721  	return &constructed
   722  }
   723  
   724  // intersectWildcardWithWildcard performs intersection between two wildcards, returning the resolved
   725  // wildcard subject, if any.
   726  func intersectWildcardWithWildcard[T Subject[T]](first *T, second *T, constructor constructor[T]) (*T, error) {
   727  	// If either wildcard does not exist, then no wildcard is placed into the resulting set.
   728  	if first == nil || second == nil {
   729  		return nil, nil
   730  	}
   731  
   732  	// If the other wildcard exists, then the intersection between the two wildcards is an && of
   733  	// their conditionals, and a *union* of their exclusions.
   734  	firstWildcard := *first
   735  	secondWildcard := *second
   736  
   737  	concreteExclusions := NewBaseSubjectSet(constructor)
   738  	for _, excludedSubject := range firstWildcard.GetExcludedSubjects() {
   739  		if excludedSubject.GetSubjectId() == tuple.PublicWildcard {
   740  			return nil, spiceerrors.MustBugf("wildcards are not allowed in exclusions")
   741  		}
   742  
   743  		err := concreteExclusions.Add(excludedSubject)
   744  		if err != nil {
   745  			return nil, err
   746  		}
   747  	}
   748  
   749  	for _, excludedSubject := range secondWildcard.GetExcludedSubjects() {
   750  		if excludedSubject.GetSubjectId() == tuple.PublicWildcard {
   751  			return nil, spiceerrors.MustBugf("wildcards are not allowed in exclusions")
   752  		}
   753  
   754  		err := concreteExclusions.Add(excludedSubject)
   755  		if err != nil {
   756  			return nil, err
   757  		}
   758  	}
   759  
   760  	constructed := constructor(
   761  		tuple.PublicWildcard,
   762  		caveatAnd(firstWildcard.GetCaveatExpression(), secondWildcard.GetCaveatExpression()),
   763  		concreteExclusions.AsSlice(),
   764  		firstWildcard,
   765  		secondWildcard)
   766  	return &constructed, nil
   767  }
   768  
   769  // intersectConcreteWithWildcard performs intersection between a concrete subject and a wildcard
   770  // subject, returning the concrete, if any.
   771  func intersectConcreteWithWildcard[T Subject[T]](concrete T, wildcard *T, constructor constructor[T]) (*T, error) {
   772  	// If no wildcard exists, then the concrete cannot exist (for this branch)
   773  	if wildcard == nil {
   774  		return nil, nil
   775  	}
   776  
   777  	wildcardToIntersect := *wildcard
   778  	exclusionsMap := exclusionsMapFor(wildcardToIntersect)
   779  	exclusion, isExcluded := exclusionsMap[concrete.GetSubjectId()]
   780  
   781  	// Cases:
   782  	// - The concrete subject is not excluded and the wildcard is not conditional => concrete is kept
   783  	// - The concrete subject is excluded and the wildcard is not conditional but the exclusion *is* conditional => concrete is made conditional
   784  	// - The concrete subject is excluded and the wildcard is not conditional => concrete is removed
   785  	// - The concrete subject is not excluded but the wildcard is conditional => concrete is kept, but made conditional
   786  	// - The concrete subject is excluded and the wildcard is conditional => concrete is removed, since it is always excluded
   787  	// - The concrete subject is excluded and the wildcard is conditional and the exclusion is conditional => combined conditional
   788  	switch {
   789  	case !isExcluded && wildcardToIntersect.GetCaveatExpression() == nil:
   790  		// If the concrete is not excluded and the wildcard conditional is empty, then the concrete is always found.
   791  		// Example: {user:tom} & {*} => {user:tom}
   792  		return &concrete, nil
   793  
   794  	case !isExcluded && wildcardToIntersect.GetCaveatExpression() != nil:
   795  		// The concrete subject is only included if the wildcard's caveat is true.
   796  		// Example: {user:tom}[acaveat] & {* - user:tom}[somecaveat] => {user:tom}[acaveat && somecaveat]
   797  		constructed := constructor(
   798  			concrete.GetSubjectId(),
   799  			caveatAnd(concrete.GetCaveatExpression(), wildcardToIntersect.GetCaveatExpression()),
   800  			nil,
   801  			concrete,
   802  			wildcardToIntersect)
   803  		return &constructed, nil
   804  
   805  	case isExcluded && exclusion.GetCaveatExpression() == nil:
   806  		// If the concrete is excluded and the exclusion is not conditional, then the concrete can never show up,
   807  		// regardless of whether the wildcard is conditional.
   808  		// Example: {user:tom} & {* - user:tom}[somecaveat] => {}
   809  		return nil, nil
   810  
   811  	case isExcluded && exclusion.GetCaveatExpression() != nil:
   812  		// NOTE: whether the wildcard is itself conditional or not is handled within the expression combinators below.
   813  		// The concrete subject is included if the wildcard's caveat is true and the exclusion's caveat is *false*.
   814  		// Example: {user:tom}[acaveat] & {* - user:tom[ecaveat]}[wcaveat] => {user:tom[acaveat && wcaveat && !ecaveat]}
   815  		constructed := constructor(
   816  			concrete.GetSubjectId(),
   817  			caveatAnd(
   818  				concrete.GetCaveatExpression(),
   819  				caveatAnd(
   820  					wildcardToIntersect.GetCaveatExpression(),
   821  					caveatInvert(exclusion.GetCaveatExpression()),
   822  				)),
   823  			nil,
   824  			concrete,
   825  			wildcardToIntersect,
   826  			exclusion)
   827  		return &constructed, nil
   828  
   829  	default:
   830  		return nil, spiceerrors.MustBugf("unhandled case in basesubjectset intersectConcreteWithWildcard: %v & %v", concrete, wildcardToIntersect)
   831  	}
   832  }
   833  
   834  type handle[T any] struct {
   835  	value *T
   836  }
   837  
   838  func newHandle[T any]() *handle[T] {
   839  	return &handle[T]{}
   840  }
   841  
   842  func (h *handle[T]) getOrNil() *T {
   843  	return h.value
   844  }
   845  
   846  func (h *handle[T]) setOrNil(value *T) {
   847  	h.value = value
   848  }
   849  
   850  func (h *handle[T]) get() (T, bool) {
   851  	if h.value != nil {
   852  		return *h.value, true
   853  	}
   854  
   855  	return *new(T), false
   856  }
   857  
   858  func (h *handle[T]) clear() {
   859  	h.value = nil
   860  }
   861  
   862  func (h *handle[T]) clone() *handle[T] {
   863  	return &handle[T]{
   864  		value: h.value,
   865  	}
   866  }
   867  
   868  // exclusionsMapFor creates a map of all the exclusions on a wildcard, by subject ID.
   869  func exclusionsMapFor[T Subject[T]](wildcard T) map[string]T {
   870  	exclusions := make(map[string]T, len(wildcard.GetExcludedSubjects()))
   871  	for _, excludedSubject := range wildcard.GetExcludedSubjects() {
   872  		exclusions[excludedSubject.GetSubjectId()] = excludedSubject
   873  	}
   874  	return exclusions
   875  }