github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/development/warningdefs.go (about)

     1  package development
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	corev1 "github.com/authzed/spicedb/pkg/proto/core/v1"
     9  	devinterface "github.com/authzed/spicedb/pkg/proto/developer/v1"
    10  	"github.com/authzed/spicedb/pkg/tuple"
    11  	"github.com/authzed/spicedb/pkg/typesystem"
    12  )
    13  
    14  var lintRelationReferencesParentType = func(
    15  	ctx context.Context,
    16  	relation *corev1.Relation,
    17  	ts *typesystem.TypeSystem,
    18  ) (*devinterface.DeveloperWarning, error) {
    19  	parentDef := ts.Namespace()
    20  	if strings.HasSuffix(relation.Name, parentDef.Name) {
    21  		if ts.IsPermission(relation.Name) {
    22  			return warningForMetadata(
    23  				fmt.Sprintf("Permission %q references parent type %q in its name; it is recommended to drop the suffix", relation.Name, parentDef.Name),
    24  				relation,
    25  			), nil
    26  		}
    27  
    28  		return warningForMetadata(
    29  			fmt.Sprintf("Relation %q references parent type %q in its name; it is recommended to drop the suffix", relation.Name, parentDef.Name),
    30  			relation,
    31  		), nil
    32  	}
    33  
    34  	return nil, nil
    35  }
    36  
    37  var lintPermissionReferencingItself = func(
    38  	ctx context.Context,
    39  	computedUserset *corev1.ComputedUserset,
    40  	sourcePosition *corev1.SourcePosition,
    41  	ts *typesystem.TypeSystem,
    42  ) (*devinterface.DeveloperWarning, error) {
    43  	parentRelation := ctx.Value(relationKey).(*corev1.Relation)
    44  	permName := parentRelation.Name
    45  	if computedUserset.Relation == permName {
    46  		return warningForPosition(
    47  			fmt.Sprintf("Permission %q references itself, which will cause an error to be raised due to infinite recursion", permName),
    48  			sourcePosition,
    49  		), nil
    50  	}
    51  
    52  	return nil, nil
    53  }
    54  
    55  var lintArrowReferencingUnreachable = func(
    56  	ctx context.Context,
    57  	ttu *corev1.TupleToUserset,
    58  	sourcePosition *corev1.SourcePosition,
    59  	ts *typesystem.TypeSystem,
    60  ) (*devinterface.DeveloperWarning, error) {
    61  	parentRelation := ctx.Value(relationKey).(*corev1.Relation)
    62  
    63  	referencedRelation, ok := ts.GetRelation(ttu.Tupleset.Relation)
    64  	if !ok {
    65  		return nil, nil
    66  	}
    67  
    68  	allowedSubjectTypes, err := ts.AllowedSubjectRelations(referencedRelation.Name)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	wasFound := false
    74  	for _, subjectType := range allowedSubjectTypes {
    75  		nts, err := ts.TypeSystemForNamespace(ctx, subjectType.Namespace)
    76  		if err != nil {
    77  			return nil, err
    78  		}
    79  
    80  		_, ok := nts.GetRelation(ttu.ComputedUserset.Relation)
    81  		if ok {
    82  			wasFound = true
    83  		}
    84  	}
    85  
    86  	if !wasFound {
    87  		return warningForPosition(
    88  			fmt.Sprintf(
    89  				"Arrow `%s->%s` under permission %q references relation/permission %q that does not exist on any subject types of relation %q",
    90  				ttu.Tupleset.Relation,
    91  				ttu.ComputedUserset.Relation,
    92  				parentRelation.Name,
    93  				ttu.ComputedUserset.Relation,
    94  				ttu.Tupleset.Relation,
    95  			),
    96  			sourcePosition,
    97  		), nil
    98  	}
    99  
   100  	return nil, nil
   101  }
   102  
   103  var lintArrowOverSubRelation = func(
   104  	ctx context.Context,
   105  	ttu *corev1.TupleToUserset,
   106  	sourcePosition *corev1.SourcePosition,
   107  	ts *typesystem.TypeSystem,
   108  ) (*devinterface.DeveloperWarning, error) {
   109  	parentRelation := ctx.Value(relationKey).(*corev1.Relation)
   110  
   111  	referencedRelation, ok := ts.GetRelation(ttu.Tupleset.Relation)
   112  	if !ok {
   113  		return nil, nil
   114  	}
   115  
   116  	allowedSubjectTypes, err := ts.AllowedSubjectRelations(referencedRelation.Name)
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	for _, subjectType := range allowedSubjectTypes {
   122  		if subjectType.Relation != tuple.Ellipsis {
   123  			return warningForPosition(
   124  				fmt.Sprintf(
   125  					"Arrow `%s->%s` under permission %q references relation %q that has relation %q on subject %q: *the subject relation will be ignored for the arrow*",
   126  					ttu.Tupleset.Relation,
   127  					ttu.ComputedUserset.Relation,
   128  					parentRelation.Name,
   129  					ttu.Tupleset.Relation,
   130  					subjectType.Relation,
   131  					subjectType.Namespace,
   132  				),
   133  				sourcePosition,
   134  			), nil
   135  		}
   136  	}
   137  
   138  	return nil, nil
   139  }
   140  
   141  var lintArrowReferencingRelation = func(
   142  	ctx context.Context,
   143  	ttu *corev1.TupleToUserset,
   144  	sourcePosition *corev1.SourcePosition,
   145  	ts *typesystem.TypeSystem,
   146  ) (*devinterface.DeveloperWarning, error) {
   147  	parentRelation := ctx.Value(relationKey).(*corev1.Relation)
   148  
   149  	referencedRelation, ok := ts.GetRelation(ttu.Tupleset.Relation)
   150  	if !ok {
   151  		return nil, nil
   152  	}
   153  
   154  	// For each subject type of the referenced relation, check if the referenced permission
   155  	// is, in fact, a relation.
   156  	allowedSubjectTypes, err := ts.AllowedSubjectRelations(referencedRelation.Name)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	for _, subjectType := range allowedSubjectTypes {
   162  		nts, err := ts.TypeSystemForNamespace(ctx, subjectType.Namespace)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  
   167  		targetRelation, ok := nts.GetRelation(ttu.ComputedUserset.Relation)
   168  		if !ok {
   169  			continue
   170  		}
   171  
   172  		if !nts.IsPermission(targetRelation.Name) {
   173  			return warningForPosition(
   174  				fmt.Sprintf(
   175  					"Arrow `%s->%s` under permission %q references relation %q on definition %q; it is recommended to point to a permission",
   176  					ttu.Tupleset.Relation,
   177  					ttu.ComputedUserset.Relation,
   178  					parentRelation.Name,
   179  					targetRelation.Name,
   180  					subjectType.Namespace,
   181  				),
   182  				sourcePosition,
   183  			), nil
   184  		}
   185  	}
   186  
   187  	return nil, nil
   188  }