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/resolver.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/resolver.go')
| -rw-r--r-- | vendor/github.com/bufbuild/protocompile/resolver.go | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/vendor/github.com/bufbuild/protocompile/resolver.go b/vendor/github.com/bufbuild/protocompile/resolver.go new file mode 100644 index 0000000..400d554 --- /dev/null +++ b/vendor/github.com/bufbuild/protocompile/resolver.go @@ -0,0 +1,215 @@ +// 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 protocompile + +import ( + "errors" + "io" + "io/fs" + "os" + "path/filepath" + "strings" + + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/descriptorpb" + + "github.com/bufbuild/protocompile/ast" + "github.com/bufbuild/protocompile/parser" +) + +// Resolver is used by the compiler to resolve a proto source file name +// into some unit that is usable by the compiler. The result could be source +// for a proto file or it could be an already-parsed AST or descriptor. +// +// Resolver implementations must be thread-safe as a single compilation +// operation could invoke FindFileByPath from multiple goroutines. +type Resolver interface { + // FindFileByPath searches for information for the given file path. If no + // result is available, it should return a non-nil error, such as + // protoregistry.NotFound. + FindFileByPath(path string) (SearchResult, error) +} + +// SearchResult represents information about a proto source file. Only one of +// the various fields must be set, based on what is available for a file. If +// multiple fields are set, the compiler prefers them in opposite order listed: +// so it uses a descriptor if present and only falls back to source if nothing +// else is available. +type SearchResult struct { + // Represents source code for the file. This should be nil if source code + // is not available. If no field below is set, then the compiler will parse + // the source code into an AST. + Source io.Reader + // Represents the abstract syntax tree for the file. If no field below is + // set, then the compiler will convert the AST into a descriptor proto. + AST *ast.FileNode + // A descriptor proto that represents the file. If the field below is not + // set, then the compiler will link this proto with its dependencies to + // produce a linked descriptor. + Proto *descriptorpb.FileDescriptorProto + // A parse result for the file. This packages both an AST and a descriptor + // proto in one. When a parser result is available, it is more efficient + // than using an AST search result, since the descriptor proto need not be + // re-created. And it provides better error messages than a descriptor proto + // search result, since the AST has greater fidelity with regard to source + // positions (even if the descriptor proto includes source code info). + ParseResult parser.Result + // A fully linked descriptor that represents the file. If this field is set, + // then the compiler has little or no additional work to do for this file as + // it is already compiled. If this value implements linker.File, there is no + // additional work. Otherwise, the additional work is to compute an index of + // symbols in the file, for efficient lookup. + Desc protoreflect.FileDescriptor +} + +// ResolverFunc is a simple function type that implements Resolver. +type ResolverFunc func(string) (SearchResult, error) + +var _ Resolver = ResolverFunc(nil) + +func (f ResolverFunc) FindFileByPath(path string) (SearchResult, error) { + return f(path) +} + +// CompositeResolver is a slice of resolvers, which are consulted in order +// until one can supply a result. If none of the constituent resolvers can +// supply a result, the error returned by the first resolver is returned. If +// the slice of resolvers is empty, all operations return +// protoregistry.NotFound. +type CompositeResolver []Resolver + +var _ Resolver = CompositeResolver(nil) + +func (f CompositeResolver) FindFileByPath(path string) (SearchResult, error) { + if len(f) == 0 { + return SearchResult{}, protoregistry.NotFound + } + var firstErr error + for _, res := range f { + r, err := res.FindFileByPath(path) + if err == nil { + return r, nil + } + if firstErr == nil { + firstErr = err + } + } + return SearchResult{}, firstErr +} + +// SourceResolver can resolve file names by returning source code. It uses +// an optional list of import paths to search. By default, it searches the +// file system. +type SourceResolver struct { + // Optional list of import paths. If present and not empty, then all + // file paths to find are assumed to be relative to one of these paths. + // If nil or empty, all file paths to find are assumed to be relative to + // the current working directory. + ImportPaths []string + // Optional function for returning a file's contents. If nil, then + // os.Open is used to open files on the file system. + // + // This function must be thread-safe as a single compilation operation + // could result in concurrent invocations of this function from + // multiple goroutines. + Accessor func(path string) (io.ReadCloser, error) +} + +var _ Resolver = (*SourceResolver)(nil) + +func (r *SourceResolver) FindFileByPath(path string) (SearchResult, error) { + if len(r.ImportPaths) == 0 { + reader, err := r.accessFile(path) + if err != nil { + return SearchResult{}, err + } + return SearchResult{Source: reader}, nil + } + + var e error + for _, importPath := range r.ImportPaths { + reader, err := r.accessFile(filepath.Join(importPath, path)) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + e = err + continue + } + return SearchResult{}, err + } + return SearchResult{Source: reader}, nil + } + return SearchResult{}, e +} + +func (r *SourceResolver) accessFile(path string) (io.ReadCloser, error) { + if r.Accessor != nil { + return r.Accessor(path) + } + return os.Open(path) +} + +// SourceAccessorFromMap returns a function that can be used as the Accessor +// field of a SourceResolver that uses the given map to load source. The map +// keys are file names and the values are the corresponding file contents. +// +// The given map is used directly and not copied. Since accessor functions +// must be thread-safe, this means that the provided map must not be mutated +// once this accessor is provided to a compile operation. +func SourceAccessorFromMap(srcs map[string]string) func(string) (io.ReadCloser, error) { + return func(path string) (io.ReadCloser, error) { + src, ok := srcs[path] + if !ok { + return nil, os.ErrNotExist + } + return io.NopCloser(strings.NewReader(src)), nil + } +} + +// WithStandardImports returns a new resolver that knows about the same standard +// imports that are included with protoc. +// +// Note that this uses the descriptors embedded in generated code in the packages +// of the Protobuf Go module, except for "google/protobuf/cpp_features.proto" and +// "google/protobuf/java_features.proto". For those two files, compiled descriptors +// are embedded in this module because there is no package in the Protobuf Go module +// that contains generated code for those files. This resolver also provides results +// for the "google/protobuf/go_features.proto", which is technically not a standard +// file (it is not included with protoc) but is included in generated code in the +// Protobuf Go module. +// +// As of v0.14.0 of this module (and v1.34.2 of the Protobuf Go module and v27.0 of +// Protobuf), the contents of the standard import "google/protobuf/descriptor.proto" +// contain extension declarations which are *absent* from the descriptors that this +// resolver returns. That is because extension declarations are only retained in +// source, not at runtime, which means they are not available in the embedded +// descriptors in generated code. +// +// To use versions of the standard imports that *do* include these extension +// declarations, see wellknownimports.WithStandardImports instead. As of this +// writing, the declarations are only needed to prevent source files from +// illegally re-defining the custom features for C++, Java, and Go. +func WithStandardImports(r Resolver) Resolver { + return ResolverFunc(func(name string) (SearchResult, error) { + res, err := r.FindFileByPath(name) + if err != nil { + // error from given resolver? see if it's a known standard file + if d, ok := standardImports[name]; ok { + return SearchResult{Desc: d}, nil + } + } + return res, err + }) +} |
