summaryrefslogtreecommitdiff
path: root/vendor/github.com/bufbuild/protocompile/options/source_retention_options.go
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-05-20 14:28:06 -0600
committermo khan <mo@mokhan.ca>2025-05-23 14:49:19 -0600
commit4beee46dc6c7642316e118a4d3aa51e4b407256e (patch)
tree039bdf57b99061844aeb0fe55ad0bc1c864166af /vendor/github.com/bufbuild/protocompile/options/source_retention_options.go
parent0ba49bfbde242920d8675a193d7af89420456fc0 (diff)
feat: add external authorization service (authzd) with JWT authentication
- Add new authzd gRPC service implementing Envoy's external authorization API - Integrate JWT authentication filter in Envoy configuration with claim extraction - Update middleware to support both cookie-based and header-based user authentication - Add comprehensive test coverage for authorization service and server - Configure proper service orchestration with authzd, sparkled, and Envoy - Update build system and Docker configuration for multi-service deployment - Add grpcurl tool for gRPC service debugging and testing This enables fine-grained authorization control through Envoy's ext_authz filter while maintaining backward compatibility with existing cookie-based authentication.
Diffstat (limited to 'vendor/github.com/bufbuild/protocompile/options/source_retention_options.go')
-rw-r--r--vendor/github.com/bufbuild/protocompile/options/source_retention_options.go539
1 files changed, 539 insertions, 0 deletions
diff --git a/vendor/github.com/bufbuild/protocompile/options/source_retention_options.go b/vendor/github.com/bufbuild/protocompile/options/source_retention_options.go
new file mode 100644
index 0000000..05c3e29
--- /dev/null
+++ b/vendor/github.com/bufbuild/protocompile/options/source_retention_options.go
@@ -0,0 +1,539 @@
+// Copyright 2020-2024 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package options
+
+import (
+ "fmt"
+
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/types/descriptorpb"
+
+ "github.com/bufbuild/protocompile/internal"
+)
+
+// StripSourceRetentionOptionsFromFile returns a file descriptor proto that omits any
+// options in file that are defined to be retained only in source. If file has no
+// such options, then it is returned as is. If it does have such options, a copy is
+// made; the given file will not be mutated.
+//
+// Even when a copy is returned, it is not a deep copy: it may share data with the
+// original file. So callers should not mutate the returned file unless mutating the
+// input file is also safe.
+func StripSourceRetentionOptionsFromFile(file *descriptorpb.FileDescriptorProto) (*descriptorpb.FileDescriptorProto, error) {
+ var path sourcePath
+ var removedPaths *sourcePathTrie
+ if file.SourceCodeInfo != nil && len(file.SourceCodeInfo.Location) > 0 {
+ path = make(sourcePath, 0, 16)
+ removedPaths = &sourcePathTrie{}
+ }
+ var dirty bool
+ optionsPath := path.push(internal.FileOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(file.GetOptions(), optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts != file.GetOptions() {
+ dirty = true
+ }
+ msgsPath := path.push(internal.FileMessagesTag)
+ newMsgs, changed, err := stripOptionsFromAll(file.GetMessageType(), stripSourceRetentionOptionsFromMessage, msgsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ enumsPath := path.push(internal.FileEnumsTag)
+ newEnums, changed, err := stripOptionsFromAll(file.GetEnumType(), stripSourceRetentionOptionsFromEnum, enumsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ extsPath := path.push(internal.FileExtensionsTag)
+ newExts, changed, err := stripOptionsFromAll(file.GetExtension(), stripSourceRetentionOptionsFromField, extsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ svcsPath := path.push(internal.FileServicesTag)
+ newSvcs, changed, err := stripOptionsFromAll(file.GetService(), stripSourceRetentionOptionsFromService, svcsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+
+ if !dirty {
+ return file, nil
+ }
+
+ newFile, err := shallowCopy(file)
+ if err != nil {
+ return nil, err
+ }
+ newFile.Options = newOpts
+ newFile.MessageType = newMsgs
+ newFile.EnumType = newEnums
+ newFile.Extension = newExts
+ newFile.Service = newSvcs
+ newFile.SourceCodeInfo = stripSourcePathsForSourceRetentionOptions(newFile.SourceCodeInfo, removedPaths)
+ return newFile, nil
+}
+
+type sourcePath protoreflect.SourcePath
+
+func (p sourcePath) push(element int32) sourcePath {
+ if p == nil {
+ return nil
+ }
+ return append(p, element)
+}
+
+type sourcePathTrie struct {
+ removed bool
+ children map[int32]*sourcePathTrie
+}
+
+func (t *sourcePathTrie) addPath(p sourcePath) {
+ if t == nil {
+ return
+ }
+ if len(p) == 0 {
+ t.removed = true
+ return
+ }
+ child := t.children[p[0]]
+ if child == nil {
+ if t.children == nil {
+ t.children = map[int32]*sourcePathTrie{}
+ }
+ child = &sourcePathTrie{}
+ t.children[p[0]] = child
+ }
+ child.addPath(p[1:])
+}
+
+func (t *sourcePathTrie) isRemoved(p []int32) bool {
+ if t == nil {
+ return false
+ }
+ if t.removed {
+ return true
+ }
+ if len(p) == 0 {
+ return false
+ }
+ child := t.children[p[0]]
+ if child == nil {
+ return false
+ }
+ return child.isRemoved(p[1:])
+}
+
+func stripSourceRetentionOptions[M proto.Message](
+ options M,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (M, error) {
+ optionsRef := options.ProtoReflect()
+ // See if there are any options to strip.
+ var hasFieldToStrip bool
+ var numFieldsToKeep int
+ var err error
+ optionsRef.Range(func(field protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
+ fieldOpts, ok := field.Options().(*descriptorpb.FieldOptions)
+ if !ok {
+ err = fmt.Errorf("field options is unexpected type: got %T, want %T", field.Options(), fieldOpts)
+ return false
+ }
+ if fieldOpts.GetRetention() == descriptorpb.FieldOptions_RETENTION_SOURCE {
+ hasFieldToStrip = true
+ } else {
+ numFieldsToKeep++
+ }
+ return true
+ })
+ var zero M
+ if err != nil {
+ return zero, err
+ }
+ if !hasFieldToStrip {
+ return options, nil
+ }
+
+ if numFieldsToKeep == 0 {
+ // Stripping the message would remove *all* options. In that case,
+ // we'll clear out the options by returning the zero value (i.e. nil).
+ removedPaths.addPath(path) // clear out all source locations, too
+ return zero, nil
+ }
+
+ // There is at least one option to remove. So we need to make a copy that does not have those options.
+ newOptions := optionsRef.New()
+ ret, ok := newOptions.Interface().(M)
+ if !ok {
+ return zero, fmt.Errorf("creating new message of same type resulted in unexpected type; got %T, want %T", newOptions.Interface(), zero)
+ }
+ optionsRef.Range(func(field protoreflect.FieldDescriptor, val protoreflect.Value) bool {
+ fieldOpts, ok := field.Options().(*descriptorpb.FieldOptions)
+ if !ok {
+ err = fmt.Errorf("field options is unexpected type: got %T, want %T", field.Options(), fieldOpts)
+ return false
+ }
+ if fieldOpts.GetRetention() != descriptorpb.FieldOptions_RETENTION_SOURCE {
+ newOptions.Set(field, val)
+ } else {
+ removedPaths.addPath(path.push(int32(field.Number())))
+ }
+ return true
+ })
+ if err != nil {
+ return zero, err
+ }
+ return ret, nil
+}
+
+func stripSourceRetentionOptionsFromMessage(
+ msg *descriptorpb.DescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.DescriptorProto, error) {
+ var dirty bool
+ optionsPath := path.push(internal.MessageOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(msg.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts != msg.Options {
+ dirty = true
+ }
+ fieldsPath := path.push(internal.MessageFieldsTag)
+ newFields, changed, err := stripOptionsFromAll(msg.Field, stripSourceRetentionOptionsFromField, fieldsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ oneofsPath := path.push(internal.MessageOneofsTag)
+ newOneofs, changed, err := stripOptionsFromAll(msg.OneofDecl, stripSourceRetentionOptionsFromOneof, oneofsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ extRangesPath := path.push(internal.MessageExtensionRangesTag)
+ newExtRanges, changed, err := stripOptionsFromAll(msg.ExtensionRange, stripSourceRetentionOptionsFromExtensionRange, extRangesPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ msgsPath := path.push(internal.MessageNestedMessagesTag)
+ newMsgs, changed, err := stripOptionsFromAll(msg.NestedType, stripSourceRetentionOptionsFromMessage, msgsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ enumsPath := path.push(internal.MessageEnumsTag)
+ newEnums, changed, err := stripOptionsFromAll(msg.EnumType, stripSourceRetentionOptionsFromEnum, enumsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+ extsPath := path.push(internal.MessageExtensionsTag)
+ newExts, changed, err := stripOptionsFromAll(msg.Extension, stripSourceRetentionOptionsFromField, extsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+
+ if !dirty {
+ return msg, nil
+ }
+
+ newMsg, err := shallowCopy(msg)
+ if err != nil {
+ return nil, err
+ }
+ newMsg.Options = newOpts
+ newMsg.Field = newFields
+ newMsg.OneofDecl = newOneofs
+ newMsg.ExtensionRange = newExtRanges
+ newMsg.NestedType = newMsgs
+ newMsg.EnumType = newEnums
+ newMsg.Extension = newExts
+ return newMsg, nil
+}
+
+func stripSourceRetentionOptionsFromField(
+ field *descriptorpb.FieldDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.FieldDescriptorProto, error) {
+ optionsPath := path.push(internal.FieldOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(field.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts == field.Options {
+ return field, nil
+ }
+ newField, err := shallowCopy(field)
+ if err != nil {
+ return nil, err
+ }
+ newField.Options = newOpts
+ return newField, nil
+}
+
+func stripSourceRetentionOptionsFromOneof(
+ oneof *descriptorpb.OneofDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.OneofDescriptorProto, error) {
+ optionsPath := path.push(internal.OneofOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(oneof.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts == oneof.Options {
+ return oneof, nil
+ }
+ newOneof, err := shallowCopy(oneof)
+ if err != nil {
+ return nil, err
+ }
+ newOneof.Options = newOpts
+ return newOneof, nil
+}
+
+func stripSourceRetentionOptionsFromExtensionRange(
+ extRange *descriptorpb.DescriptorProto_ExtensionRange,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.DescriptorProto_ExtensionRange, error) {
+ optionsPath := path.push(internal.ExtensionRangeOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(extRange.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts == extRange.Options {
+ return extRange, nil
+ }
+ newExtRange, err := shallowCopy(extRange)
+ if err != nil {
+ return nil, err
+ }
+ newExtRange.Options = newOpts
+ return newExtRange, nil
+}
+
+func stripSourceRetentionOptionsFromEnum(
+ enum *descriptorpb.EnumDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.EnumDescriptorProto, error) {
+ var dirty bool
+ optionsPath := path.push(internal.EnumOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(enum.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts != enum.Options {
+ dirty = true
+ }
+ valsPath := path.push(internal.EnumValuesTag)
+ newVals, changed, err := stripOptionsFromAll(enum.Value, stripSourceRetentionOptionsFromEnumValue, valsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+
+ if !dirty {
+ return enum, nil
+ }
+
+ newEnum, err := shallowCopy(enum)
+ if err != nil {
+ return nil, err
+ }
+ newEnum.Options = newOpts
+ newEnum.Value = newVals
+ return newEnum, nil
+}
+
+func stripSourceRetentionOptionsFromEnumValue(
+ enumVal *descriptorpb.EnumValueDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.EnumValueDescriptorProto, error) {
+ optionsPath := path.push(internal.EnumValOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(enumVal.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts == enumVal.Options {
+ return enumVal, nil
+ }
+ newEnumVal, err := shallowCopy(enumVal)
+ if err != nil {
+ return nil, err
+ }
+ newEnumVal.Options = newOpts
+ return newEnumVal, nil
+}
+
+func stripSourceRetentionOptionsFromService(
+ svc *descriptorpb.ServiceDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.ServiceDescriptorProto, error) {
+ var dirty bool
+ optionsPath := path.push(internal.ServiceOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(svc.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts != svc.Options {
+ dirty = true
+ }
+ methodsPath := path.push(internal.ServiceMethodsTag)
+ newMethods, changed, err := stripOptionsFromAll(svc.Method, stripSourceRetentionOptionsFromMethod, methodsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if changed {
+ dirty = true
+ }
+
+ if !dirty {
+ return svc, nil
+ }
+
+ newSvc, err := shallowCopy(svc)
+ if err != nil {
+ return nil, err
+ }
+ newSvc.Options = newOpts
+ newSvc.Method = newMethods
+ return newSvc, nil
+}
+
+func stripSourceRetentionOptionsFromMethod(
+ method *descriptorpb.MethodDescriptorProto,
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) (*descriptorpb.MethodDescriptorProto, error) {
+ optionsPath := path.push(internal.MethodOptionsTag)
+ newOpts, err := stripSourceRetentionOptions(method.Options, optionsPath, removedPaths)
+ if err != nil {
+ return nil, err
+ }
+ if newOpts == method.Options {
+ return method, nil
+ }
+ newMethod, err := shallowCopy(method)
+ if err != nil {
+ return nil, err
+ }
+ newMethod.Options = newOpts
+ return newMethod, nil
+}
+
+func stripSourcePathsForSourceRetentionOptions(
+ sourceInfo *descriptorpb.SourceCodeInfo,
+ removedPaths *sourcePathTrie,
+) *descriptorpb.SourceCodeInfo {
+ if sourceInfo == nil || len(sourceInfo.Location) == 0 || removedPaths == nil {
+ // nothing to do
+ return sourceInfo
+ }
+ newLocations := make([]*descriptorpb.SourceCodeInfo_Location, len(sourceInfo.Location))
+ var i int
+ for _, loc := range sourceInfo.Location {
+ if removedPaths.isRemoved(loc.Path) {
+ continue
+ }
+ newLocations[i] = loc
+ i++
+ }
+ newLocations = newLocations[:i]
+ return &descriptorpb.SourceCodeInfo{Location: newLocations}
+}
+
+func shallowCopy[M proto.Message](msg M) (M, error) {
+ msgRef := msg.ProtoReflect()
+ other := msgRef.New()
+ ret, ok := other.Interface().(M)
+ if !ok {
+ return ret, fmt.Errorf("creating new message of same type resulted in unexpected type; got %T, want %T", other.Interface(), ret)
+ }
+ msgRef.Range(func(field protoreflect.FieldDescriptor, val protoreflect.Value) bool {
+ other.Set(field, val)
+ return true
+ })
+ return ret, nil
+}
+
+// stripOptionsFromAll applies the given function to each element in the given
+// slice in order to remove source-retention options from it. It returns the new
+// slice and a bool indicating whether anything was actually changed. If the
+// second value is false, then the returned slice is the same slice as the input
+// slice. Usually, T is a pointer type, in which case the given updateFunc should
+// NOT mutate the input value. Instead, it should return the input value if only
+// if there is no update needed. If a mutation is needed, it should return a new
+// value.
+func stripOptionsFromAll[T comparable](
+ slice []T,
+ updateFunc func(T, sourcePath, *sourcePathTrie) (T, error),
+ path sourcePath,
+ removedPaths *sourcePathTrie,
+) ([]T, bool, error) {
+ var updated []T // initialized lazily, only when/if a copy is needed
+ for i, item := range slice {
+ newItem, err := updateFunc(item, path.push(int32(i)), removedPaths)
+ if err != nil {
+ return nil, false, err
+ }
+ if updated != nil {
+ updated[i] = newItem
+ } else if newItem != item {
+ updated = make([]T, len(slice))
+ copy(updated[:i], slice)
+ updated[i] = newItem
+ }
+ }
+ if updated != nil {
+ return updated, true, nil
+ }
+ return slice, false, nil
+}