diff --git a/private/bufpkg/bufcheck/buflint/buflint_test.go b/private/bufpkg/bufcheck/buflint/buflint_test.go index 4cc0bb55a8..a5f23eecee 100644 --- a/private/bufpkg/bufcheck/buflint/buflint_test.go +++ b/private/bufpkg/bufcheck/buflint/buflint_test.go @@ -633,6 +633,8 @@ func TestRunProtovalidateRules(t *testing.T) { bufanalysistesting.NewFileAnnotation(t, "number.proto", 134, 5, 134, 56, "PROTOVALIDATE"), bufanalysistesting.NewFileAnnotation(t, "number.proto", 139, 5, 139, 50, "PROTOVALIDATE"), bufanalysistesting.NewFileAnnotation(t, "number.proto", 142, 5, 142, 52, "PROTOVALIDATE"), + bufanalysistesting.NewFileAnnotation(t, "oneof.proto", 13, 7, 13, 43, "PROTOVALIDATE"), + bufanalysistesting.NewFileAnnotation(t, "oneof.proto", 19, 7, 19, 43, "PROTOVALIDATE"), bufanalysistesting.NewFileAnnotation(t, "repeated.proto", 25, 5, 25, 48, "PROTOVALIDATE"), bufanalysistesting.NewFileAnnotation(t, "repeated.proto", 27, 5, 27, 48, "PROTOVALIDATE"), bufanalysistesting.NewFileAnnotation(t, "repeated.proto", 45, 5, 45, 48, "PROTOVALIDATE"), diff --git a/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go b/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go index 944be1eec0..5f45d8fda8 100644 --- a/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go +++ b/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go @@ -178,6 +178,16 @@ func checkConstraintsForField( if fieldDescriptor.IsExtension() { checkConstraintsForExtension(adder, fieldConstraints) } + if fieldDescriptor.ContainingOneof() != nil && fieldConstraints.GetRequired() { + adder.addForPathf( + []int32{requiredFieldNumber}, + "Field %q has %s but is in a oneof (%s). Oneof fields must not have %s.", + adder.fieldName(), + adder.getFieldRuleName(requiredFieldNumber), + fieldDescriptor.ContainingOneof().Name(), + adder.getFieldRuleName(requiredFieldNumber), + ) + } checkFieldFlags(adder, fieldConstraints) if err := checkCELForField( adder, diff --git a/private/bufpkg/bufcheck/buflint/testdata/protovalidate_rules/oneof.proto b/private/bufpkg/bufcheck/buflint/testdata/protovalidate_rules/oneof.proto new file mode 100644 index 0000000000..aecac9592e --- /dev/null +++ b/private/bufpkg/bufcheck/buflint/testdata/protovalidate_rules/oneof.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package what; + +import "buf/validate/validate.proto"; +import "google/protobuf/duration.proto"; + +message OneofTest { + oneof foo { + int32 v1 = 1 [ + (buf.validate.field).int32.lt = 3, + // must not have required + (buf.validate.field).required = true + ]; + string v2 = 2; + google.protobuf.Duration v3 = 3 [ + (buf.validate.field).duration.gt = {seconds: 5}, + // must not have required + (buf.validate.field).required = true, + (buf.validate.field).duration.lt = {seconds: 10} + ]; + } + // required is OK for non-oneof fields + string f4 = 4 [(buf.validate.field).required = true]; +}