...

Source file src/go.einride.tech/aip/reflect/aipreflect/validateresourcereferences.go

Documentation: go.einride.tech/aip/reflect/aipreflect

     1  package aipreflect
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"go.einride.tech/aip/resourcename"
     8  	"google.golang.org/genproto/googleapis/api/annotations"
     9  	"google.golang.org/protobuf/proto"
    10  	"google.golang.org/protobuf/reflect/protopath"
    11  	"google.golang.org/protobuf/reflect/protorange"
    12  	"google.golang.org/protobuf/reflect/protoreflect"
    13  	"google.golang.org/protobuf/reflect/protoregistry"
    14  )
    15  
    16  // ValidateResourceReferences validates the resource reference fields in a message.
    17  func ValidateResourceReferences(message proto.Message) error {
    18  	return protorange.Range(message.ProtoReflect(), func(values protopath.Values) error {
    19  		curr := values.Index(-1)
    20  		var field protoreflect.FieldDescriptor
    21  		var fieldValue string
    22  		switch curr.Step.Kind() {
    23  		case protopath.FieldAccessStep:
    24  			field = curr.Step.FieldDescriptor()
    25  			if field.Kind() != protoreflect.StringKind {
    26  				return nil
    27  			}
    28  			if field.Cardinality() == protoreflect.Repeated {
    29  				return nil
    30  			}
    31  			fieldValue = curr.Value.String()
    32  		case protopath.ListIndexStep:
    33  			prev := values.Index(-2)
    34  			field = prev.Step.FieldDescriptor()
    35  			if field.Kind() != protoreflect.StringKind {
    36  				return nil
    37  			}
    38  			fieldValue = curr.Value.String()
    39  		default:
    40  			return nil
    41  		}
    42  		resourceReferenceAnnotation := proto.GetExtension(
    43  			field.Options(), annotations.E_ResourceReference,
    44  		).(*annotations.ResourceReference)
    45  		if resourceReferenceAnnotation == nil {
    46  			return nil
    47  		}
    48  		var errValidate error
    49  		RangeResourceDescriptorsInPackage(
    50  			protoregistry.GlobalFiles,
    51  			field.ParentFile().Package(),
    52  			func(resource *annotations.ResourceDescriptor) bool {
    53  				if resource.GetType() != resourceReferenceAnnotation.GetType() {
    54  					return true
    55  				}
    56  				for _, pattern := range resource.GetPattern() {
    57  					if resourcename.Match(pattern, fieldValue) {
    58  						return false
    59  					}
    60  				}
    61  				errValidate = fmt.Errorf(
    62  					"value '%s' of field %s is not a valid resource reference for %s",
    63  					fieldValue,
    64  					// trim the message type from the path
    65  					strings.TrimLeft(strings.TrimLeftFunc(values.Path.String(), func(r rune) bool {
    66  						return r != ')'
    67  					}), ")."),
    68  					resourceReferenceAnnotation.GetType(),
    69  				)
    70  				return false
    71  			},
    72  		)
    73  		return errValidate
    74  	})
    75  }
    76  

View as plain text