Skip to content

Automate CAS Diff comments#1178

Open
unmultimedio wants to merge 41 commits intomainfrom
jfigueroa/automate-cas-comment
Open

Automate CAS Diff comments#1178
unmultimedio wants to merge 41 commits intomainfrom
jfigueroa/automate-cas-comment

Conversation

@unmultimedio
Copy link
Member

@unmultimedio unmultimedio commented Mar 17, 2026

Set up a GH workflow to automate casdiff manual comments for git reference transitions like this one.

  • Recognize if a PR targetting main changes any module's state file.
  • Calculate all digest transitions in those state files diffs.
  • For each digest transition, run the casdiff command.
  • Post a comment in the "digest": PR line with the result of the casdiff command.
  • If there are new commits in the PR, update the existing comments instead of posting new ones.

Test comment: #1178 (comment)

@github-actions
Copy link

github-actions bot commented Mar 17, 2026

The latest Buf updates on your PR. Results from workflow Buf CI / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMar 18, 2026, 10:55 PM

@unmultimedio unmultimedio changed the base branch from main to jfigueroa/mock-old-main March 17, 2026 20:19
@unmultimedio
Copy link
Member Author

cc @pkwarren @jhump this PR does not contain any actual changes to wellknowntypes repo, it's just a test I'm doing to automate cas diff comments. Pls disregard.

@unmultimedio unmultimedio force-pushed the jfigueroa/mock-old-main branch from 6a16eae to 832b817 Compare March 17, 2026 21:12
@unmultimedio unmultimedio requested a review from a team March 18, 2026 19:02
@unmultimedio unmultimedio marked this pull request as ready for review March 18, 2026 19:03
@unmultimedio unmultimedio requested a review from jhump as a code owner March 18, 2026 19:03
@unmultimedio unmultimedio removed the request for review from jhump March 18, 2026 19:09
// Run casdiff in the module directory. casdiff reads state.json from "." so it must run from the
// module directory. We use an absolute path to the package to avoid path resolution issues when
// cmd.Dir is set.
cmd := exec.CommandContext( //nolint:gosec
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of shelling out to casdiff, it would be nice if it could just call the main logic here as an API. This works for now though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had Claude analyze this:

The core problem is that casdiff is package main — everything is unexported and unimportable. On top of that, printMarkdown() writes directly to os.Stdout, so even if we could import it, we'd need an io.Writer-based API to capture the output as a string.

The cleanest path, following the pattern already set by private/bufpkg/bufstate, is to extract the core logic into a new package — something like private/bufpkg/bufcasdiff. That package would expose something like:

// DiffMarkdown computes the CAS diff for two refs in a module directory and
// writes the result in markdown format to w.
func DiffMarkdown(ctx context.Context, moduleDir string, from, to string, w io.Writer) error

Then:

  • cmd/casdiff becomes a thin wrapper that calls bufcasdiff.DiffMarkdown writing to os.Stdout
  • cmd/commentprcasdiff calls it writing to a strings.Builder, capturing the output directly

It's a real refactor — you'd be moving buildManifestDiff, manifestDiff, calculateDiffFromCASDirectory, and the formatting logic out of cmd/casdiff/main into the new package, and updating cmd/casdiff to use it. The calculateFileNodeDiff logic has the heaviest dependencies (cas, storage, diff from buf), but those are already dependencies of this module.

Happy to take that as a follow up!

// If base state is empty, use first appended ref as baseline
currentDigest = appendedRefs[0].GetDigest()
currentRef = appendedRefs[0].GetName()
appendedRefs = appendedRefs[1:] // Skip first as it's now the baseline
Copy link
Member

@pkwarren pkwarren Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to adjust baseRefsCount / headRefsCount here?

In general the algorithm here feels fairly complicated. Couldn't we just:

  1. Get last reference in old file.
  2. Get last reference in new file.
  3. If they differ in digest, then find the last line in the file that has the latest digest from the new file.

If we wanted to clean up old comments, we could just find all PR comments from the bot that aren't on the new line(s).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason why I wanna traverse all refs in between base and head refs is because I wanna send a comment for every digest change we find, eg:

# old file
- ref: a, digest: foo

# new file
- ref: a, digest: foo
- ref: b, digest: foo # should not produce any comment
- ref: c, digest: bar # should produce `casdiff b c`
- ref: d, digest: baz # should produce `casdiff c d`

Now, your suggestion has 2 missing points, if we only compared the latest digests in both old/new files:

  • what if old file is empty? in this implementation we handle that scenario using the first reference in the new file as the base.

  • what if latest digests in both files is the same, but there were some transitions?

# old file
- ref: a, digest: foo

# new file
- ref: a, digest: foo
- ref: b, digest: bar # some changes foo -> bar
- ref: c, digest: baz # some changes bar -> baz
- ref: d, digest: foo # reverted back to foo

In here we wouldn't produce any comment, even though there were 2. Also, that scenario is fairly unlikely, we haven't seen it yet.

If we wanted to clean up old comments, we could just find all PR comments from the bot that aren't on the new line(s).

I wouldn't want to clean up old comments, but instead avoid duplication, so if there's already a comment from the bot user in the same place we're about to post, then we update it instead. The GH UI lets us navigate across those diffs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. In most cases I'm not interested in seeing all the intermediate diffs but just the old/new to get a glimpse of the overall changes. Happy to try this out though.

As for "old file is empty" - would that only be when adding a new managed module (and not doing an initial sync)?

Copy link
Member Author

@unmultimedio unmultimedio Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chatted internally, good catch off-by-one when base is empty, fixed in 9c72750

Ok. In most cases I'm not interested in seeing all the intermediate diffs but just the old/new to get a glimpse of the overall changes. Happy to try this out though.

Because all of these refs end up being new labels, it might be interesting to see the diffs across labels? But yeah I see your point, it's nice just to see how the BSR default label changes on each PR. We could add that comment too, lemme do that tomorrow!

As for "old file is empty" - would that only be when adding a new managed module (and not doing an initial sync)?

Yes that would happen only when adding a new module, which most of the times include a manual sync, although some others we just let the fetcher run.

@unmultimedio unmultimedio marked this pull request as draft March 18, 2026 21:44
@unmultimedio unmultimedio removed the request for review from a team March 18, 2026 21:44
@unmultimedio unmultimedio changed the base branch from main to jfigueroa/mock-old-main March 18, 2026 21:45
},
{
"name": "v1.0.0",
"digest": "ddff976f6322abaecd49ff0b271b7f8dec485046bafc52fe31f3272b555fa2829328be24d71ececefca38c87319173a31f1e931984066531b6ca2016b3598146"
Copy link

@github-actions github-actions bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Updated at 2026-03-18T22:06:59Z]

$ casdiff v0.14.2 v1.0.0 --format=markdown

2 files changed: 0 removed, 0 renamed, 0 added, 2 changed content

Files changed content:

README.md:

--- shake256:5a0914c87b8da1b129f11059efb92621377fcdc3048ab5afcf82648261260fcd10af3bdf46a4df815deb40ce00b5b9a64fba8697813fa8808621d73d16b79947  README.md
+++ shake256:413ef70a5630038ee90dc20755dd02da018ac52533f977a9d9e5061b94e0fa5e4e164430d4b9166e0570c24a6eb863c2f7e8b850286f2314cbf909da9a6865cb  README.md
@@ -34,7 +34,7 @@
 
 ## Supported languages
 
-To start using Protovalidate in your projects, see the [developer quickstart][quickstart], [Protovalidate overview][protovalidate], or go directly to the repository for your language of choice:
+To start using Protovalidate in your projects, see the [developer quickstart][quickstart], [Protovalidate overview][protovalidate-overview], or go directly to the repository for your language of choice:
 
 - [`protovalidate-go`][pv-go] (Go)
 - [`protovalidate-java`][pv-java] (Java)
@@ -44,7 +44,7 @@
 
 ## Documentation
 
-Comprehensive documentation for Protovalidate is available in [Buf's documentation library][protovalidate].
+Comprehensive documentation for Protovalidate is available at [protovalidate.com][protovalidate].
 
 Highlights include:
 
@@ -81,10 +81,11 @@
 [conformance]: https://github.com/bufbuild/protovalidate/blob/main/docs/conformance.md
 [ci]: https://github.com/bufbuild/protovalidate/actions/workflows/ci.yaml
 
-[protovalidate]: https://buf.build/docs/protovalidate/
-[quickstart]: https://buf.build/docs/protovalidate/quickstart/
-[connect-go]: https://buf.build/docs/protovalidate/quickstart/connect-go/
-[grpc-go]: https://buf.build/docs/protovalidate/quickstart/grpc-go/
-[grpc-java]: https://buf.build/docs/protovalidate/quickstart/grpc-java/
-[grpc-python]: https://buf.build/docs/protovalidate/quickstart/grpc-python/
+[protovalidate]: https://protovalidate.com/
+[protovalidate-overview]: https://protovalidate.com/about/
+[quickstart]: https://protovalidate.com/quickstart/
+[connect-go]: https://protovalidate.com/quickstart/connect-go/
+[grpc-go]: https://protovalidate.com/quickstart/grpc-go/
+[grpc-java]: https://protovalidate.com/quickstart/grpc-java/
+[grpc-python]: https://protovalidate.com/quickstart/grpc-python/
 [migration-guide]: https://buf.build/docs/migration-guides/migrate-from-protoc-gen-validate/

buf/validate/validate.proto:

--- shake256:848971f837964c4ec318dbd3bee1ff7aa47ee00c461a3f5c42430e971c38cbf53001105380bc07406ad5e7518046199e3bdc408ef7d57472ee44c8c1040701d3  buf/validate/validate.proto
+++ shake256:6a5df233100ed85ab753479e45487b60e7a4b2f14ddde95dce98c72151a577b0b83576e26cbfebdb02ad2400725f4fc9b8d091704fe1e8b2f4890c7d13de9681  buf/validate/validate.proto
@@ -243,7 +243,8 @@
   // the fields are set and valid.
   //
   // Fields that don't track presence are always validated by Protovalidate,
-  // whether they are set or not. It is not necessary to add `required`:
+  // whether they are set or not. It is not necessary to add `required`. It
+  // can be added to indicate that the field cannot be the zero value.
   //
   // ```proto
   // syntax="proto3";
@@ -254,9 +255,14 @@
   //     (buf.validate.field).string.email = true
   //   ];
   //   // `repeated.min_items` always applies, even to an empty list.
-  //   repeated string labels = 4 [
+  //   repeated string labels = 2 [
   //     (buf.validate.field).repeated.min_items = 1
   //   ];
+  //   // `required`, for fields that don't track presence, indicates
+  //   // the value of the field can't be the zero value.
+  //   int32 zero_value_not_allowed = 3 [
+  //     (buf.validate.field).required = true
+  //   ];
   // }
   // ```
   //
@@ -419,7 +425,8 @@
   //   // The field's rules will always be ignored, including any validations
   //   // on value's fields.
   //   MyOtherMessage value = 1 [
-  //     (buf.validate.field).ignore = IGNORE_ALWAYS];
+  //     (buf.validate.field).ignore = IGNORE_ALWAYS
+  //   ];
   // }
   // ```
   IGNORE_ALWAYS = 3;

},
{
"name": "v1.1.0",
"digest": "35b3d88f6b0fbf159d9eedfc2fbfa976490e6bca1d98914c1c71f29bfe2da6261fca56c057975b3e5c022b3234a0f2eea8e2d1b599a937c6c5d63d21201a9bc3"
Copy link

@github-actions github-actions bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Updated at 2026-03-18T22:07:00Z]

$ casdiff v1.0.0 v1.1.0 --format=markdown

2 files changed: 0 removed, 0 renamed, 0 added, 2 changed content

Files changed content:

README.md:

--- shake256:413ef70a5630038ee90dc20755dd02da018ac52533f977a9d9e5061b94e0fa5e4e164430d4b9166e0570c24a6eb863c2f7e8b850286f2314cbf909da9a6865cb  README.md
+++ shake256:26622ee52e0fe9e7daa0bd4cdc14bef2dc25f8bfacc79d077db09aebb218bb34d9911e4f525ef8571efba1db405d1d2855b2213e8aa42c6db1724ac9179d15e0  README.md
@@ -88,4 +88,4 @@
 [grpc-go]: https://protovalidate.com/quickstart/grpc-go/
 [grpc-java]: https://protovalidate.com/quickstart/grpc-java/
 [grpc-python]: https://protovalidate.com/quickstart/grpc-python/
-[migration-guide]: https://buf.build/docs/migration-guides/migrate-from-protoc-gen-validate/
+[migration-guide]: https://protovalidate.com/migration-guides/migrate-from-protoc-gen-validate/

buf/validate/validate.proto:

--- shake256:6a5df233100ed85ab753479e45487b60e7a4b2f14ddde95dce98c72151a577b0b83576e26cbfebdb02ad2400725f4fc9b8d091704fe1e8b2f4890c7d13de9681  buf/validate/validate.proto
+++ shake256:64f9cf945094e1bec0406887f3d6b7704e051c750c3b2ef45d678232d25dc451f9f0304dd9161b853a5ec5b61c9df583f92180db3319d082ae5d0ff46c70c202  buf/validate/validate.proto
@@ -18,6 +18,7 @@
 
 import "google/protobuf/descriptor.proto";
 import "google/protobuf/duration.proto";
+import "google/protobuf/field_mask.proto";
 import "google/protobuf/timestamp.proto";
 
 option go_package = "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate";
@@ -109,6 +110,25 @@
 // MessageRules represents validation rules that are applied to the entire message.
 // It includes disabling options and a list of Rule messages representing Common Expression Language (CEL) validation rules.
 message MessageRules {
+  // `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation
+  // rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax.
+  //
+  // This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for
+  // simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will
+  // be same as the `expression`.
+  //
+  // For more information, [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `foo` must be greater than 42.
+  //   option (buf.validate.message).cel_expression = "this.foo > 42";
+  //   // The field `foo` must be less than 84.
+  //   option (buf.validate.message).cel_expression = "this.foo < 84";
+  //   optional int32 foo = 1;
+  // }
+  // ```
+  repeated string cel_expression = 5;
   // `cel` is a repeated field of type Rule. Each Rule specifies a validation rule to be applied to this message.
   // These rules are written in Common Expression Language (CEL) syntax. For more information,
   // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
@@ -201,6 +221,22 @@
 // FieldRules encapsulates the rules for each type of field. Depending on
 // the field, the correct set should be used to ensure proper validations.
 message FieldRules {
+  // `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation
+  // rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax.
+  //
+  // This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for
+  // simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will
+  // be same as the `expression`.
+  //
+  // For more information, [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be greater than 42.
+  //   optional int32 value = 1 [(buf.validate.field).cel_expression = "this > 42"];
+  // }
+  // ```
+  repeated string cel_expression = 29;
   // `cel` is a repeated field used to represent a textual expression
   // in the Common Expression Language (CEL) syntax. For more information,
   // [see our documentation](https://buf.build/docs/protovalidate/schemas/custom-rules/).
@@ -313,6 +349,7 @@
     // Well-Known Field Types
     AnyRules any = 20;
     DurationRules duration = 21;
+    FieldMaskRules field_mask = 28;
     TimestampRules timestamp = 22;
   }
 
@@ -3731,6 +3768,29 @@
       }
     ];
 
+    // `ulid` specifies that the field value must be a valid ULID (Universally Unique
+    // Lexicographically Sortable Identifier) as defined by the [ULID specification](https://github.com/ulid/spec).
+    // If the field value isn't a valid ULID, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid ULID
+    //   string value = 1 [(buf.validate.field).string.ulid = true];
+    // }
+    // ```
+    bool ulid = 35 [
+      (predefined).cel = {
+        id: "string.ulid"
+        message: "value must be a valid ULID"
+        expression: "!rules.ulid || this == '' || this.matches('^[0-7][0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{25}$')"
+      },
+      (predefined).cel = {
+        id: "string.ulid_empty"
+        message: "value is empty, which is not a valid ULID"
+        expression: "!rules.ulid || this != ''"
+      }
+    ];
+
     // `well_known_regex` specifies a common well-known pattern
     // defined as a regex. If the field value doesn't match the well-known
     // regex, an error message will be generated.
@@ -3943,7 +4003,7 @@
   // the string.
   // If the field value doesn't meet the requirement, an error message is generated.
   //
-  // ```protobuf
+  // ```proto
   // message MyBytes {
   //   // value does not contain \x02\x03
   //   optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"];
@@ -3958,7 +4018,7 @@
   // values. If the field value doesn't match any of the specified values, an
   // error message is generated.
   //
-  // ```protobuf
+  // ```proto
   // message MyBytes {
   //   // value must in ["\x01\x02", "\x02\x03", "\x03\x04"]
   //   optional bytes value = 1 [(buf.validate.field).bytes.in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
@@ -4052,6 +4112,31 @@
         expression: "!rules.ipv6 || this.size() != 0"
       }
     ];
+
+    // `uuid` ensures that the field `value` encodes the 128-bit UUID data as
+    // defined by [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2).
+    // The field must contain exactly 16 bytes
+    // representing the UUID. If the field value isn't a valid UUID, an error
+    // message will be generated.
+    //
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid UUID
+    //   optional bytes value = 1 [(buf.validate.field).bytes.uuid = true];
+    // }
+    // ```
+    bool uuid = 15 [
+      (predefined).cel = {
+        id: "bytes.uuid"
+        message: "value must be a valid UUID"
+        expression: "!rules.uuid || this.size() == 0 || this.size() == 16"
+      },
+      (predefined).cel = {
+        id: "bytes.uuid_empty"
+        message: "value is empty, which is not a valid UUID"
+        expression: "!rules.uuid || this.size() != 0"
+      }
+    ];
   }
 
   // `example` specifies values that the field may have. These values SHOULD
@@ -4592,6 +4677,93 @@
     expression: "true"
   }];
 
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field rules that can then be
+  // set on the field options of other fields to apply field rules.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// FieldMaskRules describe rules applied exclusively to the `google.protobuf.FieldMask` well-known type.
+message FieldMaskRules {
+  // `const` dictates that the field must match the specified value of the `google.protobuf.FieldMask` type exactly.
+  // If the field's value deviates from the specified value, an error message
+  // will be generated.
+  //
+  // ```proto
+  // message MyFieldMask {
+  //   // value must equal ["a"]
+  //   google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask.const = {
+  //       paths: ["a"]
+  //   }];
+  // }
+  // ```
+  optional google.protobuf.FieldMask const = 1 [(predefined).cel = {
+    id: "field_mask.const"
+    expression: "this.paths != getField(rules, 'const').paths ? 'value must equal paths %s'.format([getField(rules, 'const').paths]) : ''"
+  }];
+
+  // `in` requires the field value to only contain paths matching specified
+  // values or their subpaths.
+  // If any of the field value's paths doesn't match the rule,
+  // an error message is generated.
+  // See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask
+  //
+  // ```proto
+  // message MyFieldMask {
+  //   //  The `value` FieldMask must only contain paths listed in `in`.
+  //   google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = {
+  //       in: ["a", "b", "c.a"]
+  //   }];
+  // }
+  // ```
+  repeated string in = 2 [(predefined).cel = {
+    id: "field_mask.in"
+    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')]) : ''"
+  }];
+
+  // `not_in` requires the field value to not contain paths matching specified
+  // values or their subpaths.
+  // If any of the field value's paths matches the rule,
+  // an error message is generated.
+  // See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask
+  //
+  // ```proto
+  // message MyFieldMask {
+  //   //  The `value` FieldMask shall not contain paths listed in `not_in`.
+  //   google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = {
+  //       not_in: ["forbidden", "immutable", "c.a"]
+  //   }];
+  // }
+  // ```
+  repeated string not_in = 3 [(predefined).cel = {
+    id: "field_mask.not_in"
+    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')]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other rules. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFieldMask {
+  //   google.protobuf.FieldMask value = 1 [
+  //     (buf.validate.field).field_mask.example = { paths: ["a", "b"] },
+  //     (buf.validate.field).field_mask.example = { paths: ["c.a", "d"] },
+  //   ];
+  // }
+  // ```
+  repeated google.protobuf.FieldMask example = 4 [(predefined).cel = {
+    id: "field_mask.example"
+    expression: "true"
+  }];
+
   // Extension fields in this range that have the (buf.validate.predefined)
   // option set will be treated as predefined field rules that can then be
   // set on the field options of other fields to apply field rules.

},
{
"name": "v1.1.1",
"digest": "2d64e8ff856e1bf78a1289c24e868bdbe1ee2196f32b10bfe6ad8a743c7db99ba4be1a75c21d9f865ffa28464e11d339365b0f7937c75f7b308b3d5993cefd25"
Copy link

@github-actions github-actions bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Updated at 2026-03-18T22:07:00Z]

$ casdiff v1.1.0 v1.1.1 --format=markdown

2 files changed: 0 removed, 0 renamed, 0 added, 2 changed content

Files changed content:

LICENSE:

--- shake256:16e9625485026e419d9b1b46bc780f0f734c02cbf8587f8c923e72d9ab4c826158af791a94b8590a846dc1698dc73d5170dd03124652264d9fe92ddce2595fc4  LICENSE
+++ shake256:e702a95ca4516da9365b47a96282a3997660ecff5f614135d19a480ae7e9fb7fc0780efa034d133b95f5fe214a9fe4dd1cd65a9a9b6362db5f07792c0b699f38  LICENSE
@@ -186,7 +186,7 @@
       same "printed page" as the copyright notice for easier
       identification within third-party archives.
 
-   Copyright 2023-2025 Buf Technologies, Inc.
+   Copyright 2023-2026 Buf Technologies, Inc.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.

buf/validate/validate.proto:

--- shake256:64f9cf945094e1bec0406887f3d6b7704e051c750c3b2ef45d678232d25dc451f9f0304dd9161b853a5ec5b61c9df583f92180db3319d082ae5d0ff46c70c202  buf/validate/validate.proto
+++ shake256:2751dd35f02933b1ae7a0394896014c1506c8aa3a737d3f65c81fb67f6332626db630c1c9291a579bb8b60d1eccd35064e19dffdbffd033dd0144bd228861503  buf/validate/validate.proto
@@ -1,4 +1,4 @@
-// Copyright 2023-2025 Buf Technologies, Inc.
+// Copyright 2023-2026 Buf Technologies, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,6 +14,34 @@
 
 syntax = "proto2";
 
+// [Protovalidate](https://protovalidate.com/) is the semantic validation library for Protobuf.
+// It provides standard annotations to validate common rules on messages and fields, as well as the ability to use [CEL](https://cel.dev) to write custom rules.
+// It's the next generation of [protoc-gen-validate](https://github.com/bufbuild/protoc-gen-validate).
+//
+// This package provides the options, messages, and enums that power Protovalidate.
+// Apply its options to messages, fields, and oneofs in your Protobuf schemas to add validation rules:
+//
+// ```proto
+// message User {
+//   string id = 1 [(buf.validate.field).string.uuid = true];
+//   string first_name = 2 [(buf.validate.field).string.max_len = 64];
+//   string last_name = 3 [(buf.validate.field).string.max_len = 64];
+//
+//   option (buf.validate.message).cel = {
+//     id: "first_name_requires_last_name"
+//     message: "last_name must be present if first_name is present"
+//     expression: "!has(this.first_name) || has(this.last_name)"
+//   };
+// }
+// ```
+//
+// These rules are enforced at runtime by language-specific libraries.
+// See the [developer quickstart](https://protovalidate.com/quickstart/) to get started, or go directly to the runtime library for your language:
+// [Go](https://github.com/bufbuild/protovalidate-go)
+// [JavaScript/TypeScript](https://github.com/bufbuild/protovalidate-es),
+// [Java](https://github.com/bufbuild/protovalidate-java),
+// [Python](https://github.com/bufbuild/protovalidate-python),
+// or [C++](https://github.com/bufbuild/protovalidate-cc).
 package buf.validate;
 
 import "google/protobuf/descriptor.proto";
@@ -683,16 +711,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -904,16 +925,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -1119,16 +1133,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -1334,16 +1341,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -1549,16 +1549,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -1763,16 +1756,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -1977,16 +1963,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -2191,16 +2170,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -2405,16 +2377,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -2619,16 +2584,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -2833,16 +2791,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -3047,16 +2998,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -3094,16 +3038,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -3867,16 +3804,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4156,16 +4086,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4271,16 +4194,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4354,16 +4270,9 @@
   // cannot be unset.
   optional FieldRules items = 4;
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4432,16 +4341,9 @@
   // Note that the `required` rule does not apply. Map values cannot be unset.
   optional FieldRules values = 5;
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4677,16 +4579,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4764,16 +4659,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 
@@ -4982,16 +4870,9 @@
     expression: "true"
   }];
 
-  // Extension fields in this range that have the (buf.validate.predefined)
-  // option set will be treated as predefined field rules that can then be
-  // set on the field options of other fields to apply field rules.
-  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
-  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
-  // above this range are reserved for extension numbers that are not explicitly
-  // assigned. For rules defined in publicly-consumed schemas, use of extensions
-  // above 99999 is discouraged due to the risk of conflicts.
-  //
-  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  // Extension fields that have the (buf.validate.predefined) option set
+  // will be treated as predefined field rules.
+  // See https://protovalidate.com/schemas/predefined-rules/
   extensions 1000 to max;
 }
 

@unmultimedio unmultimedio changed the base branch from jfigueroa/mock-old-main to main March 18, 2026 22:09
@unmultimedio unmultimedio marked this pull request as ready for review March 18, 2026 22:10
@unmultimedio unmultimedio requested a review from pkwarren March 18, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants