{"id":13461376,"url":"https://github.com/bufbuild/protoc-gen-validate","last_synced_at":"2026-02-18T17:03:44.213Z","repository":{"id":37732910,"uuid":"105711679","full_name":"bufbuild/protoc-gen-validate","owner":"bufbuild","description":"Protocol Buffer Validation - replaced by https://github.com/bufbuild/protovalidate","archived":false,"fork":false,"pushed_at":"2026-01-26T15:04:57.000Z","size":14856,"stargazers_count":4097,"open_issues_count":13,"forks_count":598,"subscribers_count":190,"default_branch":"main","last_synced_at":"2026-01-26T15:15:38.364Z","etag":null,"topics":["constraints","protoc","protoc-plugin","protocol-buffers","validation"],"latest_commit_sha":null,"homepage":"https://github.com/bufbuild/protovalidate","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bufbuild.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-10-03T22:51:17.000Z","updated_at":"2026-01-26T15:04:59.000Z","dependencies_parsed_at":"2023-02-13T02:01:55.920Z","dependency_job_id":"05e9e75c-befa-41e3-8a35-5db3f271a594","html_url":"https://github.com/bufbuild/protoc-gen-validate","commit_stats":{"total_commits":476,"total_committers":139,"mean_commits":"3.4244604316546763","dds":0.7668067226890756,"last_synced_commit":"0ea3708b3daae55e0037bb6a04df45d8542c4f6c"},"previous_names":["bufbuild/protoc-gen-validate","envoyproxy/protoc-gen-validate","lyft/protoc-gen-validate"],"tags_count":223,"template":false,"template_full_name":null,"purl":"pkg:github/bufbuild/protoc-gen-validate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bufbuild%2Fprotoc-gen-validate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bufbuild%2Fprotoc-gen-validate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bufbuild%2Fprotoc-gen-validate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bufbuild%2Fprotoc-gen-validate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bufbuild","download_url":"https://codeload.github.com/bufbuild/protoc-gen-validate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bufbuild%2Fprotoc-gen-validate/sbom","scorecard":{"id":257305,"data":{"date":"2025-08-11","repo":{"name":"github.com/bufbuild/protoc-gen-validate","commit":"b3457d0baa718735d053a42fa465a1c22743eb3c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":6,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Code-Review","score":10,"reason":"all changesets reviewed","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/maven-verify.yaml:10","Warn: no topLevel permission defined: .github/workflows/add-to-project.yaml:1","Warn: no topLevel permission defined: .github/workflows/ci.yaml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/goreleaser.yaml:10","Warn: no topLevel permission defined: .github/workflows/maven-deploy.yaml:1","Warn: no topLevel permission defined: .github/workflows/maven-release.yaml:1","Warn: no topLevel permission defined: .github/workflows/maven-verify.yaml:1","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/notify-approval-bypass.yaml:9","Info: topLevel 'pull-requests' permission set to 'read': .github/workflows/pr-title.yaml:5","Warn: no topLevel permission defined: .github/workflows/python-package.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":10,"reason":"14 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":10,"reason":"project is fuzzed","details":["Info: OSSFuzz integration found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/add-to-project.yaml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/add-to-project.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:32: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:33: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/ci.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yaml:37: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/ci.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/emergency-review-bypass.yaml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/emergency-review-bypass.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/goreleaser.yaml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/goreleaser.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/goreleaser.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/goreleaser.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/goreleaser.yaml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/goreleaser.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/goreleaser.yaml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/goreleaser.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-deploy.yaml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-deploy.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-deploy.yaml:24: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-deploy.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-deploy.yaml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-deploy.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-release.yaml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-release.yaml:34: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-release.yaml:62: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-release.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-verify.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-verify.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-verify.yaml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-verify.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/maven-verify.yaml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/maven-verify.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/notify-approval-bypass.yaml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/notify-approval-bypass.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pr-title.yaml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/pr-title.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/python-package.yaml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/python-package.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/python-package.yaml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/python-package.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/python-package.yaml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/python-package.yaml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/python-package.yaml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/bufbuild/protoc-gen-validate/python-package.yaml/main?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating ubuntu:focal to ubuntu:focal@sha256:8feb4d8ca5354def3d8fce243717141ce31e2c428701f6682bd2fafe15388214","Warn: pipCommand not pinned by hash: .github/workflows/ci.yaml:52","Info:   0 out of  17 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   8 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/goreleaser.yaml:13"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v1.2.1 not signed: https://api.github.com/repos/bufbuild/protoc-gen-validate/releases/196201484","Warn: release artifact v1.2.0 not signed: https://api.github.com/repos/bufbuild/protoc-gen-validate/releases/196185611","Warn: release artifact v1.2.1 does not have provenance: https://api.github.com/repos/bufbuild/protoc-gen-validate/releases/196201484","Warn: release artifact v1.2.0 does not have provenance: https://api.github.com/repos/bufbuild/protoc-gen-validate/releases/196185611"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T09:58:43.349Z","repository_id":37732910,"created_at":"2025-08-17T09:58:43.349Z","updated_at":"2025-08-17T09:58:43.349Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29587066,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T16:55:40.614Z","status":"ssl_error","status_checked_at":"2026-02-18T16:55:37.558Z","response_time":162,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constraints","protoc","protoc-plugin","protocol-buffers","validation"],"created_at":"2024-07-31T11:00:36.615Z","updated_at":"2026-02-18T17:03:44.157Z","avatar_url":"https://github.com/bufbuild.png","language":"Go","readme":"# [![](./.github/buf-logo.svg)][buf] protoc-gen-validate (PGV)\n\n![License](https://img.shields.io/github/license/bufbuild/protoc-gen-validate?color=blue)\n![Release](https://img.shields.io/github/v/release/bufbuild/protoc-gen-validate?include_prereleases)\n![Slack](https://img.shields.io/badge/slack-buf-%23e01563)\n\n\u003e [!IMPORTANT]\n\u003e protoc-gen-validate (PGV) has reached a stable state and is in maintenance mode.\n\u003e\n\u003e We recommend that new and existing projects transition to using [`protovalidate`][pv].\n\u003e Our [migration guide][migration-guide] walks you through the process.\n\u003e \n\u003e Read [our blog post][pv-announce] if you want to learn more about the limitations of protoc-gen-validate and\n\u003e how we have designed [`protovalidate`][pv] to be better.\n\nPGV is a protoc plugin to generate polyglot message validators. While protocol\nbuffers effectively guarantee the types of structured data, they cannot enforce\nsemantic rules for values. This plugin adds support to protoc-generated code to\nvalidate such constraints.\n\nDevelopers import the PGV extension and annotate the messages and fields in\ntheir proto files with constraint rules:\n\n```protobuf\nsyntax = \"proto3\";\n\npackage examplepb;\n\nimport \"validate/validate.proto\";\n\nmessage Person {\n  uint64 id = 1 [(validate.rules).uint64.gt = 999];\n\n  string email = 2 [(validate.rules).string.email = true];\n\n  string name = 3 [(validate.rules).string = {\n    pattern:   \"^[A-Za-z]+( [A-Za-z]+)*$\",\n    max_bytes: 256,\n  }];\n\n  Location home = 4 [(validate.rules).message.required = true];\n\n  message Location {\n    double lat = 1 [(validate.rules).double = {gte: -90,  lte: 90}];\n    double lng = 2 [(validate.rules).double = {gte: -180, lte: 180}];\n  }\n}\n```\n\nExecuting `protoc` with PGV and the target language's default plugin will\ncreate `Validate` methods on the generated types:\n\n```go\np := new(Person)\n\nerr := p.Validate() // err: Id must be greater than 999\np.Id = 1000\n\nerr = p.Validate() // err: Email must be a valid email address\np.Email = \"example@bufbuild.com\"\n\nerr = p.Validate() // err: Name must match pattern '^[A-Za-z]+( [A-Za-z]+)*$'\np.Name = \"Protocol Buffer\"\n\nerr = p.Validate() // err: Home is required\np.Home = \u0026Location{37.7, 999}\n\nerr = p.Validate() // err: Home.Lng must be within [-180, 180]\np.Home.Lng = -122.4\n\nerr = p.Validate() // err: nil\n```\n\n## Usage\n\n### Dependencies\n\n- `go` toolchain (≥ v1.7)\n- `protoc` compiler in `$PATH`\n- `protoc-gen-validate` in `$PATH`\n- official language-specific plugin for target language(s)\n- **Only `proto3` syntax is currently supported.**\n\n### Installation\n\n#### Download from GitHub Releases\n\nDownload assets from [GitHub Releases](https://github.com/bufbuild/protoc-gen-validate/releases) and unarchive them and add plugins into `$PATH`.\n\n#### Build from source\n\n```sh\n# fetches this repo into $GOPATH\ngo get -d github.com/envoyproxy/protoc-gen-validate\n```\n\n\u003e #### 💡 Yes, our go module path is `github.com/envoyproxy/protoc-gen-validate` **not** `bufbuild` this is intentional.\n\u003e Changing the module path is effectively creating a new, independent module. We\n\u003e would prefer not to break our users. The Go team are working on\n\u003e better `cmd/go`\n\u003e support for modules that change paths, but progress is slow. Until then, we\n\u003e will\n\u003e continue to use the `envoyproxy` module path.\n\n```\ngit clone https://github.com/bufbuild/protoc-gen-validate.git\n# installs PGV into $GOPATH/bin\ncd protoc-gen-validate \u0026\u0026 make build\n```\n\n### Parameters\n\n- **`lang`**: specify the target language to generate. Currently, the only\n  supported options are:\n    - `go`\n    - `cc` for c++ (partially implemented)\n    - `java`\n- Note: Python works via runtime code generation. There's no compile-time\n  generation. See the Python section for details.\n\n### Examples\n\n#### Go\n\nGo generation should occur into the same output path as the official plugin. For\na proto file `example.proto`, the corresponding validation code is generated\ninto `../generated/example.pb.validate.go`:\n\n```sh\nprotoc \\\n  -I . \\\n  -I path/to/validate/ \\\n  --go_out=\":../generated\" \\\n  --validate_out=\"lang=go:../generated\" \\\n  example.proto\n```\n\nAll messages generated include the following methods:\n\n- `Validate() error` which returns the first error encountered during\n  validation.\n- `ValidateAll() error` which returns all errors encountered during validation.\n\nPGV requires no additional runtime dependencies from the existing generated\ncode.\n\n**Note**: by default **example.pb.validate.go** is nested in a directory\nstructure that matches your `option go_package` name. You can change this using\nthe protoc parameter `paths=source_relative:.`, as like `--validate_out=\"lang=go,paths=source_relative:../generated\"`. Then `--validate_out` will\noutput the file where it is expected. See Google's protobuf documentation\nor [packages and input paths](https://github.com/golang/protobuf#packages-and-input-paths)\nor [parameters](https://github.com/golang/protobuf#parameters) for more\ninformation.\n\nThere's also support for the `module=example.com/foo`\nflag [described here](https://developers.google.com/protocol-buffers/docs/reference/go-generated#invocation)\n.\n\nWith newer Buf CLI versions (\u003ev1.9.0), you can use the new plugin key instead of using the `protoc` command directly:\n\n```\n# buf.gen.yaml\n\nversion: v1\nplugins:\n  - plugin: buf.build/bufbuild/validate-go\n    out: gen\n```\n\n```\n# proto/buf.yaml\n\nversion: v1\ndeps:\n  - buf.build/envoyproxy/protoc-gen-validate\n```\n\n#### Java\n\nJava generation is integrated with the existing protobuf toolchain for java\nprojects. For Maven projects, add the\nfollowing to your pom.xml or build.gradle.\n\n```xml\n\n\u003cdependencies\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ebuild.buf.protoc-gen-validate\u003c/groupId\u003e\n        \u003cartifactId\u003epgv-java-stub\u003c/artifactId\u003e\n        \u003cversion\u003e${pgv.version}\u003c/version\u003e\n    \u003c/dependency\u003e\n\u003c/dependencies\u003e\n\n\u003cbuild\u003e\n\u003cextensions\u003e\n    \u003cextension\u003e\n        \u003cgroupId\u003ekr.motd.maven\u003c/groupId\u003e\n        \u003cartifactId\u003eos-maven-plugin\u003c/artifactId\u003e\n        \u003cversion\u003e1.4.1.Final\u003c/version\u003e\n    \u003c/extension\u003e\n\u003c/extensions\u003e\n\u003cplugins\u003e\n    \u003cplugin\u003e\n        \u003cgroupId\u003eorg.xolstice.maven.plugins\u003c/groupId\u003e\n        \u003cartifactId\u003eprotobuf-maven-plugin\u003c/artifactId\u003e\n        \u003cversion\u003e0.6.1\u003c/version\u003e\n        \u003cconfiguration\u003e\n            \u003cprotocArtifact\u003e\n                com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}\n            \u003c/protocArtifact\u003e\n        \u003c/configuration\u003e\n        \u003cexecutions\u003e\n            \u003cexecution\u003e\n                \u003cid\u003eprotoc-java-pgv\u003c/id\u003e\n                \u003cgoals\u003e\n                    \u003cgoal\u003ecompile-custom\u003c/goal\u003e\n                \u003c/goals\u003e\n                \u003cconfiguration\u003e\n                    \u003cpluginParameter\u003elang=java\u003c/pluginParameter\u003e\n                    \u003cpluginId\u003ejava-pgv\u003c/pluginId\u003e\n                    \u003cpluginArtifact\u003e\n                        build.buf.protoc-gen-validate:protoc-gen-validate:${pgv.version}:exe:${os.detected.classifier}\n                    \u003c/pluginArtifact\u003e\n                \u003c/configuration\u003e\n            \u003c/execution\u003e\n        \u003c/executions\u003e\n    \u003c/plugin\u003e\n\u003c/plugins\u003e\n\u003c/build\u003e\n```\n\n```gradle\nplugins {\n    ...\n    id \"com.google.protobuf\" version \"${protobuf.version}\"\n    ...\n}\n\nprotobuf {\n    protoc {\n        artifact = \"com.google.protobuf:protoc:${protoc.version}\"\n    }\n\n    plugins {\n        javapgv {\n            artifact = \"build.buf.protoc-gen-validate:protoc-gen-validate:${pgv.version}\"\n        }\n    }\n\n    generateProtoTasks {\n        all()*.plugins {\n            javapgv {\n                option \"lang=java\"\n            }\n        }\n    }\n}\n```\n\n```java\n// Create a validator index that reflectively loads generated validators\nValidatorIndex index = new ReflectiveValidatorIndex();\n// Assert that a message is valid\nindex.validatorFor(message.getClass()).assertValid(message);\n\n// Create a gRPC client and server interceptor to automatically validate messages (requires pgv-java-grpc module)\nclientStub = clientStub.withInterceptors(new ValidatingClientInterceptor(index));\nserverBuilder.addService(ServerInterceptors.intercept(svc, new ValidatingServerInterceptor(index)));\n```\n\n#### Python\n\nThe python implementation works via JIT code generation. In other words,\nthe `validate(msg)` function is written\non-demand and [exec-ed](https://docs.python.org/3/library/functions.html#exec).\nAn LRU-cache improves performance by\nstoring generated functions per descriptor.\n\nThe python package is available\non [PyPI](https://pypi.org/project/protoc-gen-validate).\n\nTo run `validate()`, do the following:\n\n```python\nfrom entities_pb2 import Person\nfrom protoc_gen_validate.validator import validate, ValidationFailed\n\np = Person(first_name=\"Foo\", last_name=\"Bar\", age=42)\ntry:\n    validate(p)\nexcept ValidationFailed as err:\n    print(err)\n```\n\nYou can view what code has been generated by using the `print_validate()`\nfunction.\n\n## Constraint Rules\n\n[The provided constraints](validate/validate.proto) are modeled largerly after\nthose in JSON Schema. PGV rules can be mixed for the same field; the plugin\nensures the rules applied to a field cannot contradict before code generation.\n\nCheck the [constraint rule comparison matrix](rule_comparison.md) for\nlanguage-specific constraint capabilities.\n\n### Numerics\n\n\u003e All numeric types (`float`, `double`, `int32`, `int64`, `uint32`, `uint64`\n\u003e , `sint32`, `sint64`, `fixed32`, `fixed64`, `sfixed32`, `sfixed64`) share the\n\u003e same rules.\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must equal 1.23 exactly\n  float x = 1 [(validate.rules).float.const = 1.23];\n  ```\n\n- **lt/lte/gt/gte**: these inequalities (`\u003c`, `\u003c=`, `\u003e`, `\u003e=`, respectively)\n  allow for deriving ranges in which the field must reside.\n\n  ```protobuf\n  // x must be less than 10\n  int32 x = 1 [(validate.rules).int32.lt = 10];\n\n  // x must be greater than or equal to 20\n  uint64 x = 1 [(validate.rules).uint64.gte = 20];\n\n  // x must be in the range [30, 40)\n  fixed32 x = 1 [(validate.rules).fixed32 = {gte:30, lt: 40}];\n  ```\n\n  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive\n  range.\n\n  ```protobuf\n  // x must be outside the range [30, 40)\n  double x = 1 [(validate.rules).double = {lt:30, gte:40}];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for the\n  values of a field.\n\n  ```protobuf\n  // x must be either 1, 2, or 3\n  uint32 x = 1 [(validate.rules).uint32 = {in: [1,2,3]}];\n\n  // x cannot be 0 nor 0.99\n  float x = 1 [(validate.rules).float = {not_in: [0, 0.99]}];\n  ```\n\n- **ignore_empty**: this rule specifies that if field is empty or set to the\n  default value, to ignore any validation rules. These are typically useful\n  where being able to unset a field in an update request, or to skip validation\n  for optional fields where switching to WKTs is not feasible.\n\n  ```protobuf\n  uint32 x = 1 [(validate.rules).uint32 = {ignore_empty: true, gte: 200}];\n  ```\n\n### Bools\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must be set to true\n  bool x = 1 [(validate.rules).bool.const = true];\n\n  // x cannot be set to true\n  bool x = 1 [(validate.rules).bool.const = false];\n  ```\n\n### Strings\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must be set to \"foo\"\n  string x = 1 [(validate.rules).string.const = \"foo\"];\n  ```\n\n- **len/min_len/max_len**: these rules constrain the number of characters (\n  Unicode code points) in the field. Note that the number of characters may\n  differ from the number of bytes in the string. The string is considered as-is,\n  and does not normalize.\n\n  ```protobuf\n  // x must be exactly 5 characters long\n  string x = 1 [(validate.rules).string.len = 5];\n\n  // x must be at least 3 characters long\n  string x = 1 [(validate.rules).string.min_len = 3];\n\n  // x must be between 5 and 10 characters, inclusive\n  string x = 1 [(validate.rules).string = {min_len: 5, max_len: 10}];\n  ```\n\n- **min_bytes/max_bytes**: these rules constrain the number of bytes in the\n  field.\n\n  ```protobuf\n  // x must be at most 15 bytes long\n  string x = 1 [(validate.rules).string.max_bytes = 15];\n\n  // x must be between 128 and 1024 bytes long\n  string x = 1 [(validate.rules).string = {min_bytes: 128, max_bytes: 1024}];\n  ```\n\n- **pattern**: the field must match the specified [RE2-compliant][re2] regular\n  expression. The included expression should elide any delimiters (ie, `/\\d+/`\n  should just be `\\d+`).\n\n  ```protobuf\n  // x must be a non-empty, case-insensitive hexadecimal string\n  string x = 1 [(validate.rules).string.pattern = \"(?i)^[0-9a-f]+$\"];\n  ```\n\n- **prefix/suffix/contains/not_contains**: the field must contain the specified\n  substring in an optionally explicit location, or not contain the specified\n  substring.\n\n  ```protobuf\n  // x must begin with \"foo\"\n  string x = 1 [(validate.rules).string.prefix = \"foo\"];\n\n  // x must end with \"bar\"\n  string x = 1 [(validate.rules).string.suffix = \"bar\"];\n\n  // x must contain \"baz\" anywhere inside it\n  string x = 1 [(validate.rules).string.contains = \"baz\"];\n\n  // x cannot contain \"baz\" anywhere inside it\n  string x = 1 [(validate.rules).string.not_contains = \"baz\"];\n\n  // x must begin with \"fizz\" and end with \"buzz\"\n  string x = 1 [(validate.rules).string = {prefix: \"fizz\", suffix: \"buzz\"}];\n\n  // x must end with \".proto\" and be less than 64 characters\n  string x = 1 [(validate.rules).string = {suffix: \".proto\", max_len:64}];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for the\n  values of a field.\n\n  ```protobuf\n  // x must be either \"foo\", \"bar\", or \"baz\"\n  string x = 1 [(validate.rules).string = {in: [\"foo\", \"bar\", \"baz\"]}];\n\n  // x cannot be \"fizz\" nor \"buzz\"\n  string x = 1 [(validate.rules).string = {not_in: [\"fizz\", \"buzz\"]}];\n  ```\n\n- **ignore_empty**: this rule specifies that if field is empty or set to the\n  default value, to ignore any validation rules. These are typically useful\n  where being able to unset a field in an update request, or to skip validation\n  for optional fields where switching to WKTs is not feasible.\n\n  ```protobuf\n  string CountryCode = 1 [(validate.rules).string = {ignore_empty: true, len: 2}];\n  ```\n\n- **well-known formats**: these rules provide advanced constraints for common\n  string patterns. These constraints will typically be more permissive and\n  performant than equivalent regular expression patterns, while providing more\n  explanatory failure descriptions.\n\n  ```protobuf\n  // x must be a valid email address (via RFC 5322)\n  string x = 1 [(validate.rules).string.email = true];\n\n  // x must be a valid address (IP or Hostname).\n  string x = 1 [(validate.rules).string.address = true];\n\n  // x must be a valid hostname (via RFC 1034)\n  string x = 1 [(validate.rules).string.hostname = true];\n\n  // x must be a valid IP address (either v4 or v6)\n  string x = 1 [(validate.rules).string.ip = true];\n\n  // x must be a valid IPv4 address\n  // eg: \"192.168.0.1\"\n  string x = 1 [(validate.rules).string.ipv4 = true];\n\n  // x must be a valid IPv6 address\n  // eg: \"fe80::3\"\n  string x = 1 [(validate.rules).string.ipv6 = true];\n\n  // x must be a valid absolute URI (via RFC 3986)\n  string x = 1 [(validate.rules).string.uri = true];\n\n  // x must be a valid URI reference (either absolute or relative)\n  string x = 1 [(validate.rules).string.uri_ref = true];\n\n  // x must be a valid UUID (via RFC 4122)\n  string x = 1 [(validate.rules).string.uuid = true];\n\n  // x must conform to a well known regex for HTTP header names (via RFC 7230)\n  string x = 1 [(validate.rules).string.well_known_regex = HTTP_HEADER_NAME]\n\n  // x must conform to a well known regex for HTTP header values (via RFC 7230)\n  string x = 1 [(validate.rules).string.well_known_regex = HTTP_HEADER_VALUE];\n\n  // x must conform to a well known regex for headers, disallowing \\r\\n\\0 characters.\n  string x = 1 [(validate.rules).string {well_known_regex: HTTP_HEADER_VALUE, strict: false}];\n  ```\n\n### Bytes\n\n\u003e Literal values should be expressed with strings, using escaping where\n\u003e necessary.\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must be set to \"foo\" (\"\\x66\\x6f\\x6f\")\n  bytes x = 1 [(validate.rules).bytes.const = \"foo\"];\n\n  // x must be set to \"\\xf0\\x90\\x28\\xbc\"\n  bytes x = 1 [(validate.rules).bytes.const = \"\\xf0\\x90\\x28\\xbc\"];\n  ```\n\n- **len/min_len/max_len**: these rules constrain the number of bytes in the\n  field.\n\n  ```protobuf\n  // x must be exactly 3 bytes\n  bytes x = 1 [(validate.rules).bytes.len = 3];\n\n  // x must be at least 3 bytes long\n  bytes x = 1 [(validate.rules).bytes.min_len = 3];\n\n  // x must be between 5 and 10 bytes, inclusive\n  bytes x = 1 [(validate.rules).bytes = {min_len: 5, max_len: 10}];\n  ```\n\n- **pattern**: the field must match the specified [RE2-compliant][re2] regular\n  expression. The included expression should elide any delimiters (ie, `/\\d+/`\n  should just be `\\d+`).\n\n  ```protobuf\n  // x must be a non-empty, ASCII byte sequence\n  bytes x = 1 [(validate.rules).bytes.pattern = \"^[\\x00-\\x7F]+$\"];\n  ```\n\n- **prefix/suffix/contains**: the field must contain the specified byte sequence\n  in an optionally explicit location.\n\n  ```protobuf\n  // x must begin with \"\\x99\"\n  bytes x = 1 [(validate.rules).bytes.prefix = \"\\x99\"];\n\n  // x must end with \"buz\\x7a\"\n  bytes x = 1 [(validate.rules).bytes.suffix = \"buz\\x7a\"];\n\n  // x must contain \"baz\" anywhere inside it\n  bytes x = 1 [(validate.rules).bytes.contains = \"baz\"];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for the\n  values of a field.\n\n  ```protobuf\n  // x must be either \"foo\", \"bar\", or \"baz\"\n  bytes x = 1 [(validate.rules).bytes = {in: [\"foo\", \"bar\", \"baz\"]}];\n\n  // x cannot be \"fizz\" nor \"buzz\"\n  bytes x = 1 [(validate.rules).bytes = {not_in: [\"fizz\", \"buzz\"]}];\n  ```\n\n- **ignore_empty**: this rule specifies that if field is empty or set to the\n  default value, to ignore any validation rules. These are typically useful\n  where being able to unset a field in an update request, or to skip validation\n  for optional fields where switching to WKTs is not feasible.\n\n  ```protobuf\n  bytes x = 1 [(validate.rules).bytes = {ignore_empty: true, in: [\"foo\", \"bar\", \"baz\"]}];\n  ```\n\n- **well-known formats**: these rules provide advanced constraints for common\n  patterns. These constraints will typically be more permissive and performant\n  than equivalent regular expression patterns, while providing more explanatory\n  failure descriptions.\n\n  ```protobuf\n  // x must be a valid IP address (either v4 or v6) in byte format\n  bytes x = 1 [(validate.rules).bytes.ip = true];\n\n  // x must be a valid IPv4 address in byte format\n  // eg: \"\\xC0\\xA8\\x00\\x01\"\n  bytes x = 1 [(validate.rules).bytes.ipv4 = true];\n\n  // x must be a valid IPv6 address in byte format\n  // eg: \"\\x20\\x01\\x0D\\xB8\\x85\\xA3\\x00\\x00\\x00\\x00\\x8A\\x2E\\x03\\x70\\x73\\x34\"\n  bytes x = 1 [(validate.rules).bytes.ipv6 = true];\n  ```\n\n### Enums\n\n\u003e All literal values should use the numeric (int32) value as defined in the enum\n\u003e descriptor.\n\nThe following examples use this `State` enum\n\n```protobuf\nenum State {\n  INACTIVE = 0;\n  PENDING = 1;\n  ACTIVE = 2;\n}\n```\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must be set to ACTIVE (2)\n  State x = 1 [(validate.rules).enum.const = 2];\n  ```\n\n- **defined_only**: the field must be one of the specified values in the enum\n  descriptor.\n\n  ```protobuf\n  // x can only be INACTIVE, PENDING, or ACTIVE\n  State x = 1 [(validate.rules).enum.defined_only = true];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for the\n  values of a field.\n\n  ```protobuf\n  // x must be either INACTIVE (0) or ACTIVE (2)\n  State x = 1 [(validate.rules).enum = {in: [0,2]}];\n\n  // x cannot be PENDING (1)\n  State x = 1 [(validate.rules).enum = {not_in: [1]}];\n  ```\n\n### Messages\n\n\u003e If a field contains a message and the message has been generated with PGV,\n\u003e validation will be performed recursively. Message's not generated with PGV are\n\u003e skipped.\n\n```protobuf\n// if Person was generated with PGV and x is set,\n// x's fields will be validated.\n    Person x = 1;\n```\n\n- **skip**: this rule specifies that the validation rules of this field should\n  not be evaluated.\n\n  ```protobuf\n  // The fields on Person x will not be validated.\n  Person x = 1 [(validate.rules).message.skip = true];\n  ```\n\n- **required**: this rule specifies that the field cannot be unset.\n\n  ```protobuf\n  // x cannot be unset\n  Person x = 1 [(validate.rules).message.required = true];\n\n  // x cannot be unset, but the validations on x will not be performed\n  Person x = 1 [(validate.rules).message = {required: true, skip: true}];\n  ```\n\n### Repeated\n\n- **min_items/max_items**: these rules control how many elements are contained\n  in the field\n\n  ```protobuf\n  // x must contain at least 3 elements\n  repeated int32 x = 1 [(validate.rules).repeated.min_items = 3];\n\n  // x must contain between 5 and 10 Persons, inclusive\n  repeated Person x = 1 [(validate.rules).repeated = {min_items: 5, max_items: 10}];\n\n  // x must contain exactly 7 elements\n  repeated double x = 1 [(validate.rules).repeated = {min_items: 7, max_items: 7}];\n  ```\n\n- **unique**: this rule requires that all elements in the field must be unique.\n  This rule does not support repeated messages.\n\n  ```protobuf\n  // x must contain unique int64 values\n  repeated int64 x = 1 [(validate.rules).repeated.unique = true];\n  ```\n\n- **items**: this rule specifies constraints that should be applied to each\n  element in the field. Repeated message fields also have their validation rules\n  applied unless `skip` is specified on this constraint.\n\n  ```protobuf\n  // x must contain positive float values\n  repeated float x = 1 [(validate.rules).repeated.items.float.gt = 0];\n\n  // x must contain Persons but don't validate them\n  repeated Person x = 1 [(validate.rules).repeated.items.message.skip = true];\n  ```\n\n- **ignore_empty**: this rule specifies that if field is empty or set to the\n  default value, to ignore any validation rules. These are typically useful\n  where being able to unset a field in an update request, or to skip validation\n  for optional fields where switching to WKTs is not feasible.\n\n  ```protobuf\n  repeated int64 x = 1 [(validate.rules).repeated = {ignore_empty: true, items: {int64: {gt: 200}}}];\n  ```\n\n### Maps\n\n- **min_pairs/max_pairs**: these rules control how many KV pairs are contained\n  in this field\n\n  ```protobuf\n  // x must contain at least 3 KV pairs\n  map\u003cstring, uint64\u003e x = 1 [(validate.rules).map.min_pairs = 3];\n\n  // x must contain between 5 and 10 KV pairs\n  map\u003cstring, string\u003e x = 1 [(validate.rules).map = {min_pairs: 5, max_pairs: 10}];\n\n  // x must contain exactly 7 KV pairs\n  map\u003cstring, Person\u003e x = 1 [(validate.rules).map = {min_pairs: 7, max_pairs: 7}];\n  ```\n\n- **no_sparse**: for map fields with message values, setting this rule to true\n  disallows keys with unset values.\n\n  ```protobuf\n  // all values in x must be set\n  map\u003cuint64, Person\u003e x = 1 [(validate.rules).map.no_sparse = true];\n  ```\n\n- **keys**: this rule specifies constraints that are applied to the keys in the\n  field.\n\n  ```protobuf\n  // x's keys must all be negative\n  \u003csint32, string\u003e x = [(validate.rules).map.keys.sint32.lt = 0];\n  ```\n\n- **values**: this rule specifies constraints that are be applied to each value\n  in the field. Repeated message fields also have their validation rules applied\n  unless `skip` is specified on this constraint.\n\n  ```protobuf\n  // x must contain strings of at least 3 characters\n  map\u003cstring, string\u003e x = 1 [(validate.rules).map.values.string.min_len = 3];\n\n  // x must contain Persons but doesn't validate them\n  map\u003cstring, Person\u003e x = 1 [(validate.rules).map.values.message.skip = true];\n  ```\n\n- **ignore_empty**: this rule specifies that if field is empty or set to the\n  default value, to ignore any validation rules. These are typically useful\n  where being able to unset a field in an update request, or to skip validation\n  for optional fields where switching to WKTs is not feasible.\n\n  ```protobuf\n  map\u003cstring, string\u003e x = 1 [(validate.rules).map = {ignore_empty: true, values: {string: {min_len: 3}}}];\n  ```\n\n### Well-Known Types (WKTs)\n\nA set of [WKTs][wkts] are packaged with protoc and common message patterns\nuseful in many domains.\n\n#### Scalar Value Wrappers\n\nIn the `proto3` syntax, there is no way of distinguishing between unset and the\nzero value of a scalar field. The value WKTs permit this differentiation by\nwrapping them in a message. PGV permits using the same scalar rules that the\nwrapper encapsulates.\n\n```protobuf\n// if it is set, x must be greater than 3\n    google.protobuf.Int32Value x = 1 [(validate.rules).int32.gt = 3];\n```\n\nMessage Rules can also be used with scalar Well-Known Types (WKTs):\n\n```protobuf\n// Ensures that if a value is not set for age, it would not pass the validation despite its zero value being 0.\nmessage X {google.protobuf.Int32Value age = 1 [(validate.rules).int32.gt = -1, (validate.rules).message.required = true];}\n```\n\n#### Anys\n\n- **required**: this rule specifies that the field must be set\n\n  ```protobuf\n  // x cannot be unset\n  google.protobuf.Any x = 1 [(validate.rules).any.required = true];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for\n  the `type_url` value in this field. Consider using a `oneof` union instead\n  of `in` if possible.\n\n  ```protobuf\n  // x must not be the Duration or Timestamp WKT\n  google.protobuf.Any x = 1 [(validate.rules).any = {not_in: [\n      \"type.googleapis.com/google.protobuf.Duration\",\n      \"type.googleapis.com/google.protobuf.Timestamp\"\n    ]}];\n  ```\n\n#### Durations\n\n- **required**: this rule specifies that the field must be set\n\n  ```protobuf\n  // x cannot be unset\n  google.protobuf.Duration x = 1 [(validate.rules).duration.required = true];\n  ```\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must equal 1.5s exactly\n  google.protobuf.Duration x = 1 [(validate.rules).duration.const = {\n      seconds: 1,\n      nanos:   500000000\n    }];\n  ```\n\n- **lt/lte/gt/gte**: these inequalities (`\u003c`, `\u003c=`, `\u003e`, `\u003e=`, respectively)\n  allow for deriving ranges in which the field must reside.\n\n  ```protobuf\n  // x must be less than 10s\n  google.protobuf.Duration x = 1 [(validate.rules).duration.lt.seconds = 10];\n\n  // x must be greater than or equal to 20ns\n  google.protobuf.Duration x = 1 [(validate.rules).duration.gte.nanos = 20];\n\n  // x must be in the range [0s, 1s)\n  google.protobuf.Duration x = 1 [(validate.rules).duration = {\n      gte: {},\n      lt:  {seconds: 1}\n    }];\n  ```\n\n  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive\n  range.\n\n  ```protobuf\n  // x must be outside the range [0s, 1s)\n  google.protobuf.Duration x = 1 [(validate.rules).duration = {\n      lt:  {},\n      gte: {seconds: 1}\n    }];\n  ```\n\n- **in/not_in**: these two rules permit specifying allow/denylists for the\n  values of a field.\n\n  ```protobuf\n  // x must be either 0s or 1s\n  google.protobuf.Duration x = 1 [(validate.rules).duration = {in: [\n      {},\n      {seconds: 1}\n    ]}];\n\n  // x cannot be 20s nor 500ns\n  google.protobuf.Duration x = 1 [(validate.rules).duration = {not_in: [\n      {seconds: 20},\n      {nanos: 500}\n    ]}];\n  ```\n\n#### Timestamps\n\n- **required**: this rule specifies that the field must be set\n\n  ```protobuf\n  // x cannot be unset\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.required = true];\n  ```\n\n- **const**: the field must be _exactly_ the specified value.\n\n  ```protobuf\n  // x must equal 2009/11/10T23:00:00.500Z exactly\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.const = {\n      seconds: 63393490800,\n      nanos:   500000000\n    }];\n  ```\n\n- **lt/lte/gt/gte**: these inequalities (`\u003c`, `\u003c=`, `\u003e`, `\u003e=`, respectively)\n  allow for deriving ranges in which the field must reside.\n\n  ```protobuf\n  // x must be less than the Unix Epoch\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.lt.seconds = 0];\n\n  // x must be greater than or equal to 2009/11/10T23:00:00Z\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.gte.seconds = 63393490800];\n\n  // x must be in the range [epoch, 2009/11/10T23:00:00Z)\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = {\n      gte: {},\n      lt:  {seconds: 63393490800}\n    }];\n  ```\n\n  Inverting the values of `lt(e)` and `gt(e)` is valid and creates an exclusive\n  range.\n\n  ```protobuf\n  // x must be outside the range [epoch, 2009/11/10T23:00:00Z)\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = {\n      lt:  {},\n      gte: {seconds: 63393490800}\n    }];\n  ```\n\n- **lt_now/gt_now**: these inequalities allow for ranges relative to the current\n  time. These rules cannot be used with the absolute rules above.\n\n  ```protobuf\n  // x must be less than the current timestamp\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.lt_now = true];\n  ```\n- **within**: this rule specifies that the field's value should be within a\n  duration of the current time. This rule can be used in conjunction\n  with `lt_now` and `gt_now` to control those ranges.\n\n  ```protobuf\n  // x must be within ±1s of the current time\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp.within.seconds = 1];\n\n  // x must be within the range (now, now+1h)\n  google.protobuf.Timestamp x = 1 [(validate.rules).timestamp = {\n      gt_now: true,\n      within: {seconds: 3600}\n    }];\n  ```\n\n### Message-Global\n\n- **disabled**: All validation rules for the fields on a message can be\n  nullified, including any message fields that support validation themselves.\n\n  ```protobuf\n  message Person {\n    option (validate.disabled) = true;\n\n    // x will not be required to be greater than 123\n    uint64 x = 1 [(validate.rules).uint64.gt = 123];\n\n    // y's fields will not be validated\n    Person y = 2;\n  }\n  ```\n\n- **ignored**: Don't generate a validate method or any related validation code\n  for this message.\n\n  ```protobuf\n  message Person {\n    option (validate.ignored) = true;\n\n    // x will not be required to be greater than 123\n    uint64 x = 1 [(validate.rules).uint64.gt = 123];\n\n    // y's fields will not be validated\n    Person y = 2;\n  }\n  ```\n\n### OneOfs\n\n- **required**: require that one of the fields in a `oneof` must be set. By\n  default, none or one of the unioned fields can be set. Enabling this rules\n  disallows having all of them unset.\n\n  ```protobuf\n  oneof id {\n    // either x, y, or z must be set.\n    option (validate.required) = true;\n\n    string x = 1;\n    int32  y = 2;\n    Person z = 3;\n  }\n  ```\n\n## Development\n\nPGV is written in Go on top of the [protoc-gen-star][pg*] framework and compiles\nto a standalone binary.\n\n### Dependencies\n\nAll PGV dependencies are currently checked into the project. To test\nPGV, `protoc` must be installed, either from [source][protoc-source], the\nprovided [releases][protoc-releases], or a package manager. The official protoc\nplugin for the target language(s) should be installed as well.\n\n### Make Targets\n\n- **`make build`**: generates the constraints proto and compiles PGV\n  into `$GOPATH/bin`\n\n- **`make lint`**: runs static-analysis rules against the PGV codebase,\n  including `golint`, `go vet`, and `gofmt -s`\n\n- **`make testcases`**: generates the proto files\n  in [`/tests/harness/cases`](/tests/harness/cases). These are used by the test\n  harness to verify the validation rules generated for each language.\n\n- **`make harness`**: executes the test-cases against each language's test\n  harness.\n\n### Run all tests under Bazel\n\nEnsure that your `PATH` is setup to include `protoc-gen-go` and `protoc`, then:\n\n```\nbazel test //tests/...\n```\n\n### Docker\n\nPGV comes with a [Dockerfile](/Dockerfile) for consistent development tooling\nand CI. The main entrypoint is `make` with `build` as the default target.\n\n```sh\n# build the image\ndocker build -t bufbuild/protoc-gen-validate .\n\n# executes the default make target: build\ndocker run --rm \\\n  bufbuild/protoc-gen-validate\n\n# executes the 'ci' make target\ndocker run --rm \\\n  bufbuild/protoc-gen-validate ci\n\n# executes the 'build' \u0026 'testcases' make targets\ndocker run --rm \\\n  bufbuild/protoc-gen-validate build testcases\n\n# override the entrypoint and interact with the container directly\n# this can be useful when wanting to run bazel commands without\n# bazel installed locally.\ndocker run --rm \\\n -it --entrypoint=/bin/bash \\\n bufbuild/protoc-gen-validate\n```\n\n[buf]:             https://buf.build\n[protoc-source]:   https://github.com/google/protobuf\n[protoc-releases]: https://github.com/google/protobuf/releases\n[pg*]:             https://github.com/bufbuild/protoc-gen-star\n[re2]:             https://github.com/google/re2/wiki/Syntax\n[wkts]:            https://developers.google.com/protocol-buffers/docs/reference/google.protobuf\n[pv]:              https://github.com/bufbuild/protovalidate\n[pv-announce]:     https://buf.build/blog/protoc-gen-validate-v1-and-v2/\n[migration-guide]: https://buf.build/docs/migration-guides/migrate-from-protoc-gen-validate/\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbufbuild%2Fprotoc-gen-validate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbufbuild%2Fprotoc-gen-validate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbufbuild%2Fprotoc-gen-validate/lists"}