From 74718aaf705a2a8f933620aeb0c432bdb8a23074 Mon Sep 17 00:00:00 2001 From: Toni Reina Date: Mon, 2 Jun 2025 14:56:44 +0200 Subject: [PATCH 1/2] Update the `method-options` plugin making it configurable With this change it is possible to configure the list of required method options. For our internal api, we can exclude the validation of `google.api.http` because we don't use it. --- cmd/buf-plugin-method-options/main.go | 41 +++++++++++++--- cmd/buf-plugin-method-options/main_test.go | 57 ++++++++++++++++++++++ 2 files changed, 91 insertions(+), 7 deletions(-) diff --git a/cmd/buf-plugin-method-options/main.go b/cmd/buf-plugin-method-options/main.go index a4d73a3..acc3d7e 100644 --- a/cmd/buf-plugin-method-options/main.go +++ b/cmd/buf-plugin-method-options/main.go @@ -1,5 +1,8 @@ // Package main implements a plugin that checks that all rpc methods set the -// required options (permissions, http). +// required options. The list of options is configurable. +// The default value is: +// - "qdrant.cloud.common.v1.permissions" +// - "google.api.http" // // To use this plugin: // @@ -11,6 +14,10 @@ // - QDRANT_CLOUD_METHOD_OPTIONS // plugins: // - plugin: buf-plugin-method-options +// # Uncomment in case you need to configure the list of method options to validate. +// # options: +// # required_method_options: +// # - "qdrant.cloud.common.v1.permissions" package main import ( @@ -19,16 +26,19 @@ import ( "buf.build/go/bufplugin/check" "buf.build/go/bufplugin/check/checkutil" "buf.build/go/bufplugin/info" + "buf.build/go/bufplugin/option" + commonv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/common/v1" googleann "google.golang.org/genproto/googleapis/api/annotations" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - - commonv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/common/v1" ) const ( + // methodOptionsRuleID is the Rule ID of the methodOptions rule. methodOptionsRuleID = "QDRANT_CLOUD_METHOD_OPTIONS" + // methodOptionsOptionKey is the option key to override the default list of required options. + methodOptionsOptionKey = "required_method_options" ) var ( @@ -49,10 +59,11 @@ var ( LicenseURL: "", }, } - requiredMethodOptionExtensions = []*protoimpl.ExtensionInfo{ - commonv1.E_Permissions, - googleann.E_Http, + extensionRegistry = map[string]*protoimpl.ExtensionInfo{ + "qdrant.cloud.common.v1.permissions": commonv1.E_Permissions, + "google.api.http": googleann.E_Http, } + requiredMethodOptionExtensions = []string{"qdrant.cloud.common.v1.permissions", "google.api.http"} ) func main() { @@ -60,9 +71,25 @@ func main() { } func checkMethodOptions(ctx context.Context, responseWriter check.ResponseWriter, request check.Request, methodDescriptor protoreflect.MethodDescriptor) error { + requiredOptions := requiredMethodOptionExtensions + optionValue, err := option.GetStringSliceValue(request.Options(), methodOptionsOptionKey) + if err != nil { + return err + } + if len(optionValue) > 0 { + requiredOptions = optionValue + } + options := methodDescriptor.Options() - for _, extension := range requiredMethodOptionExtensions { + for _, extensionKey := range requiredOptions { + extension, found := extensionRegistry[extensionKey] + if !found { + responseWriter.AddAnnotation( + check.WithMessagef("extension key %q does not exist", extensionKey), + ) + return nil + } if !proto.HasExtension(options, extension) { responseWriter.AddAnnotation( check.WithMessagef("Method %q does not define the %q option", methodDescriptor.FullName(), extension.TypeDescriptor().FullName()), diff --git a/cmd/buf-plugin-method-options/main_test.go b/cmd/buf-plugin-method-options/main_test.go index f537f23..c4c900d 100644 --- a/cmd/buf-plugin-method-options/main_test.go +++ b/cmd/buf-plugin-method-options/main_test.go @@ -62,3 +62,60 @@ func TestSimpleFailure(t *testing.T) { }, }.Run(t) } + +func TestSimpleFailureWithOption(t *testing.T) { + t.Parallel() + checktest.CheckTest{ + Request: &checktest.RequestSpec{ + Files: &checktest.ProtoFileSpec{ + DirPaths: []string{"testdata/simple_failure"}, + FilePaths: []string{"simple.proto"}, + }, + Options: map[string]any{ + methodOptionsOptionKey: []string{"qdrant.cloud.common.v1.permissions", "unknown.extension"}, + }, + }, + Spec: spec, + ExpectedAnnotations: []checktest.ExpectedAnnotation{ + { + RuleID: methodOptionsRuleID, + Message: "extension key \"unknown.extension\" does not exist", + }, + { + RuleID: methodOptionsRuleID, + Message: "Method \"simple.GreeterService.HelloWorld\" does not define the \"qdrant.cloud.common.v1.permissions\" option", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: "simple.proto", + StartLine: 9, + StartColumn: 4, + EndLine: 12, + EndColumn: 5, + }, + }, + }, + }.Run(t) + +} + +func TestSimpleFailureWithOptionWrongKey(t *testing.T) { + t.Parallel() + checktest.CheckTest{ + Request: &checktest.RequestSpec{ + Files: &checktest.ProtoFileSpec{ + DirPaths: []string{"testdata/simple_failure"}, + FilePaths: []string{"simple.proto"}, + }, + Options: map[string]any{ + methodOptionsOptionKey: []string{"unknown.extension"}, + }, + }, + Spec: spec, + ExpectedAnnotations: []checktest.ExpectedAnnotation{ + { + RuleID: methodOptionsRuleID, + Message: "extension key \"unknown.extension\" does not exist", + }, + }, + }.Run(t) + +} From ff2b8bd1393b13caa1e2fbdf52b2edf4d4c99a92 Mon Sep 17 00:00:00 2001 From: Toni Reina Date: Tue, 10 Jun 2025 17:24:38 +0200 Subject: [PATCH 2/2] Fix linting issue --- cmd/buf-plugin-method-options/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/buf-plugin-method-options/main.go b/cmd/buf-plugin-method-options/main.go index acc3d7e..767c8f2 100644 --- a/cmd/buf-plugin-method-options/main.go +++ b/cmd/buf-plugin-method-options/main.go @@ -27,11 +27,12 @@ import ( "buf.build/go/bufplugin/check/checkutil" "buf.build/go/bufplugin/info" "buf.build/go/bufplugin/option" - commonv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/common/v1" googleann "google.golang.org/genproto/googleapis/api/annotations" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + + commonv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/common/v1" ) const (