Skip to content

Add string.uuid_types and string.tuuid_types rules - #532

Open
otnc wants to merge 1 commit into
bufbuild:mainfrom
otnc:uuid-types
Open

otnc wants to merge 1 commit into
bufbuild:mainfrom
otnc:uuid-types

Conversation

@otnc

@otnc otnc commented Sep 16, 2026

Copy link
Copy Markdown

Closes #530.

As discussed in that issue, string.uuid and string.tuuid keep checking the shape only, so that UUID versions defined in the future are not rejected, and their documentation now says so. This adds string.uuid_types and string.tuuid_types for callers who do want the stricter check.

message MyString {
  // must be a UUIDv4
  string value = 1 [(buf.validate.field).string.uuid_types = UUID_V4];

  // must be a UUIDv4 or a UUIDv7
  string reference_id = 2 [(buf.validate.field).string = {uuid_types: [UUID_V4, UUID_V7]}];
}

A listed version must also carry the RFC 9562 variant (8, 9, a or b), since a version without it is not a UUID of that version. UUID_NIL and UUID_MAX are the two special cases that follow neither rule. An empty list means no restriction, and UUID_UNSPECIFIED matches nothing.

No custom CEL function needed

The issue mentioned pushing this down into a custom CEL function. It turned out not to be necessary: the version is the only part of the pattern that varies, and it is the decimal digit of the enum value, so the expression builds the pattern from string(t).

rules.uuid_types.size() == 0 || this == '' || rules.uuid_types.exists(t,
t == 9 ? this.matches('^0{8}-0{4}-0{4}-0{4}-0{12}$') :
t == 10 ? this.matches('^[fF]{8}-[fF]{4}-[fF]{4}-[fF]{4}-[fF]{12}$') :
t >= 1 && t <= 8 && this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-' + string(t) + '[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$'))

That keeps this PR to the schema and the conformance suite, and means no runtime needs a new function to implement it. A dynamic argument to matches is already used by string.well_known_regex.

Changes

  • validate.proto: a Uuid enum (UUID_V1 through UUID_V8, UUID_NIL, UUID_MAX), the uuid_types (39) and tuuid_types (40) rules with their *_empty companions, and reworded documentation for uuid and tuuid.
  • Conformance: six case messages in strings.proto and 21 cases covering both rules, including the variant check, the Nil and Max UUIDs, an unspecified list, and a dashed value given to tuuid_types.
  • tools/internal/gen: regenerated.

Checks

buf lint, buf format, make lint-protovalidate, go build ./tools/..., go vet ./tools/... and go test ./tools/protovalidate-conformance/... pass. (TestMigrator fails for me on main as well, before this change: it compares golden files and I am on Windows.)

To confirm the expressions themselves, I evaluated them exactly as written in validate.proto, with the rule list substituted, against every value in the new conformance cases. All 24 evaluations matched the expected outcome under both CEL implementations, protovalidate-es and protovalidate-go.

Open questions

  • Field numbers: I used 39 and 40, since 36 is unused but not reserved and Add protobuf_fqn and protobuf_dot_fqn #465 skipped it. Happy to move them.
  • Enum naming: Uuid with UUID_V4 follows the sketch in the issue and satisfies ENUM_VALUE_PREFIX. If you would rather have UuidType with UUID_TYPE_V4, say the word.
  • The enum covers what RFC 9562 defines as a UUID. If you also want to allow the Microsoft variant (c/d) or the reserved variant (e/f), I can add values for them.
  • Documentation on protovalidate.com lives in another repository; I am happy to follow up there once this lands.

The uuid and tuuid rules only enforce the textual shape, which is deliberate so that future UUID versions are not rejected. These new rules restrict a value to the UUID types listed, checking the version and the RFC 9562 variant, with the Nil and Max UUIDs as special cases. The documentation of uuid and tuuid now says that they check the shape only.
@CLAassistant

CLAassistant commented Sep 16, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

[BUG] string.uuid and string.tuuid accept values with an undefined UUID version or variant

2 participants