https://github.com/mathematic-inc/protovalidate-buffa
Static-codegen protovalidate for the buffa Rust protobuf runtime
https://github.com/mathematic-inc/protovalidate-buffa
Last synced: 10 days ago
JSON representation
Static-codegen protovalidate for the buffa Rust protobuf runtime
- Host: GitHub
- URL: https://github.com/mathematic-inc/protovalidate-buffa
- Owner: mathematic-inc
- License: apache-2.0
- Created: 2026-04-21T12:22:03.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-05-14T23:27:24.000Z (20 days ago)
- Last Synced: 2026-05-15T01:30:42.639Z (20 days ago)
- Language: Rust
- Size: 446 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# protovalidate-buffa
Static-codegen [protovalidate] for the [buffa] Rust protobuf runtime.
Annotate your `.proto` messages with `(buf.validate.*)` rules; a codegen plugin emits pure-Rust `impl Validate` blocks per message. Handlers call `req.validate()?` at entry (or use the `#[connect_impl]` macro to do it automatically on every handler in a service impl).
For what the rules *mean*, the full rule catalogue, CEL semantics, and design docs, read the upstream project — this crate intentionally does not duplicate that material:
- **Docs:**
- **Rule catalogue:**
- **Custom / predefined rules:**
- **Source of truth (`validate.proto`):**
[protovalidate]: https://github.com/bufbuild/protovalidate
[buffa]: https://github.com/anthropics/buffa
## Status
**Conformance: 2872 / 2872 (100%)** against the upstream [`protovalidate-conformance`](https://github.com/bufbuild/protovalidate/tree/main/tools/protovalidate-conformance) harness, covering proto2, proto3, and editions 2023.
## Why a different crate?
Existing Rust implementations of protovalidate (`prost-protovalidate`, `protocheck`, `protify`) all target [prost]. buffa has a different runtime model — zero-copy views, static types, no dynamic-message reflection — so prost-based validators are incompatible. This repo fills that gap.
Compared to reflection-based implementations, the codegen approach has two characteristics:
- **No runtime descriptor lookup.** Every `validate()` is a direct struct field walk that LLVM can inline.
- **Schema-aware compile errors.** Rule / field type mismatches, malformed `message.oneof` specs, and CEL expressions that reference non-existent fields are surfaced at codegen time rather than at first-call.
[prost]: https://github.com/tokio-rs/prost
## Crates
| Crate | Purpose |
|-------|---------|
| [`protovalidate-buffa`](crates/protovalidate-buffa/) | Runtime library: `Validate` trait, structured `ValidationError` (with typed `compile_error` / `runtime_error` slots), `Violation` / `FieldPath`, rule helpers, `CelScalar` widening trait + Duration/Timestamp helpers, Connect error adapter. CEL rules are transpiled to native Rust at codegen time, so the runtime carries no interpreter. |
| [`protovalidate-buffa-macros`](crates/protovalidate-buffa-macros/) | `#[connect_impl]` attribute macro — inserts `req.validate()?` at the top of every handler in a service `impl` block. Re-exported from the runtime crate. |
| [`protoc-gen-protovalidate-buffa`](crates/protoc-gen-protovalidate-buffa/) | Codegen plugin. Reads `(buf.validate.*)` extensions off descriptors via buffa's `ExtensionSet`, emits `impl Validate for Foo` blocks. Wire into `buf.gen.yaml`. |
| [`protovalidate-buffa-protos`](crates/protovalidate-buffa-protos/) | Compiled Rust for `buf/validate/validate.proto` (vendored under `proto/`). Consumed by the codegen plugin. |
`protovalidate-buffa-conformance` also lives in this workspace but is private (`publish = false`) — see [its README](crates/protovalidate-buffa-conformance/README.md) for the conformance test-run flow.
## Supported rules
Every rule family in the upstream [standard-rules catalogue](https://buf.build/docs/protovalidate/schemas/standard-rules/) plus [predefined rules](https://buf.build/docs/protovalidate/schemas/custom-rules/#predefined-rules) is implemented — that's what the 2872 / 2872 conformance number above is measuring. See the upstream docs for semantics; this repo doesn't maintain a parallel list.
## Quick start
For the proto-annotation side (which rules exist, how to combine them, CEL syntax), follow the upstream [protovalidate quick start](https://buf.build/docs/protovalidate/quickstart/). The Rust-specific bits are:
```bash
# Install the plugin
cargo install --git https://github.com/mathematic-inc/protovalidate-buffa protoc-gen-protovalidate-buffa
```
Add to your `buf.gen.yaml`:
```yaml
- local: protoc-gen-protovalidate-buffa
out: gen/protovalidate
strategy: all
```
Annotate a proto (see upstream for the full rule vocabulary):
```protobuf
syntax = "proto3";
import "buf/validate/validate.proto";
message CreateUserRequest {
string email = 1 [(buf.validate.field).string = { min_len: 5, max_len: 254, email: true }];
int32 age = 3 [(buf.validate.field).int32 = { gte: 13, lte: 150 }];
}
```
Use in a Connect handler:
```rust
use protovalidate_buffa::Validate;
#[protovalidate_buffa::connect_impl]
impl UserService for UserServiceImpl {
async fn create_user(
&self,
ctx: Context,
request: OwnedView>,
) -> Result<(pb::CreateUserResponse, Context), ConnectError> {
// #[connect_impl] inserts req.validate()? here automatically.
// Body only sees already-validated requests.
}
}
```
## Error model
`Validate::validate` returns `Result<(), ValidationError>`:
```rust
pub struct ValidationError {
pub violations: Vec,
pub compile_error: Option, // schema mismatch detected at codegen time
pub runtime_error: Option, // rule precondition failed (e.g. non-UTF-8 bytes under `pattern`)
}
```
Match on the typed fields rather than stringly-typed rule-id prefixes. `Violation` / `FieldPath` mirror the [upstream proto shape](https://github.com/bufbuild/protovalidate/blob/main/proto/protovalidate/buf/validate/validate.proto) — see those message definitions for field semantics. The `connect` feature provides `ValidationError::into_connect_error` mapping to `InvalidArgument`.
## Conformance testing
See [`crates/protovalidate-buffa-conformance/README.md`](crates/protovalidate-buffa-conformance/README.md) for how to build the dispatch binary and drive the upstream harness locally. CI runs `cargo clippy --workspace --all-targets -- -D warnings` and `cargo test --workspace` on every push; conformance is currently a local-only / pre-release check.
## License
Dual-licensed under Apache-2.0 or MIT at your option.