diff --git a/cmd/buf-plugin-method-options/main.go b/cmd/buf-plugin-method-options/main.go index 767c8f2..e87918e 100644 --- a/cmd/buf-plugin-method-options/main.go +++ b/cmd/buf-plugin-method-options/main.go @@ -60,11 +60,18 @@ var ( LicenseURL: "", }, } + permissionsOption = commonv1.E_Permissions + restHTTPOption = googleann.E_Http + requiresAuthenticationOption = commonv1.E_RequiresAuthentication + extensionRegistry = map[string]*protoimpl.ExtensionInfo{ - "qdrant.cloud.common.v1.permissions": commonv1.E_Permissions, - "google.api.http": googleann.E_Http, + string(permissionsOption.TypeDescriptor().Descriptor().FullName()): permissionsOption, + string(restHTTPOption.TypeDescriptor().Descriptor().FullName()): restHTTPOption, + } + requiredMethodOptionExtensions = []string{ + string(permissionsOption.TypeDescriptor().Descriptor().FullName()), + string(restHTTPOption.TypeDescriptor().Descriptor().FullName()), } - requiredMethodOptionExtensions = []string{"qdrant.cloud.common.v1.permissions", "google.api.http"} ) func main() { @@ -92,6 +99,16 @@ func checkMethodOptions(ctx context.Context, responseWriter check.ResponseWriter return nil } if !proto.HasExtension(options, extension) { + // special case for "qdrant.cloud.common.v1.permissions": in case + // there is "qdrant.cloud.common.v1.requires_authentication" set to + // false, setting permissions isn't needed. + if extensionKey == "qdrant.cloud.common.v1.permissions" && proto.HasExtension(options, requiresAuthenticationOption) { + val := proto.GetExtension(options, requiresAuthenticationOption).(bool) + if !val { + // requires_authentication is false, we skip it. + break + } + } responseWriter.AddAnnotation( check.WithMessagef("Method %q does not define the %q option", methodDescriptor.FullName(), extension.TypeDescriptor().FullName()), check.WithDescriptor(methodDescriptor), diff --git a/cmd/buf-plugin-method-options/main_test.go b/cmd/buf-plugin-method-options/main_test.go index c4c900d..c0b45e8 100644 --- a/cmd/buf-plugin-method-options/main_test.go +++ b/cmd/buf-plugin-method-options/main_test.go @@ -59,6 +59,28 @@ func TestSimpleFailure(t *testing.T) { EndColumn: 5, }, }, + { + RuleID: methodOptionsRuleID, + Message: "Method \"simple.GreeterService.ClosedGoodbye\" does not define the \"google.api.http\" option", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: "simple.proto", + StartLine: 14, + StartColumn: 4, + EndLine: 18, + EndColumn: 5, + }, + }, + { + RuleID: methodOptionsRuleID, + Message: "Method \"simple.GreeterService.ClosedGoodbye\" does not define the \"qdrant.cloud.common.v1.permissions\" option", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: "simple.proto", + StartLine: 14, + StartColumn: 4, + EndLine: 18, + EndColumn: 5, + }, + }, }, }.Run(t) } @@ -81,6 +103,10 @@ func TestSimpleFailureWithOption(t *testing.T) { RuleID: methodOptionsRuleID, Message: "extension key \"unknown.extension\" does not exist", }, + { + 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", @@ -92,6 +118,17 @@ func TestSimpleFailureWithOption(t *testing.T) { EndColumn: 5, }, }, + { + RuleID: methodOptionsRuleID, + Message: "Method \"simple.GreeterService.ClosedGoodbye\" does not define the \"qdrant.cloud.common.v1.permissions\" option", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: "simple.proto", + StartLine: 14, + StartColumn: 4, + EndLine: 18, + EndColumn: 5, + }, + }, }, }.Run(t) @@ -115,6 +152,10 @@ func TestSimpleFailureWithOptionWrongKey(t *testing.T) { RuleID: methodOptionsRuleID, Message: "extension key \"unknown.extension\" does not exist", }, + { + RuleID: methodOptionsRuleID, + Message: "extension key \"unknown.extension\" does not exist", + }, }, }.Run(t) diff --git a/cmd/buf-plugin-method-options/testdata/common.proto b/cmd/buf-plugin-method-options/testdata/common.proto index ea10e42..995d8c2 100644 --- a/cmd/buf-plugin-method-options/testdata/common.proto +++ b/cmd/buf-plugin-method-options/testdata/common.proto @@ -11,3 +11,10 @@ extend google.protobuf.MethodOptions { // A list of permissions which ALL need to be met by the current user. repeated string permissions = 50001; } + +// The extension for allowing a method to be be used without authentication. +// If the extension is missing the system requires authentication and return a 'permission denied' error if missing. +extend google.protobuf.MethodOptions { + // Set to allow a method to be used without authentication. + bool requires_authentication = 50003; +} diff --git a/cmd/buf-plugin-method-options/testdata/simple_failure/simple.proto b/cmd/buf-plugin-method-options/testdata/simple_failure/simple.proto index 76239f4..2cee295 100644 --- a/cmd/buf-plugin-method-options/testdata/simple_failure/simple.proto +++ b/cmd/buf-plugin-method-options/testdata/simple_failure/simple.proto @@ -11,4 +11,10 @@ service GreeterService { // missing qdrant.cloud.common.v1.permissions // missing google.api.http } + + rpc ClosedGoodbye(google.protobuf.Empty) returns (google.protobuf.Empty) { + option (qdrant.cloud.common.v1.requires_authentication) = true; + // missing qdrant.cloud.common.v1.permissions + // missing google.api.http + } } diff --git a/cmd/buf-plugin-method-options/testdata/simple_success/simple.proto b/cmd/buf-plugin-method-options/testdata/simple_success/simple.proto index 84d8468..bb65bda 100644 --- a/cmd/buf-plugin-method-options/testdata/simple_success/simple.proto +++ b/cmd/buf-plugin-method-options/testdata/simple_success/simple.proto @@ -13,4 +13,11 @@ service GreeterService { option (qdrant.cloud.common.v1.permissions) = "read:api_keys"; option (google.api.http) = {get: "/api/hello-world"}; } + + rpc OpenGoodbye(google.protobuf.Empty) returns (google.protobuf.Empty) { + // there aren't permissions required because it doesn't require + // authentication. + option (qdrant.cloud.common.v1.requires_authentication) = false; + option (google.api.http) = {get: "/api/hello-world"}; + } }