@@ -18,6 +18,7 @@ package buf.validate;
1818
1919import "google/protobuf/descriptor.proto" ;
2020import "google/protobuf/duration.proto" ;
21+ import "google/protobuf/field_mask.proto" ;
2122import "google/protobuf/timestamp.proto" ;
2223
2324option go_package = "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" ;
@@ -109,6 +110,25 @@ message Rule {
109110// MessageRules represents validation rules that are applied to the entire message.
110111// It includes disabling options and a list of Rule messages representing Common Expression Language (CEL) validation rules.
111112message MessageRules {
113+ // `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation
114+ // rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax.
115+ //
116+ // This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for
117+ // simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will
118+ // be same as the `expression`.
119+ //
120+ // For more information, [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
121+ //
122+ // ```proto
123+ // message MyMessage {
124+ // // The field `foo` must be greater than 42.
125+ // option (buf.validate.message).cel_expression = "this.foo > 42";
126+ // // The field `foo` must be less than 84.
127+ // option (buf.validate.message).cel_expression = "this.foo < 84";
128+ // optional int32 foo = 1;
129+ // }
130+ // ```
131+ repeated string cel_expression = 5 ;
112132 // `cel` is a repeated field of type Rule. Each Rule specifies a validation rule to be applied to this message.
113133 // These rules are written in Common Expression Language (CEL) syntax. For more information,
114134 // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
@@ -201,6 +221,22 @@ message OneofRules {
201221// FieldRules encapsulates the rules for each type of field. Depending on
202222// the field, the correct set should be used to ensure proper validations.
203223message FieldRules {
224+ // `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation
225+ // rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax.
226+ //
227+ // This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for
228+ // simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will
229+ // be same as the `expression`.
230+ //
231+ // For more information, [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
232+ //
233+ // ```proto
234+ // message MyMessage {
235+ // // The field `value` must be greater than 42.
236+ // optional int32 value = 1 [(buf.validate.field).cel_expression = "this > 42"];
237+ // }
238+ // ```
239+ repeated string cel_expression = 29 ;
204240 // `cel` is a repeated field used to represent a textual expression
205241 // in the Common Expression Language (CEL) syntax. For more information,
206242 // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
@@ -313,6 +349,7 @@ message FieldRules {
313349 // Well-Known Field Types
314350 AnyRules any = 20 ;
315351 DurationRules duration = 21 ;
352+ FieldMaskRules field_mask = 28 ;
316353 TimestampRules timestamp = 22 ;
317354 }
318355
@@ -3731,6 +3768,29 @@ message StringRules {
37313768 }
37323769 ];
37333770
3771+ // `ulid` specifies that the field value must be a valid ULID (Universally Unique
3772+ // Lexicographically Sortable Identifier) as defined by the [ULID specification](https://github.com/ulid/spec).
3773+ // If the field value isn't a valid ULID, an error message will be generated.
3774+ //
3775+ // ```proto
3776+ // message MyString {
3777+ // // value must be a valid ULID
3778+ // string value = 1 [(buf.validate.field).string.ulid = true];
3779+ // }
3780+ // ```
3781+ bool ulid = 35 [
3782+ (predefined).cel = {
3783+ id : "string.ulid"
3784+ message : "value must be a valid ULID"
3785+ expression : "!rules.ulid || this == '' || this.matches('^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$')"
3786+ },
3787+ (predefined).cel = {
3788+ id : "string.ulid_empty"
3789+ message : "value is empty, which is not a valid ULID"
3790+ expression : "!rules.ulid || this != ''"
3791+ }
3792+ ];
3793+
37343794 // `well_known_regex` specifies a common well-known pattern
37353795 // defined as a regex. If the field value doesn't match the well-known
37363796 // regex, an error message will be generated.
@@ -3943,7 +4003,7 @@ message BytesRules {
39434003 // the string.
39444004 // If the field value doesn't meet the requirement, an error message is generated.
39454005 //
3946- // ```protobuf
4006+ // ```proto
39474007 // message MyBytes {
39484008 // // value does not contain \x02\x03
39494009 // optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"];
@@ -3958,7 +4018,7 @@ message BytesRules {
39584018 // values. If the field value doesn't match any of the specified values, an
39594019 // error message is generated.
39604020 //
3961- // ```protobuf
4021+ // ```proto
39624022 // message MyBytes {
39634023 // // value must in ["\x01\x02", "\x02\x03", "\x03\x04"]
39644024 // optional bytes value = 1 [(buf.validate.field).bytes.in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
@@ -4052,6 +4112,31 @@ message BytesRules {
40524112 expression : "!rules.ipv6 || this.size() != 0"
40534113 }
40544114 ];
4115+
4116+ // `uuid` ensures that the field `value` encodes the 128-bit UUID data as
4117+ // defined by [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2).
4118+ // The field must contain exactly 16 bytes
4119+ // representing the UUID. If the field value isn't a valid UUID, an error
4120+ // message will be generated.
4121+ //
4122+ // ```proto
4123+ // message MyBytes {
4124+ // // value must be a valid UUID
4125+ // optional bytes value = 1 [(buf.validate.field).bytes.uuid = true];
4126+ // }
4127+ // ```
4128+ bool uuid = 15 [
4129+ (predefined).cel = {
4130+ id : "bytes.uuid"
4131+ message : "value must be a valid UUID"
4132+ expression : "!rules.uuid || this.size() == 0 || this.size() == 16"
4133+ },
4134+ (predefined).cel = {
4135+ id : "bytes.uuid_empty"
4136+ message : "value is empty, which is not a valid UUID"
4137+ expression : "!rules.uuid || this.size() != 0"
4138+ }
4139+ ];
40554140 }
40564141
40574142 // `example` specifies values that the field may have. These values SHOULD
@@ -4605,6 +4690,93 @@ message DurationRules {
46054690 extensions 1000 to max;
46064691}
46074692
4693+ // FieldMaskRules describe rules applied exclusively to the `google.protobuf.FieldMask` well-known type.
4694+ message FieldMaskRules {
4695+ // `const` dictates that the field must match the specified value of the `google.protobuf.FieldMask` type exactly.
4696+ // If the field's value deviates from the specified value, an error message
4697+ // will be generated.
4698+ //
4699+ // ```proto
4700+ // message MyFieldMask {
4701+ // // value must equal ["a"]
4702+ // google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask.const = {
4703+ // paths: ["a"]
4704+ // }];
4705+ // }
4706+ // ```
4707+ optional google.protobuf.FieldMask const = 1 [(predefined).cel = {
4708+ id : "field_mask.const"
4709+ expression : "this.paths != getField(rules, 'const').paths ? 'value must equal paths %s'.format([getField(rules, 'const').paths]) : ''"
4710+ }];
4711+
4712+ // `in` requires the field value to only contain paths matching specified
4713+ // values or their subpaths.
4714+ // If any of the field value's paths doesn't match the rule,
4715+ // an error message is generated.
4716+ // See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask
4717+ //
4718+ // ```proto
4719+ // message MyFieldMask {
4720+ // // The `value` FieldMask must only contain paths listed in `in`.
4721+ // google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = {
4722+ // in: ["a", "b", "c.a"]
4723+ // }];
4724+ // }
4725+ // ```
4726+ repeated string in = 2 [(predefined).cel = {
4727+ id : "field_mask.in"
4728+ expression : "!this.paths.all(p, p in getField(rules, 'in') || getField(rules, 'in').exists(f, p.startsWith(f+'.'))) ? 'value must only contain paths in %s'.format([getField(rules, 'in')]) : ''"
4729+ }];
4730+
4731+ // `not_in` requires the field value to not contain paths matching specified
4732+ // values or their subpaths.
4733+ // If any of the field value's paths matches the rule,
4734+ // an error message is generated.
4735+ // See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask
4736+ //
4737+ // ```proto
4738+ // message MyFieldMask {
4739+ // // The `value` FieldMask shall not contain paths listed in `not_in`.
4740+ // google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = {
4741+ // not_in: ["forbidden", "immutable", "c.a"]
4742+ // }];
4743+ // }
4744+ // ```
4745+ repeated string not_in = 3 [(predefined).cel = {
4746+ id : "field_mask.not_in"
4747+ expression : "!this.paths.all(p, !(p in getField(rules, 'not_in') || getField(rules, 'not_in').exists(f, p.startsWith(f+'.')))) ? 'value must not contain any paths in %s'.format([getField(rules, 'not_in')]) : ''"
4748+ }];
4749+
4750+ // `example` specifies values that the field may have. These values SHOULD
4751+ // conform to other rules. `example` values will not impact validation
4752+ // but may be used as helpful guidance on how to populate the given field.
4753+ //
4754+ // ```proto
4755+ // message MyFieldMask {
4756+ // google.protobuf.FieldMask value = 1 [
4757+ // (buf.validate.field).field_mask.example = { paths: ["a", "b"] },
4758+ // (buf.validate.field).field_mask.example = { paths: ["c.a", "d"] },
4759+ // ];
4760+ // }
4761+ // ```
4762+ repeated google.protobuf.FieldMask example = 4 [(predefined).cel = {
4763+ id : "field_mask.example"
4764+ expression : "true"
4765+ }];
4766+
4767+ // Extension fields in this range that have the (buf.validate.predefined)
4768+ // option set will be treated as predefined field rules that can then be
4769+ // set on the field options of other fields to apply field rules.
4770+ // Extension numbers 1000 to 99999 are reserved for extension numbers that are
4771+ // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
4772+ // above this range are reserved for extension numbers that are not explicitly
4773+ // assigned. For rules defined in publicly-consumed schemas, use of extensions
4774+ // above 99999 is discouraged due to the risk of conflicts.
4775+ //
4776+ // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
4777+ extensions 1000 to max;
4778+ }
4779+
46084780// TimestampRules describe the rules applied exclusively to the `google.protobuf.Timestamp` well-known type.
46094781message TimestampRules {
46104782 // `const` dictates that this field, of the `google.protobuf.Timestamp` type, must exactly match the specified value. If the field value doesn't correspond to the specified timestamp, an error message will be generated.
0 commit comments