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

     1  package namespace
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"golang.org/x/exp/maps"
     7  
     8  	"github.com/authzed/spicedb/pkg/caveats"
     9  	caveattypes "github.com/authzed/spicedb/pkg/caveats/types"
    10  	core "github.com/authzed/spicedb/pkg/proto/core/v1"
    11  	"github.com/authzed/spicedb/pkg/typesystem"
    12  )
    13  
    14  // ValidateCaveatDefinition validates the parameters and types within the given caveat
    15  // definition, including usage of the parameters.
    16  func ValidateCaveatDefinition(caveat *core.CaveatDefinition) error {
    17  	// Ensure all parameters are used by the caveat expression itself.
    18  	parameterTypes, err := caveattypes.DecodeParameterTypes(caveat.ParameterTypes)
    19  	if err != nil {
    20  		return typesystem.NewTypeErrorWithSource(
    21  			fmt.Errorf("could not decode caveat parameters `%s`: %w", caveat.Name, err),
    22  			caveat,
    23  			caveat.Name,
    24  		)
    25  	}
    26  
    27  	deserialized, err := caveats.DeserializeCaveat(caveat.SerializedExpression, parameterTypes)
    28  	if err != nil {
    29  		return typesystem.NewTypeErrorWithSource(
    30  			fmt.Errorf("could not decode caveat `%s`: %w", caveat.Name, err),
    31  			caveat,
    32  			caveat.Name,
    33  		)
    34  	}
    35  
    36  	if len(caveat.ParameterTypes) == 0 {
    37  		return typesystem.NewTypeErrorWithSource(
    38  			fmt.Errorf("caveat `%s` must have at least one parameter defined", caveat.Name),
    39  			caveat,
    40  			caveat.Name,
    41  		)
    42  	}
    43  
    44  	referencedNames, err := deserialized.ReferencedParameters(maps.Keys(caveat.ParameterTypes))
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	for paramName, paramType := range caveat.ParameterTypes {
    50  		_, err := caveattypes.DecodeParameterType(paramType)
    51  		if err != nil {
    52  			return typesystem.NewTypeErrorWithSource(
    53  				fmt.Errorf("type error for parameter `%s` for caveat `%s`: %w", paramName, caveat.Name, err),
    54  				caveat,
    55  				paramName,
    56  			)
    57  		}
    58  
    59  		if !referencedNames.Has(paramName) {
    60  			return typesystem.NewTypeErrorWithSource(
    61  				NewUnusedCaveatParameterErr(caveat.Name, paramName),
    62  				caveat,
    63  				paramName,
    64  			)
    65  		}
    66  	}
    67  
    68  	return nil
    69  }