diff options
| author | mo khan <mo@mokhan.ca> | 2025-05-20 14:28:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-05-23 14:49:19 -0600 |
| commit | 4beee46dc6c7642316e118a4d3aa51e4b407256e (patch) | |
| tree | 039bdf57b99061844aeb0fe55ad0bc1c864166af /vendor/github.com/bufbuild/protocompile/parser/clone.go | |
| parent | 0ba49bfbde242920d8675a193d7af89420456fc0 (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/parser/clone.go')
| -rw-r--r-- | vendor/github.com/bufbuild/protocompile/parser/clone.go | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/vendor/github.com/bufbuild/protocompile/parser/clone.go b/vendor/github.com/bufbuild/protocompile/parser/clone.go new file mode 100644 index 0000000..0432248 --- /dev/null +++ b/vendor/github.com/bufbuild/protocompile/parser/clone.go @@ -0,0 +1,183 @@ +// 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 parser + +import ( + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/descriptorpb" + + "github.com/bufbuild/protocompile/ast" + "github.com/bufbuild/protocompile/reporter" +) + +// Clone returns a copy of the given result. Since descriptor protos may be +// mutated during linking, this can return a defensive copy so that mutations +// don't impact concurrent operations in an unsafe way. This is called if the +// parse result could be re-used across concurrent operations and has unresolved +// references and options which will require mutation by the linker. +// +// If the given value has a method with the following signature, it will be +// called to perform the operation: +// +// Clone() Result +// +// If the given value does not provide a Clone method and is not the implementation +// provided by this package, it is possible for an error to occur in creating the +// copy, which may result in a panic. This can happen if the AST of the given result +// is not actually valid and a file descriptor proto cannot be successfully derived +// from it. +func Clone(r Result) Result { + if cl, ok := r.(interface{ Clone() Result }); ok { + return cl.Clone() + } + if res, ok := r.(*result); ok { + newProto := proto.Clone(res.proto).(*descriptorpb.FileDescriptorProto) //nolint:errcheck + newNodes := make(map[proto.Message]ast.Node, len(res.nodes)) + newResult := &result{ + file: res.file, + proto: newProto, + nodes: newNodes, + } + recreateNodeIndexForFile(res, newResult, res.proto, newProto) + return newResult + } + + // Can't do the deep-copy we know how to do. So we have to take a + // different tactic. + if r.AST() == nil { + // no AST? all we have to do is copy the proto + fileProto := proto.Clone(r.FileDescriptorProto()).(*descriptorpb.FileDescriptorProto) //nolint:errcheck + return ResultWithoutAST(fileProto) + } + // Otherwise, we have an AST, but no way to clone the result's + // internals. So just re-create them from scratch. + res, err := ResultFromAST(r.AST(), false, reporter.NewHandler(nil)) + if err != nil { + panic(err) + } + return res +} + +func recreateNodeIndexForFile(orig, clone *result, origProto, cloneProto *descriptorpb.FileDescriptorProto) { + updateNodeIndexWithOptions[*descriptorpb.FileOptions](orig, clone, origProto, cloneProto) + for i, origMd := range origProto.MessageType { + cloneMd := cloneProto.MessageType[i] + recreateNodeIndexForMessage(orig, clone, origMd, cloneMd) + } + for i, origEd := range origProto.EnumType { + cloneEd := cloneProto.EnumType[i] + recreateNodeIndexForEnum(orig, clone, origEd, cloneEd) + } + for i, origExtd := range origProto.Extension { + cloneExtd := cloneProto.Extension[i] + updateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origExtd, cloneExtd) + } + for i, origSd := range origProto.Service { + cloneSd := cloneProto.Service[i] + updateNodeIndexWithOptions[*descriptorpb.ServiceOptions](orig, clone, origSd, cloneSd) + for j, origMtd := range origSd.Method { + cloneMtd := cloneSd.Method[j] + updateNodeIndexWithOptions[*descriptorpb.MethodOptions](orig, clone, origMtd, cloneMtd) + } + } +} + +func recreateNodeIndexForMessage(orig, clone *result, origProto, cloneProto *descriptorpb.DescriptorProto) { + updateNodeIndexWithOptions[*descriptorpb.MessageOptions](orig, clone, origProto, cloneProto) + for i, origFld := range origProto.Field { + cloneFld := cloneProto.Field[i] + updateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origFld, cloneFld) + } + for i, origOod := range origProto.OneofDecl { + cloneOod := cloneProto.OneofDecl[i] + updateNodeIndexWithOptions[*descriptorpb.OneofOptions](orig, clone, origOod, cloneOod) + } + for i, origExtr := range origProto.ExtensionRange { + cloneExtr := cloneProto.ExtensionRange[i] + updateNodeIndex(orig, clone, asExtsNode(origExtr), asExtsNode(cloneExtr)) + updateNodeIndexWithOptions[*descriptorpb.ExtensionRangeOptions](orig, clone, origExtr, cloneExtr) + } + for i, origRr := range origProto.ReservedRange { + cloneRr := cloneProto.ReservedRange[i] + updateNodeIndex(orig, clone, origRr, cloneRr) + } + for i, origNmd := range origProto.NestedType { + cloneNmd := cloneProto.NestedType[i] + recreateNodeIndexForMessage(orig, clone, origNmd, cloneNmd) + } + for i, origEd := range origProto.EnumType { + cloneEd := cloneProto.EnumType[i] + recreateNodeIndexForEnum(orig, clone, origEd, cloneEd) + } + for i, origExtd := range origProto.Extension { + cloneExtd := cloneProto.Extension[i] + updateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origExtd, cloneExtd) + } +} + +func recreateNodeIndexForEnum(orig, clone *result, origProto, cloneProto *descriptorpb.EnumDescriptorProto) { + updateNodeIndexWithOptions[*descriptorpb.EnumOptions](orig, clone, origProto, cloneProto) + for i, origEvd := range origProto.Value { + cloneEvd := cloneProto.Value[i] + updateNodeIndexWithOptions[*descriptorpb.EnumValueOptions](orig, clone, origEvd, cloneEvd) + } + for i, origRr := range origProto.ReservedRange { + cloneRr := cloneProto.ReservedRange[i] + updateNodeIndex(orig, clone, origRr, cloneRr) + } +} + +func recreateNodeIndexForOptions(orig, clone *result, origProtos, cloneProtos []*descriptorpb.UninterpretedOption) { + for i, origOpt := range origProtos { + cloneOpt := cloneProtos[i] + updateNodeIndex(orig, clone, origOpt, cloneOpt) + for j, origName := range origOpt.Name { + cloneName := cloneOpt.Name[j] + updateNodeIndex(orig, clone, origName, cloneName) + } + } +} + +func updateNodeIndex[M proto.Message](orig, clone *result, origProto, cloneProto M) { + node := orig.nodes[origProto] + if node != nil { + clone.nodes[cloneProto] = node + } +} + +type pointerMessage[T any] interface { + *T + proto.Message +} + +type options[T any] interface { + // need this type instead of just proto.Message so we can check for nil pointer + pointerMessage[T] + GetUninterpretedOption() []*descriptorpb.UninterpretedOption +} + +type withOptions[O options[T], T any] interface { + proto.Message + GetOptions() O +} + +func updateNodeIndexWithOptions[O options[T], M withOptions[O, T], T any](orig, clone *result, origProto, cloneProto M) { + updateNodeIndex(orig, clone, origProto, cloneProto) + origOpts := origProto.GetOptions() + cloneOpts := cloneProto.GetOptions() + if origOpts != nil { + recreateNodeIndexForOptions(orig, clone, origOpts.GetUninterpretedOption(), cloneOpts.GetUninterpretedOption()) + } +} |
