|
17 | 17 | #include "source/common/runtime/runtime_features.h" |
18 | 18 |
|
19 | 19 | #include "absl/strings/match.h" |
| 20 | +#include "buf/validate/validator.h" |
20 | 21 | #include "udpa/annotations/sensitive.pb.h" |
21 | 22 | #include "udpa/annotations/status.pb.h" |
22 | | -#include "validate/validate.h" |
23 | 23 | #include "xds/annotations/v3/status.pb.h" |
24 | 24 |
|
25 | 25 | using namespace std::chrono_literals; |
@@ -364,32 +364,55 @@ void MessageUtil::validateDurationFields(const Protobuf::Message& message, bool |
364 | 364 |
|
365 | 365 | namespace { |
366 | 366 |
|
367 | | -class PgvCheckVisitor : public ProtobufMessage::ConstProtoVisitor { |
| 367 | +class ProtovalidateCheckVisitor : public ProtobufMessage::ConstProtoVisitor { |
368 | 368 | public: |
| 369 | + ProtovalidateCheckVisitor() { |
| 370 | + // Initialize the validator factory once |
| 371 | + auto factory_result = buf::validate::ValidatorFactory::New(); |
| 372 | + if (!factory_result.ok()) { |
| 373 | + PANIC(fmt::format("Failed to create protovalidate ValidatorFactory: {}", |
| 374 | + factory_result.status().ToString())); |
| 375 | + } |
| 376 | + factory_ = std::move(factory_result.value()); |
| 377 | + } |
| 378 | + |
369 | 379 | absl::Status onMessage(const Protobuf::Message& message, |
370 | 380 | absl::Span<const Protobuf::Message* const>, |
371 | 381 | bool was_any_or_top_level) override { |
372 | | - Protobuf::ReflectableMessage reflectable_message = createReflectableMessage(message); |
373 | | - std::string err; |
374 | | - // PGV verification is itself recursive up to the point at which it hits an Any message. As |
375 | | - // such, to avoid N^2 checking of the tree, we only perform an additional check at the point |
376 | | - // at which PGV would have stopped because it does not itself check within Any messages. |
377 | | - if (was_any_or_top_level && |
378 | | - !pgv::BaseValidator::AbstractCheckMessage(*reflectable_message, &err)) { |
379 | | - std::string error = fmt::format("{}: Proto constraint validation failed ({})", |
380 | | - reflectable_message->DebugString(), err); |
381 | | - return absl::InvalidArgumentError(error); |
| 382 | + // Protovalidate validation is recursive, similar to PGV. We only perform an additional |
| 383 | + // check at the top level or when encountering Any messages to avoid N^2 checking. |
| 384 | + if (was_any_or_top_level) { |
| 385 | + google::protobuf::Arena arena; |
| 386 | + auto validator = factory_->NewValidator(&arena, false); |
| 387 | + auto result = validator.Validate(message); |
| 388 | + if (!result.ok()) { |
| 389 | + return absl::InvalidArgumentError( |
| 390 | + fmt::format("Proto constraint validation failed: {}", result.status().ToString())); |
| 391 | + } |
| 392 | + const auto& violations = result.value(); |
| 393 | + if (violations.violations_size() > 0) { |
| 394 | + std::string error_msg = "Proto constraint validation failed:"; |
| 395 | + for (int i = 0; i < violations.violations_size(); ++i) { |
| 396 | + const auto& violation = violations.violations(i); |
| 397 | + error_msg += fmt::format("\n - Field '{}': {}", violation.field_path(), |
| 398 | + violation.message()); |
| 399 | + } |
| 400 | + return absl::InvalidArgumentError(error_msg); |
| 401 | + } |
382 | 402 | } |
383 | 403 | return absl::OkStatus(); |
384 | 404 | } |
385 | 405 |
|
386 | 406 | void onField(const Protobuf::Message&, const Protobuf::FieldDescriptor&) override {} |
| 407 | + |
| 408 | +private: |
| 409 | + std::unique_ptr<buf::validate::ValidatorFactory> factory_; |
387 | 410 | }; |
388 | 411 |
|
389 | 412 | } // namespace |
390 | 413 |
|
391 | 414 | void MessageUtil::recursivePgvCheck(const Protobuf::Message& message) { |
392 | | - PgvCheckVisitor visitor; |
| 415 | + ProtovalidateCheckVisitor visitor; |
393 | 416 | THROW_IF_NOT_OK(ProtobufMessage::traverseMessage(visitor, message, true)); |
394 | 417 | } |
395 | 418 |
|
|
0 commit comments