diff --git a/.golangci.yml b/.golangci.yml index 1adcba0882..c5977d6182 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -186,6 +186,14 @@ issues: - linters: - staticcheck text: "GetDeprecatedLegacyJsonFieldConflicts is deprecated" + - linters: + - staticcheck + text: "GetIgnoreEmpty is deprecated" + path: private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go + - linters: + - staticcheck + text: "GetSkipped is deprecated" + path: private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go # We verify manually so that we can emit verbose output while doing so. - linters: - gosec diff --git a/go.mod b/go.mod index 231d68bb3f..aa172f6b16 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,22 @@ module github.com/bufbuild/buf go 1.20 require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1 - connectrpc.com/connect v1.14.0 + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240221180331-f05a6f4403ce.1 + connectrpc.com/connect v1.15.0 connectrpc.com/otelconnect v0.7.0 github.com/bufbuild/protocompile v0.8.0 - github.com/bufbuild/protovalidate-go v0.5.1 + github.com/bufbuild/protovalidate-go v0.5.2 github.com/bufbuild/protoyaml-go v0.1.8 github.com/docker/docker v25.0.3+incompatible - github.com/go-chi/chi/v5 v5.0.11 + github.com/go-chi/chi/v5 v5.0.12 github.com/gofrs/flock v0.8.1 github.com/gofrs/uuid/v5 v5.0.0 - github.com/google/cel-go v0.19.0 + github.com/google/cel-go v0.20.0 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.19.0 github.com/jdx/go-netrc v1.0.0 github.com/jhump/protoreflect v1.15.6 - github.com/klauspost/compress v1.17.6 + github.com/klauspost/compress v1.17.7 github.com/klauspost/pgzip v1.2.6 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/pkg/profile v1.7.0 @@ -27,19 +27,19 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 github.com/tetratelabs/wazero v1.6.0 - go.opentelemetry.io/otel v1.23.1 - go.opentelemetry.io/otel/sdk v1.23.1 - go.opentelemetry.io/otel/trace v1.23.1 + go.opentelemetry.io/otel v1.24.0 + go.opentelemetry.io/otel/sdk v1.24.0 + go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/atomic v1.11.0 go.uber.org/multierr v1.11.0 - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 golang.org/x/crypto v0.19.0 - golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/mod v0.15.0 golang.org/x/net v0.21.0 golang.org/x/sync v0.6.0 golang.org/x/term v0.17.0 - golang.org/x/tools v0.17.0 + golang.org/x/tools v0.18.0 google.golang.org/protobuf v1.32.1-0.20240201194910-82c6b3ad29a1 gopkg.in/yaml.v3 v3.0.1 ) @@ -70,7 +70,7 @@ require ( github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc6 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -78,10 +78,10 @@ require ( github.com/stoewer/go-strcase v1.3.0 // indirect github.com/vbatts/tar-split v0.11.5 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 // indirect - go.opentelemetry.io/otel/metric v1.23.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect ) diff --git a/go.sum b/go.sum index ae01c9cc31..7e4843d279 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1 h1:u0olL4yf2p7Tl5jfsAK5keaFi+JFJuv1CDHrbiXkxkk= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1/go.mod h1:tiTMKD8j6Pd/D2WzREoweufjzaJKHZg35f/VGcZ2v3I= -connectrpc.com/connect v1.14.0 h1:PDS+J7uoz5Oui2VEOMcfz6Qft7opQM9hPiKvtGC01pA= -connectrpc.com/connect v1.14.0/go.mod h1:uoAq5bmhhn43TwhaKdGKN/bZcGtzPW1v+ngDTn5u+8s= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240221180331-f05a6f4403ce.1 h1:AmmAwHbvaeOIxDKG2+aTn5C36HjmFIMkrdTp49rp80Q= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20240221180331-f05a6f4403ce.1/go.mod h1:tiTMKD8j6Pd/D2WzREoweufjzaJKHZg35f/VGcZ2v3I= +connectrpc.com/connect v1.15.0 h1:lFdeCbZrVVDydAqwr4xGV2y+ULn+0Z73s5JBj2LikWo= +connectrpc.com/connect v1.15.0/go.mod h1:bQmjpDY8xItMnttnurVgOkHUBMRT9cpsNi2O4AjKhmA= connectrpc.com/otelconnect v0.7.0 h1:ZH55ZZtcJOTKWWLy3qmL4Pam4RzRWBJFOqTPyAqCXkY= connectrpc.com/otelconnect v0.7.0/go.mod h1:Bt2ivBymHZHqxvo4HkJ0EwHuUzQN6k2l0oH+mp/8nwc= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= @@ -12,8 +12,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/bufbuild/protocompile v0.8.0 h1:9Kp1q6OkS9L4nM3FYbr8vlJnEwtbpDPQlQOVXfR+78s= github.com/bufbuild/protocompile v0.8.0/go.mod h1:+Etjg4guZoAqzVk2czwEQP12yaxLJ8DxuqCJ9qHdH94= -github.com/bufbuild/protovalidate-go v0.5.1 h1:pUUNnrxkUpt2yEX0gMiPTibTTFpGmzQkYxYLbL3lDVg= -github.com/bufbuild/protovalidate-go v0.5.1/go.mod h1:3XAwFeJ2x9sXyPLgkxufH9sts1tQRk8fdt1AW93NiUU= +github.com/bufbuild/protovalidate-go v0.5.2 h1:MPNZd6F2ekGWjWVQDv8lEYOX8ndSOzMnmTaGbDZWIcg= +github.com/bufbuild/protovalidate-go v0.5.2/go.mod h1:DWCNjFl/HwtBiHyN5/3lKA+0MgXOlAoc3jk8Ps3iN+s= github.com/bufbuild/protoyaml-go v0.1.8 h1:X9QDLfl9uEllh4gsXUGqPanZYCOKzd92uniRtW2OnAQ= github.com/bufbuild/protoyaml-go v0.1.8/go.mod h1:R8vE2+l49bSiIExP4VJpxOXleHE+FDzZ6HVxr3cYunw= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -49,8 +49,8 @@ github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= -github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -65,8 +65,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU= -github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/cel-go v0.20.0 h1:h4n6DOCppEMpWERzllyNkntl7JrDyxoE543KWS6BLpc= +github.com/google/cel-go v0.20.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -85,8 +85,8 @@ github.com/jhump/protoreflect v1.15.6 h1:WMYJbw2Wo+KOWwZFvgY0jMoVHM6i4XIvRs2RcBj github.com/jhump/protoreflect v1.15.6/go.mod h1:jCHoyYQIJnaabEYnbGwyo9hUqfyUMTbJw/tAut5t97E= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= @@ -99,8 +99,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU= -github.com/opencontainers/image-spec v1.1.0-rc6/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -138,33 +138,33 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= -go.opentelemetry.io/otel v1.23.1 h1:Za4UzOqJYS+MUczKI320AtqZHZb7EqxO00jAHE0jmQY= -go.opentelemetry.io/otel v1.23.1/go.mod h1:Td0134eafDLcTS4y+zQ26GE8u3dEuRBiBCTUIRHaikA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.23.1 h1:o8iWeVFa1BcLtVEV0LzrCxV2/55tB3xLxADr6Kyoey4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1 h1:cfuy3bXmLJS7M1RZmAL6SuhGtKUp2KEsrm00OlAXkq4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.23.1/go.mod h1:22jr92C6KwlwItJmQzfixzQM3oyyuYLCfHiMY+rpsPU= -go.opentelemetry.io/otel/metric v1.23.1 h1:PQJmqJ9u2QaJLBOELl1cxIdPcpbwzbkjfEyelTl2rlo= -go.opentelemetry.io/otel/metric v1.23.1/go.mod h1:mpG2QPlAfnK8yNhNJAxDZruU9Y1/HubbC+KyH8FaCWI= -go.opentelemetry.io/otel/sdk v1.23.1 h1:O7JmZw0h76if63LQdsBMKQDWNb5oEcOThG9IrxscV+E= -go.opentelemetry.io/otel/sdk v1.23.1/go.mod h1:LzdEVR5am1uKOOwfBWFef2DCi1nu3SA8XQxx2IerWFk= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= -go.opentelemetry.io/otel/trace v1.23.1 h1:4LrmmEd8AU2rFvU1zegmvqW7+kWarxtNOPyeL6HmYY8= -go.opentelemetry.io/otel/trace v1.23.1/go.mod h1:4IpnpJFwr1mo/6HL8XIPJaE9y0+u1KcVmuW7dwFSVrI= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= -golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= @@ -200,17 +200,17 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= -google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c h1:9g7erC9qu44ks7UK4gDNlnk4kOxZG707xKm4jVniy6o= +google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/make/buf/all.mk b/make/buf/all.mk index ab39c55948..4be06597f4 100644 --- a/make/buf/all.mk +++ b/make/buf/all.mk @@ -31,7 +31,7 @@ LICENSE_HEADER_LICENSE_TYPE := apache LICENSE_HEADER_COPYRIGHT_HOLDER := Buf Technologies, Inc. LICENSE_HEADER_YEAR_RANGE := 2020-2024 LICENSE_HEADER_IGNORES := \/testdata enterprise -PROTOVALIDATE_VERSION := v0.5.1 +PROTOVALIDATE_VERSION := v0.6.0 # Comment out to use released buf BUF_GO_INSTALL_PATH := ./cmd/buf diff --git a/make/go/dep_golangci_lint.mk b/make/go/dep_golangci_lint.mk index 6c4cacdd99..4cee6a5752 100644 --- a/make/go/dep_golangci_lint.mk +++ b/make/go/dep_golangci_lint.mk @@ -7,9 +7,9 @@ $(call _assert_var,CACHE_VERSIONS) $(call _assert_var,CACHE_BIN) # Settable -# https://github.com/golangci/golangci-lint/releases 20231025 checked 20231027 +# https://github.com/golangci/golangci-lint/releases 20240208 checked 20240209 # Contrast golangci-lint configuration with the one in https://github.com/connectrpc/connect-go/blob/main/.golangci.yml when upgrading -GOLANGCI_LINT_VERSION ?= v1.55.1 +GOLANGCI_LINT_VERSION ?= v1.56.1 GOLANGCI_LINT := $(CACHE_VERSIONS)/golangci-lint/$(GOLANGCI_LINT_VERSION) $(GOLANGCI_LINT): diff --git a/make/go/dep_jq.mk b/make/go/dep_jq.mk index 258e10af49..fc98144baa 100644 --- a/make/go/dep_jq.mk +++ b/make/go/dep_jq.mk @@ -9,8 +9,8 @@ $(call _assert_var,CACHE_VERSIONS) $(call _assert_var,CACHE_BIN) # Settable -# https://jqlang.github.io/jq/download 20230906 checked 20230907 -JQ_VERSION ?= 1.7 +# https://jqlang.github.io/jq/download 20231213 checked 20240216 +JQ_VERSION ?= 1.7.1 ifeq ($(UNAME_OS),Darwin) JQ_OS := macos diff --git a/make/go/dep_protoc_gen_connect_go.mk b/make/go/dep_protoc_gen_connect_go.mk index 42118850d7..30d641026c 100644 --- a/make/go/dep_protoc_gen_connect_go.mk +++ b/make/go/dep_protoc_gen_connect_go.mk @@ -7,8 +7,8 @@ $(call _assert_var,CACHE_VERSIONS) $(call _assert_var,CACHE_BIN) # Settable -# https://github.com/connectrpc/connect-go 20231208 checked 20231211 -CONNECT_VERSION ?= v1.14.0 +# https://github.com/connectrpc/connect-go 20240216 checked 20240216 +CONNECT_VERSION ?= v1.15.0 GO_GET_PKGS := $(GO_GET_PKGS) \ connectrpc.com/connect@$(CONNECT_VERSION) diff --git a/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go b/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go index 991de9f6b9..3b0518b169 100644 --- a/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go +++ b/private/bufpkg/bufcheck/buflint/internal/buflintvalidate/field.go @@ -62,6 +62,7 @@ const ( skippedFieldNumber = 24 requiredFieldNumber = 25 ignoreEmptyFieldNumber = 26 + ignoreFieldNumber = 27 // https://buf.build/bufbuild/protovalidate/docs/v0.5.1:buf.validate#buf.validate.StringRules minLenFieldNumberInStringRules = 2 maxLenFieldNumberInStringRules = 3 @@ -258,6 +259,16 @@ func checkFieldFlags( adder.getFieldRuleName(), ) } + if fieldConstraints.GetIgnore() == validate.Ignore_IGNORE_ALWAYS && fieldCount > 1 { + adder.addForPathf( + []int32{ignoreFieldNumber}, + "Field %q has %s=%v and therefore other rules in %s are not applied and should be removed.", + adder.fieldName(), + adder.getFieldRuleName(ignoreFieldNumber), + validate.Ignore_IGNORE_ALWAYS, + adder.getFieldRuleName(), + ) + } if fieldConstraints.GetRequired() && fieldConstraints.GetIgnoreEmpty() { adder.addForPathsf( [][]int32{ @@ -270,6 +281,19 @@ func checkFieldFlags( adder.getFieldRuleName(ignoreEmptyFieldNumber), ) } + if fieldConstraints.GetRequired() && fieldConstraints.GetIgnore() == validate.Ignore_IGNORE_IF_UNPOPULATED { + adder.addForPathsf( + [][]int32{ + {requiredFieldNumber}, + {ignoreFieldNumber}, + }, + "Field %q has both %s and %s=%v. A field cannot be empty if it is required.", + adder.fieldName(), + adder.getFieldRuleName(requiredFieldNumber), + adder.getFieldRuleName(ignoreFieldNumber), + validate.Ignore_IGNORE_IF_UNPOPULATED, + ) + } } // Assumes the rule isn't a map rule or repeated rule, but the field could be a @@ -328,6 +352,15 @@ func checkConstraintsForExtension( adder.getFieldRuleName(ignoreEmptyFieldNumber), ) } + if fieldConstraints.GetIgnore() == validate.Ignore_IGNORE_IF_UNPOPULATED { + adder.addForPathf( + []int32{ignoreFieldNumber}, + "Field %q is an extension field and cannot have %s=%v.", + adder.fieldName(), + adder.getFieldRuleName(ignoreFieldNumber), + validate.Ignore_IGNORE_IF_UNPOPULATED, + ) + } } func checkRepeatedRules( diff --git a/private/bufpkg/bufcheck/buflint/testdata/deps/protovalidate/buf/validate/validate.proto b/private/bufpkg/bufcheck/buflint/testdata/deps/protovalidate/buf/validate/validate.proto index 9b4c7b4f2a..09fa744b5e 100644 --- a/private/bufpkg/bufcheck/buflint/testdata/deps/protovalidate/buf/validate/validate.proto +++ b/private/bufpkg/bufcheck/buflint/testdata/deps/protovalidate/buf/validate/validate.proto @@ -91,21 +91,22 @@ message MessageConstraints { } // The `OneofConstraints` message type enables you to manage constraints for -// oneof fields in your protobuf messages. Use the `required` constraint to ensure -// that exactly one of the fields within a oneof is set; validation will fail -// if none of the fields in the oneof are set: +// oneof fields in your protobuf messages. message OneofConstraints { - // `required` is an optional boolean attribute that ensures that - // exactly one of the field options in a oneof is set; validation fails if - // no fields in the oneof are set. + // If `required` is true, exactly one field of the oneof must be present. A + // validation error is returned if no fields in the oneof are present. The + // field itself may still be a default value; further constraints + // should be placed on the fields themselves to ensure they are valid values, + // such as `min_len` or `gt`. // // ```proto // message MyMessage { // oneof value { - // // The field `a` or `b` must be set. + // // Either `a` or `b` must be set. If `a` is set, it must also be + // // non-empty; whereas if `b` is set, it can still be an empty string. // option (buf.validate.oneof).required = true; - // optional string a = 1; - // optional string b = 2; + // string a = 1 [(buf.validate.field).string.min_len = 1]; + // string b = 2; // } // } // ``` @@ -130,42 +131,39 @@ message FieldConstraints { // } // ``` repeated Constraint cel = 23; - // `skipped` is an optional boolean attribute that specifies that the - // validation rules of this field should not be evaluated. If skipped is set to - // true, any validation rules set for the field will be ignored. + // If `required` is true, the field must be populated. A populated field can be + // described as "serialized in the wire format," which includes: // - // ```proto - // message MyMessage { - // // The field `value` must not be set. - // optional MyOtherMessage value = 1 [(buf.validate.field).skipped = true]; - // } - // ``` - bool skipped = 24; - // `required` is an optional boolean attribute that specifies that - // this field must be set. If required is set to true, the field value must - // not be empty; otherwise, an error message will be generated. - // - // Note that `required` validates that `repeated` fields are non-empty, that is - // setting a `repeated` field as `required` is equivalent to `repeated.min_items = 1`. + // - the following "nullable" fields must be explicitly set to be considered populated: + // - singular message fields (whose fields may be unpopulated/default values) + // - member fields of a oneof (may be their default value) + // - proto3 optional fields (may be their default value) + // - proto2 scalar fields (both optional and required) + // - proto3 scalar fields must be non-zero to be considered populated + // - repeated and map fields must be non-empty to be considered populated // // ```proto // message MyMessage { - // // The field `value` must be set. + // // The field `value` must be set to a non-null value. // optional MyOtherMessage value = 1 [(buf.validate.field).required = true]; // } // ``` bool required = 25; - // `ignore_empty` specifies that the validation rules of this field should be - // evaluated only if the field isn't empty. If the field is empty, no validation - // rules are applied. + // Skip validation on the field if its value matches the specified criteria. + // See Ignore enum for details. // // ```proto - // message MyRepeated { - // // The field `value` validation rules should be evaluated only if the field isn't empty. - // repeated string value = 1 [(buf.validate.field).ignore_empty = true]; + // message UpdateRequest { + // // The uri rule only applies if the field is populated and not an empty + // // string. + // optional string url = 1 [ + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE, + // (buf.validate.field).string.uri = true, + // ]; // } // ``` - bool ignore_empty = 26; + Ignore ignore = 27; + oneof type { // Scalar Field Types FloatRules float = 1; @@ -194,6 +192,165 @@ message FieldConstraints { DurationRules duration = 21; TimestampRules timestamp = 22; } + + // DEPRECATED: use ignore=IGNORE_ALWAYS instead. TODO: remove this field pre-v1. + bool skipped = 24 [deprecated = true]; + // DEPRECATED: use ignore=IGNORE_IF_UNPOPULATED instead. TODO: remove this field pre-v1. + bool ignore_empty = 26 [deprecated = true]; +} + +// Specifies how FieldConstraints.ignore behaves. See the documentation for +// FieldConstraints.required for definitions of "populated" and "nullable". +enum Ignore { + // buf:lint:ignore ENUM_NO_ALLOW_ALIAS // allowance for deprecations. TODO: remove pre-v1. + option allow_alias = true; + // Validation is only skipped if it's an unpopulated nullable fields. + // + // ```proto + // syntax="proto3"; + // + // message Request { + // // The uri rule applies to any value, including the empty string. + // string foo = 1 [ + // (buf.validate.field).string.uri = true + // ]; + // + // // The uri rule only applies if the field is set, including if it's + // // set to the empty string. + // optional string bar = 2 [ + // (buf.validate.field).string.uri = true + // ]; + // + // // The min_items rule always applies, even if the list is empty. + // repeated string baz = 3 [ + // (buf.validate.field).repeated.min_items = 3 + // ]; + // + // // The custom CEL rule applies only if the field is set, including if + // // it's the "zero" value of that message. + // SomeMessage quux = 4 [ + // (buf.validate.field).cel = {/* ... */} + // ]; + // } + // ``` + IGNORE_UNSPECIFIED = 0; + + // Validation is skipped if the field is unpopulated. This rule is redundant + // if the field is already nullable. This value is equivalent behavior to the + // deprecated ignore_empty rule. + // + // ```proto + // syntax="proto3 + // + // message Request { + // // The uri rule applies only if the value is not the empty string. + // string foo = 1 [ + // (buf.validate.field).string.uri = true, + // (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED + // ]; + // + // // IGNORE_IF_UNPOPULATED is equivalent to IGNORE_UNSPECIFIED in this + // // case: the uri rule only applies if the field is set, including if + // // it's set to the empty string. + // optional string bar = 2 [ + // (buf.validate.field).string.uri = true, + // (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED + // ]; + // + // // The min_items rule only applies if the list has at least one item. + // repeated string baz = 3 [ + // (buf.validate.field).repeated.min_items = 3, + // (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED + // ]; + // + // // IGNORE_IF_UNPOPULATED is equivalent to IGNORE_UNSPECIFIED in this + // // case: the custom CEL rule applies only if the field is set, including + // // if it's the "zero" value of that message. + // SomeMessage quux = 4 [ + // (buf.validate.field).cel = {/* ... */}, + // (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED + // ]; + // } + // ``` + IGNORE_IF_UNPOPULATED = 1; + + // Validation is skipped if the field is unpopulated or if it is a nullable + // field populated with its default value. This is typically the zero or + // empty value, but proto2 scalars support custom defaults. For messages, the + // default is a non-null message with all its fields unpopulated. + // + // ```proto + // syntax="proto3 + // + // message Request { + // // IGNORE_IF_DEFAULT_VALUE is equivalent to IGNORE_IF_UNPOPULATED in + // // this case; the uri rule applies only if the value is not the empty + // // string. + // string foo = 1 [ + // (buf.validate.field).string.uri = true, + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE + // ]; + // + // // The uri rule only applies if the field is set to a value other than + // // the empty string. + // optional string bar = 2 [ + // (buf.validate.field).string.uri = true, + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE + // ]; + // + // // IGNORE_IF_DEFAULT_VALUE is equivalent to IGNORE_IF_UNPOPULATED in + // // this case; the min_items rule only applies if the list has at least + // // one item. + // repeated string baz = 3 [ + // (buf.validate.field).repeated.min_items = 3, + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE + // ]; + // + // // The custom CEL rule only applies if the field is set to a value other + // // than an empty message (i.e., fields are unpopulated). + // SomeMessage quux = 4 [ + // (buf.validate.field).cel = {/* ... */}, + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE + // ]; + // } + // ``` + // + // This rule is affected by proto2 custom default values: + // + // ```proto + // syntax="proto2"; + // + // message Request { + // // The gt rule only applies if the field is set and it's value is not + // the default (i.e., not -42). The rule even applies if the field is set + // to zero since the default value differs. + // optional int32 value = 1 [ + // default = -42, + // (buf.validate.field).int32.gt = 0, + // (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE + // ]; + // } + IGNORE_IF_DEFAULT_VALUE = 2; + + // The validation rules of this field will be skipped and not evaluated. This + // is useful for situations that necessitate turning off the rules of a field + // containing a message that may not make sense in the current context, or to + // temporarily disable constraints during development. + // + // ```proto + // message MyMessage { + // // The field's rules will always be ignored, including any validation's + // // on value's fields. + // MyOtherMessage value = 1 [ + // (buf.validate.field).ignore = IGNORE_ALWAYS]; + // } + // ``` + IGNORE_ALWAYS = 3; + + // Deprecated: Use IGNORE_IF_UNPOPULATED instead. TODO: Remove this value pre-v1. + IGNORE_EMPTY = 1 [deprecated = true]; + // Deprecated: Use IGNORE_IF_DEFAULT_VALUE. TODO: Remove this value pre-v1. + IGNORE_DEFAULT = 2 [deprecated = true]; } // FloatRules describes the constraints applied to `float` values. These @@ -2684,11 +2841,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.email = true]; // } // ``` - bool email = 12 [(priv.field).cel = { - id: "string.email", - message: "value must be a valid email address", - expression: "this.isEmail()" - }]; + bool email = 12 [ + (priv.field).cel = { + id: "string.email", + message: "value must be a valid email address", + expression: "this == '' || this.isEmail()", + }, + (priv.field).cel = { + id: "string.email_empty", + message: "value is empty, which is not a valid email address", + expression: "this != ''", + } + ]; // `hostname` specifies that the field value must be a valid // hostname as defined by [RFC 1034](https://tools.ietf.org/html/rfc1034#section-3.5). This constraint doesn't support @@ -2701,11 +2865,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.hostname = true]; // } // ``` - bool hostname = 13 [(priv.field).cel = { - id: "string.hostname", - message: "value must be a valid hostname", - expression: "this.isHostname()", - }]; + bool hostname = 13 [ + (priv.field).cel = { + id: "string.hostname", + message: "value must be a valid hostname", + expression: "this == '' || this.isHostname()", + }, + (priv.field).cel = { + id: "string.hostname_empty", + message: "value is empty, which is not a valid hostname", + expression: "this != ''", + } + ]; // `ip` specifies that the field value must be a valid IP // (v4 or v6) address, without surrounding square brackets for IPv6 addresses. @@ -2718,11 +2889,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ip = true]; // } // ``` - bool ip = 14 [(priv.field).cel = { - id: "string.ip", - message: "value must be a valid IP address", - expression: "this.isIp()", - }]; + bool ip = 14 [ + (priv.field).cel = { + id: "string.ip", + message: "value must be a valid IP address", + expression: "this == '' || this.isIp()", + }, + (priv.field).cel = { + id: "string.ip_empty", + message: "value is empty, which is not a valid IP address", + expression: "this != ''", + } + ]; // `ipv4` specifies that the field value must be a valid IPv4 // address. If the field value isn't a valid IPv4 address, an error message @@ -2734,11 +2912,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ipv4 = true]; // } // ``` - bool ipv4 = 15 [(priv.field).cel = { - id: "string.ipv4", - message: "value must be a valid IPv4 address", - expression: "this.isIp(4)" - }]; + bool ipv4 = 15 [ + (priv.field).cel = { + id: "string.ipv4", + message: "value must be a valid IPv4 address", + expression: "this == '' || this.isIp(4)", + }, + (priv.field).cel = { + id: "string.ipv4_empty", + message: "value is empty, which is not a valid IPv4 address", + expression: "this != ''", + } + ]; // `ipv6` specifies that the field value must be a valid // IPv6 address, without surrounding square brackets. If the field value is @@ -2750,11 +2935,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ipv6 = true]; // } // ``` - bool ipv6 = 16 [(priv.field).cel = { - id: "string.ipv6", - message: "value must be a valid IPv6 address", - expression: "this.isIp(6)", - }]; + bool ipv6 = 16 [ + (priv.field).cel = { + id: "string.ipv6", + message: "value must be a valid IPv6 address", + expression: "this == '' || this.isIp(6)", + }, + (priv.field).cel = { + id: "string.ipv6_empty", + message: "value is empty, which is not a valid IPv6 address", + expression: "this != ''", + } + ]; // `uri` specifies that the field value must be a valid, // absolute URI as defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3). If the field value isn't a valid, @@ -2766,11 +2958,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.uri = true]; // } // ``` - bool uri = 17 [(priv.field).cel = { - id: "string.uri", - message: "value must be a valid URI", - expression: "this.isUri()", - }]; + bool uri = 17 [ + (priv.field).cel = { + id: "string.uri", + message: "value must be a valid URI", + expression: "this == '' || this.isUri()", + }, + (priv.field).cel = { + id: "string.uri_empty", + message: "value is empty, which is not a valid URI", + expression: "this != ''", + } + ]; // `uri_ref` specifies that the field value must be a valid URI // as defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3) and may be either relative or absolute. If the @@ -2800,11 +2999,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.address = true]; // } // ``` - bool address = 21 [(priv.field).cel = { - id: "string.address", - message: "value must be a valid hostname, or ip address", - expression: "this.isHostname() || this.isIp()", - }]; + bool address = 21 [ + (priv.field).cel = { + id: "string.address", + message: "value must be a valid hostname, or ip address", + expression: "this == '' || this.isHostname() || this.isIp()", + }, + (priv.field).cel = { + id: "string.address_empty", + message: "value is empty, which is not a valid hostname, or ip address", + expression: "this != ''", + } + ]; // `uuid` specifies that the field value must be a valid UUID as defined by // [RFC 4122](https://tools.ietf.org/html/rfc4122#section-4.1.2). If the @@ -2816,10 +3022,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.uuid = true]; // } // ``` - bool uuid = 22 [(priv.field).cel = { - id: "string.uuid", - expression: "!this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') ? 'value must be a valid UUID' : ''" - }]; + bool uuid = 22 [ + (priv.field).cel = { + id: "string.uuid", + message: "value must be a valid UUID", + expression: "this == '' || this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')", + }, + (priv.field).cel = { + id: "string.uuid_empty", + message: "value is empty, which is not a valid UUID", + expression: "this != ''", + } + ]; // `ip_with_prefixlen` specifies that the field value must be a valid IP (v4 or v6) // address with prefix length. If the field value isn't a valid IP with prefix @@ -2832,11 +3046,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ip_with_prefixlen = true]; // } // ``` - bool ip_with_prefixlen = 26 [(priv.field).cel = { - id: "string.ip_with_prefixlen", - message: "value must be a valid IP prefix", - expression: "this.isIpPrefix()", - }]; + bool ip_with_prefixlen = 26 [ + (priv.field).cel = { + id: "string.ip_with_prefixlen", + message: "value must be a valid IP prefix", + expression: "this == '' || this.isIpPrefix()", + }, + (priv.field).cel = { + id: "string.ip_with_prefixlen_empty", + message: "value is empty, which is not a valid IP prefix", + expression: "this != ''", + } + ]; // `ipv4_with_prefixlen` specifies that the field value must be a valid // IPv4 address with prefix. @@ -2845,15 +3066,22 @@ message StringRules { // // ```proto // message MyString { - // // value must be a valid IPv4 address with prefix lentgh + // // value must be a valid IPv4 address with prefix length // string value = 1 [(buf.validate.field).string.ipv4_with_prefixlen = true]; // } // ``` - bool ipv4_with_prefixlen = 27 [(priv.field).cel = { - id: "string.ipv4_with_prefixlen", - message: "value must be a valid IPv4 address with prefix length", - expression: "this.isIpPrefix(4)" - }]; + bool ipv4_with_prefixlen = 27 [ + (priv.field).cel = { + id: "string.ipv4_with_prefixlen", + message: "value must be a valid IPv4 address with prefix length", + expression: "this == '' || this.isIpPrefix(4)" + }, + (priv.field).cel = { + id: "string.ipv4_with_prefixlen_empty", + message: "value is empty, which is not a valid IPv4 address with prefix length", + expression: "this != ''" + } + ]; // `ipv6_with_prefixlen` specifies that the field value must be a valid // IPv6 address with prefix length. @@ -2866,11 +3094,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ipv6_with_prefixlen = true]; // } // ``` - bool ipv6_with_prefixlen = 28 [(priv.field).cel = { - id: "string.ipv6_with_prefixlen", - message: "value must be a valid IPv6 address with prefix length", - expression: "this.isIpPrefix(6)", - }]; + bool ipv6_with_prefixlen = 28 [ + (priv.field).cel = { + id: "string.ipv6_with_prefixlen", + message: "value must be a valid IPv6 address with prefix length", + expression: "this == '' || this.isIpPrefix(6)", + }, + (priv.field).cel = { + id: "string.ipv6_with_prefixlen_empty", + message: "value is empty, which is not a valid IPv6 address with prefix length", + expression: "this != ''", + } + ]; // `ip_prefix` specifies that the field value must be a valid IP (v4 or v6) prefix. // If the field value isn't a valid IP prefix, an error message will be @@ -2883,11 +3118,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ip_prefix = true]; // } // ``` - bool ip_prefix = 29 [(priv.field).cel = { - id: "string.ip_prefix", - message: "value must be a valid IP prefix", - expression: "this.isIpPrefix(true)", - }]; + bool ip_prefix = 29 [ + (priv.field).cel = { + id: "string.ip_prefix", + message: "value must be a valid IP prefix", + expression: "this == '' || this.isIpPrefix(true)", + }, + (priv.field).cel = { + id: "string.ip_prefix_empty", + message: "value is empty, which is not a valid IP prefix", + expression: "this != ''", + } + ]; // `ipv4_prefix` specifies that the field value must be a valid IPv4 // prefix. If the field value isn't a valid IPv4 prefix, an error message @@ -2900,11 +3142,18 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ipv4_prefix = true]; // } // ``` - bool ipv4_prefix = 30 [(priv.field).cel = { - id: "string.ipv4_prefix", - message: "value must be a valid IPv4 prefix", - expression: "this.isIpPrefix(4, true)" - }]; + bool ipv4_prefix = 30 [ + (priv.field).cel = { + id: "string.ipv4_prefix", + message: "value must be a valid IPv4 prefix", + expression: "this == '' || this.isIpPrefix(4, true)" + }, + (priv.field).cel = { + id: "string.ipv4_prefix_empty", + message: "value is empty, which is not a valid IPv4 prefix", + expression: "this != ''" + } + ]; // `ipv6_prefix` specifies that the field value must be a valid IPv6 prefix. // If the field value is not a valid IPv6 prefix, an error message will be @@ -2917,11 +3166,35 @@ message StringRules { // string value = 1 [(buf.validate.field).string.ipv6_prefix = true]; // } // ``` - bool ipv6_prefix = 31 [(priv.field).cel = { - id: "string.ipv6_prefix", - message: "value must be a valid IPv6 prefix", - expression: "this.isIpPrefix(6, true)", - }]; + bool ipv6_prefix = 31 [ + (priv.field).cel = { + id: "string.ipv6_prefix", + message: "value must be a valid IPv6 prefix", + expression: "this == '' || this.isIpPrefix(6, true)", + }, + (priv.field).cel = { + id: "string.ipv6_prefix_empty", + message: "value is empty, which is not a valid IPv6 prefix", + expression: "this != ''", + } + ]; + + // `host_and_port` specifies the field value must be a valid host and port + // pair. The host must be a valid hostname or IP address while the port + // must be in the range of 0-65535, inclusive. IPv6 addresses must be delimited + // with square brackets (e.g., `[::1]:1234`). + bool host_and_port = 32 [ + (priv.field).cel = { + id: "string.host_and_port", + message: "value must be a valid host (hostname or IP address) and port pair", + expression: "this == '' || this.isHostAndPort(true)", + }, + (priv.field).cel = { + id: "string.host_and_port_empty", + message: "value is empty, which is not a valid host and port pair", + expression: "this != ''", + } + ]; // `well_known_regex` specifies a common well-known pattern // defined as a regex. If the field value doesn't match the well-known @@ -2930,7 +3203,7 @@ message StringRules { // ```proto // message MyString { // // value must be a valid HTTP header value - // string value = 1 [(buf.validate.field).string.well_known_regex = 2]; + // string value = 1 [(buf.validate.field).string.well_known_regex = KNOWN_REGEX_HTTP_HEADER_VALUE]; // } // ``` // @@ -2945,18 +3218,25 @@ message StringRules { // | KNOWN_REGEX_HTTP_HEADER_VALUE | 2 | HTTP header value as defined by [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4) | KnownRegex well_known_regex = 24 [ (priv.field).cel = { - id: "string.well_known_regex.header_name" + id: "string.well_known_regex.header_name", + message: "value must be a valid HTTP header name", expression: - "rules.well_known_regex == 1 && !this.matches(!has(rules.strict) || rules.strict ?" + "rules.well_known_regex != 1 || this == '' || this.matches(!has(rules.strict) || rules.strict ?" "'^:?[0-9a-zA-Z!#$%&\\'*+-.^_|~\\x60]+$' :" - "'^[^\\u0000\\u000A\\u000D]+$') ? 'value must be a valid HTTP header name' : ''", + "'^[^\\u0000\\u000A\\u000D]+$')", + }, + (priv.field).cel = { + id: "string.well_known_regex.header_name_empty", + message: "value is empty, which is not a valid HTTP header name", + expression: "rules.well_known_regex != 1 || this != ''", }, (priv.field).cel = { id: "string.well_known_regex.header_value", + message: "value must be a valid HTTP header value", expression: - "rules.well_known_regex == 2 && !this.matches(!has(rules.strict) || rules.strict ?" + "rules.well_known_regex != 2 || this.matches(!has(rules.strict) || rules.strict ?" "'^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$' :" - "'^[^\\u0000\\u000A\\u000D]*$') ? 'value must be a valid HTTP header value' : ''", + "'^[^\\u0000\\u000A\\u000D]*$')", } ]; } @@ -3153,10 +3433,18 @@ message BytesRules { // optional bytes value = 1 [(buf.validate.field).bytes.ip = true]; // } // ``` - bool ip = 10 [(priv.field).cel = { - id: "bytes.ip", - expression: "this.size() != 4 && this.size() != 16 ? 'value must be a valid IP address' : ''" - }]; + bool ip = 10 [ + (priv.field).cel = { + id: "bytes.ip", + message: "value must be a valid IP address", + expression: "this.size() == 0 || this.size() == 4 || this.size() == 16", + }, + (priv.field).cel = { + id: "bytes.ip_empty", + message: "value is empty, which is not a valid IP address", + expression: "this.size() != 0", + } + ]; // `ipv4` ensures that the field `value` is a valid IPv4 address in byte format. // If the field value doesn't meet this constraint, an error message is generated. @@ -3167,10 +3455,18 @@ message BytesRules { // optional bytes value = 1 [(buf.validate.field).bytes.ipv4 = true]; // } // ``` - bool ipv4 = 11 [(priv.field).cel = { - id: "bytes.ipv4", - expression: "this.size() != 4 ? 'value must be a valid IPv4 address' : ''" - }]; + bool ipv4 = 11 [ + (priv.field).cel = { + id: "bytes.ipv4", + message: "value must be a valid IPv4 address", + expression: "this.size() == 0 || this.size() == 4", + }, + (priv.field).cel = { + id: "bytes.ipv4_empty", + message: "value is empty, which is not a valid IPv4 address", + expression: "this.size() != 0", + } + ]; // `ipv6` ensures that the field `value` is a valid IPv6 address in byte format. // If the field value doesn't meet this constraint, an error message is generated. @@ -3180,10 +3476,18 @@ message BytesRules { // optional bytes value = 1 [(buf.validate.field).bytes.ipv6 = true]; // } // ``` - bool ipv6 = 12 [(priv.field).cel = { - id: "bytes.ipv6", - expression: "this.size() != 16 ? 'value must be a valid IPv6 address' : ''" - }]; + bool ipv6 = 12 [ + (priv.field).cel = { + id: "bytes.ipv6", + message: "value must be a valid IPv6 address", + expression: "this.size() == 0 || this.size() == 16" + }, + (priv.field).cel = { + id: "bytes.ipv6_empty", + message: "value is empty, which is not a valid IPv6 address", + expression: "this.size() != 0", + } + ]; } } @@ -3239,7 +3543,7 @@ message EnumRules { // // message MyMessage { // // The field `value` must be equal to one of the specified values. - // MyEnum value = 1 [(buf.validate.field).enum.in = {1, 2}]; + // MyEnum value = 1 [(buf.validate.field).enum = { in: [1, 2]}]; // } // ``` repeated int32 in = 3 [(priv.field).cel = { @@ -3260,7 +3564,7 @@ message EnumRules { // // message MyMessage { // // The field `value` must not be equal to any of the specified values. - // MyEnum value = 1 [(buf.validate.field).enum.not_in = {1, 2}]; + // MyEnum value = 1 [(buf.validate.field).enum = { not_in: [1, 2]}]; // } // ``` repeated int32 not_in = 4 [(priv.field).cel = {