Skip to content

Validate supported fields for xDS#6736

Merged
jrhee17 merged 7 commits intoline:mainfrom
jrhee17:feat/xds-support-3
May 4, 2026
Merged

Validate supported fields for xDS#6736
jrhee17 merged 7 commits intoline:mainfrom
jrhee17:feat/xds-support-3

Conversation

@jrhee17
Copy link
Copy Markdown
Contributor

@jrhee17 jrhee17 commented Apr 23, 2026

Motivation:

The (armeria.xds.supported) proto annotation was introduced in #6722 to detect unsupported xDS field usage, but the annotation was not yet applied to the proto field definitions. Additionally, XdsValidatorIndex.assertValid() accepted Object instead of the more type-safe Message, and a StrictXdsValidatorIndex (which collects all violations and throws a single exception) was missing for use in test environments.

Modifications:

  • Changed XdsValidatorIndex.assertValid(Object) to assertValid(Message) for type safety, and updated all call sites (XdsValidatorIndexRegistry, XdsResourceValidator, XdsExtensionRegistry, DefaultXdsValidatorIndex).
  • Added protobuf-java dependency to xds-validator module to support the Message parameter type.
  • Extracted pgv validation logic from DefaultXdsValidatorIndex into a dedicated PgvValidator class.
  • Refactored DefaultXdsValidatorIndex to compose PgvValidator and SupportedFieldValidator (with warn() handler).
  • Added StrictXdsValidatorIndex with priority 1 for test environments, which collects all unsupported field violations and reports them in a single IllegalArgumentException.
  • Annotated supported fields with (armeria.xds.supported) = true across all xDS proto files.

Result:

  • In production, DefaultXdsValidatorIndex logs warnings for unsupported xDS fields via SupportedFieldValidator.
  • In test environments (where StrictXdsValidatorIndex is on the classpath via SPI), unsupported field usage fails fast with a clear error listing all violations.
  • Proto field annotations serve as living documentation of which xDS fields Armeria actively supports.

@jrhee17 jrhee17 added this to the 1.39.0 milestone Apr 23, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Validator API now requires protobuf Messages; adds PGV-based validator and a SPI-registered StrictXdsValidatorIndex that runs PGV then supported-field checks; replaces per-field boolean supported options with numeric message-level options and annotates many Envoy protos with the new armeria.xds.supported options.

Changes

Cohort / File(s) Summary
SPI & interface
it/xds-client/src/test/resources/META-INF/services/com.linecorp.armeria.xds.validator.XdsValidatorIndex, xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidatorIndex.java, xds/src/main/java/com/linecorp/armeria/xds/XdsValidatorIndexRegistry.java, it/xds-no-validation/src/test/java/com/linecorp/armeria/xds/it/NoopXdsValidatorIndex.java
Register StrictXdsValidatorIndex in test resources; change XdsValidatorIndex.assertValid and registry to accept com.google.protobuf.Message; update test Noop implementation signature.
Validator implementations & flow
xds-api/src/main/java/com/linecorp/armeria/xds/api/DefaultXdsValidatorIndex.java, xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java, xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java, xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java, xds-api/src/main/java/com/linecorp/armeria/xds/api/UnsupportedFieldHandler.java
Add PgvValidator; introduce StrictXdsValidatorIndex (priority=1) that runs PGV then supported-field checks and aggregates violations; adapt DefaultXdsValidatorIndex to protobuf-typed assert; change unsupported handling to throw XdsValidationException.
Exception type & tests
xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java, xds/src/test/java/com/linecorp/armeria/xds/XdsValidatorIndexRegistryTest.java, it/xds-client/src/test/java/.../ErrorHandlingTest.java, xds-api/src/test/java/.../SupportedFieldValidatorTest.java
Introduce XdsValidationException runtime type and update tests to expect it where validation failures occur.
Supported option schema & test protos
xds-api/src/main/proto/armeria/xds/supported.proto, xds-api/src/test/proto/armeria/xds/testing/test_supported.proto
Replace per-field boolean/enum options with message supported containing repeated int32 extensions: field, oneof_field, enum_value; update test protos to use numeric options placed before fields/enum values.
Envoy proto annotations (many files)
xds-api/src/main/proto/.../envoy/** (e.g., config/*, cluster/*, core/*, endpoint/*, listener/*, route/*, extensions/.../http_connection_manager/*, extensions/transport_sockets/tls/*, type/*, etc.)
Import armeria/xds/supported.proto and add `option (armeria.xds.supported.field
Build / dependency
xds-validator/build.gradle
Add protobuf-java as an api dependency to the xds-validator module.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant StrictIndex as StrictXdsValidatorIndex
    participant PGV as PgvValidator
    participant Supported as SupportedFieldValidator
    participant Msg as "protobuf Message"

    Client->>StrictIndex: assertValid(Msg)
    StrictIndex->>PGV: assertValid(Msg)
    PGV->>PGV: run PGV structural validation
    alt PGV fails
        PGV-->>StrictIndex: throws XdsValidationException
        StrictIndex-->>Client: propagate XdsValidationException
    else PGV passes
        PGV-->>StrictIndex: success
        StrictIndex->>Supported: validate(Msg, collector)
        Supported->>Supported: read supported.field/oneof/enum lists
        Supported->>Supported: collect unsupported items
        alt violations found
            Supported-->>StrictIndex: violations list
            StrictIndex-->>Client: throw XdsValidationException(aggregated)
        else no violations
            StrictIndex-->>Client: validation success
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

breaking change

Suggested reviewers

  • trustin
  • ikhoon
  • minwoox

Poem

🐰 I hop through protos, digits mark the way,
PGV inspects structure, strict checks have their say.
I gather every unsupported field like a prize,
Bundle them into a message — tidy carrot-sized.
Hooray — validation done, I twitch my nose and play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Validate supported fields for xDS' directly describes the main objective of the PR: applying the (armeria.xds.supported) proto annotations and implementing strict validation for xDS supported fields.
Description check ✅ Passed The description provides comprehensive coverage of the PR's motivation, modifications, and expected results, clearly explaining the changes to XdsValidatorIndex, the new PgvValidator and StrictXdsValidatorIndex classes, and the field annotations across proto files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jrhee17 jrhee17 changed the title impl Validate supported fields for xDS Apr 23, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java (1)

150-171: ⚠️ Potential issue | 🟠 Major

Unannotated envoy/xds enums will be treated as entirely unsupported.

unsupportedEnumValue() returns true whenever the enum's supported.enum_value list does not contain the value's number. For any envoy/xds enum type that has not been annotated at all (empty list), every value — including the default 0 — will be flagged as unsupported, and validateFieldValue will invoke the handler for it.

Example: DnsLookupFamily in envoy/config/cluster/v3/cluster.proto has no (armeria.xds.supported.enum_value) annotations on any of its values, yet it is used in the supported field dns_lookup_family = 17. This will cause spurious warnings (or failures under StrictXdsValidatorIndex) for all enum values.

Consider treating "no supported.enum_value annotations on the enum" as "no opinion" (skip enum value validation) and only enforce when at least one value is annotated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java`
around lines 150 - 171, validateFieldValue is flagging every enum value as
unsupported when the enum has no supported.enum_value annotations because
unsupportedEnumValue returns true if the list does not contain the value; change
unsupportedEnumValue(EnumValueDescriptor ev) to treat an empty supported-values
list as "no opinion" by returning false when the retrieved List<Integer>
supportedValues is null or empty, and only perform contains-check when the list
has entries (use
ev.getType().getOptions().getExtension(SupportedFieldProto.supported.enumValue)
and check for null/empty before contains); this will ensure validateFieldValue
only invokes handler for enums where at least one enum_value is explicitly
annotated.
xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto (1)

216-223: ⚠️ Potential issue | 🟠 Major

Move (armeria.xds.supported.field) options to the message level.

The (armeria.xds.supported.field) options are message-level options but are currently placed between field documentation comments and field declarations. Protobuf tooling associates leading comments with the next declaration, so these comments no longer document the fields when options sit between them. Relocate all supported-field options to the top of each message, immediately after other message options.

Example refactor pattern
 message TlsCertificate {
   option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.TlsCertificate";
+  option (armeria.xds.supported.field) = 1;
+  option (armeria.xds.supported.field) = 2;
+  option (armeria.xds.supported.field) = 7;
+  option (armeria.xds.supported.field) = 3;
 
   // The TLS certificate chain.
   //
   // If ``certificate_chain`` is a filesystem path, a watch will be added to the
   // parent directory for any file moves to support rotation. This currently
   // only applies to dynamic secrets, when the ``TlsCertificate`` is delivered via
   // SDS.
-  option (armeria.xds.supported.field) = 1;
   config.core.v3.DataSource certificate_chain = 1;

Apply to all 13 occurrences across TlsCertificate, SubjectAltNameMatcher, and CertificateValidationContext messages.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto`
around lines 216 - 223, The (armeria.xds.supported.field) option is placed
between field comments and field declarations (e.g., before the
certificate_chain field), which breaks the association of leading comments with
the fields; move every occurrence of the (armeria.xds.supported.field) option
into the corresponding message header (immediately after other message-level
options) for the TlsCertificate, SubjectAltNameMatcher, and
CertificateValidationContext messages (all 13 occurrences) so the field
documentation remains attached to the fields.
🧹 Nitpick comments (3)
xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java (2)

49-55: Consider tightening parameter to Message for consistency.

The rest of this PR narrows validator APIs from Object to com.google.protobuf.Message. PgvValidator.assertValid still takes Object; since the only sensible input is a protobuf message (PGV's validatorFor will otherwise return a no-op/unsupported validator), tightening to Message would align with XdsValidatorIndex.assertValid(Message) and prevent accidental misuse.

Proposed change
-    public void assertValid(Object message) {
+    public void assertValid(com.google.protobuf.Message message) {
         try {
             delegate.validatorFor(message).assertValid(message);
         } catch (ValidationException e) {
             throw new IllegalArgumentException(e);
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java` around
lines 49 - 55, Change PgvValidator.assertValid to accept
com.google.protobuf.Message instead of Object: update the method signature of
PgvValidator.assertValid(Message message), adjust the call to
delegate.validatorFor(message) and subsequent validator invocation to use the
Message type, and keep the existing try/catch that converts ValidationException
into IllegalArgumentException; this aligns the API with
XdsValidatorIndex.assertValid(Message) and prevents passing non-protobuf objects
to delegate.validatorFor.

49-55: Preserve the original message in the thrown exception.

new IllegalArgumentException(e) uses only the cause; the resulting top-level message is io.envoyproxy.pgv.ValidationException: ..., which is noisier than needed and loses context about which xDS resource failed. Consider including pgv's message and (optionally) the descriptor name so the error is actionable in logs.

Proposed change
-        } catch (ValidationException e) {
-            throw new IllegalArgumentException(e);
-        }
+        } catch (ValidationException e) {
+            throw new IllegalArgumentException(
+                    "PGV validation failed for " + message.getClass().getName() + ": " + e.getMessage(), e);
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java` around
lines 49 - 55, The catch in PgvValidator.assertValid currently rethrows
ValidationException as new IllegalArgumentException(e) which loses a clear
top-level message; update the catch to build a descriptive message that includes
pgv's error text and the protobuf descriptor name for the failing resource, e.g.
retrieve the descriptor via ((com.google.protobuf.Message)
message).getDescriptorForType().getFullName() when message is a protobuf and
format a message like "Invalid xDS resource <DescriptorName>: <pgv message>"
then throw new IllegalArgumentException(formattedMessage, e) so the original
cause is preserved.
xds-api/src/main/proto/envoy/config/core/v3/base.proto (1)

407-434: Nit: inconsistent placement of supported-field option relative to doc comment.

For HeaderValue.key, the option (armeria.xds.supported.field) = 1; at line 410 is placed before the // Header name. comment, whereas for value the option at line 423 is placed after the doc comment. Placement has no semantic effect on protobuf, but keeping it consistently immediately above the field (after its doc comment) improves readability and matches the convention used elsewhere in this PR.

Proposed tweak
-  option (armeria.xds.supported.field) = 1;
-  // Header name.
-  string key = 1
+  // Header name.
+  option (armeria.xds.supported.field) = 1;
+  string key = 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds-api/src/main/proto/envoy/config/core/v3/base.proto` around lines 407 -
434, Move the option placement for HeaderValue.key so it sits immediately above
the field declaration and immediately below the `// Header name.` doc comment
(i.e., place `option (armeria.xds.supported.field) = 1;` after the comment and
just before `string key = 1 ...`) to match the placement used for `value` and
`raw_value` and keep `HeaderValue`'s field-option ordering consistent across the
message.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/DefaultXdsValidatorIndex.java`:
- Around line 44-45: Ensure DefaultXdsValidatorIndex.assertValid performs an
explicit null-check on the incoming Message before delegating to
pgvValidator.assertValid: use Objects.requireNonNull(message, "message") at the
start of assertValid in DefaultXdsValidatorIndex so the public API enforces the
null contract rather than relying on PgvValidator/SupportedFieldValidator to
catch it; keep the subsequent call to pgvValidator.assertValid(message).

In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java`:
- Around line 43-44: Add an explicit null-check at the public API boundary of
StrictXdsValidatorIndex.assertValid by calling Objects.requireNonNull(message,
...) before delegating to pgvValidator.assertValid; this ensures the method
enforces its contract and prevents null from being handled later by
PgvValidator/SupportedFieldValidator implementation details.

In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java`:
- Around line 39-51: The Javadoc incorrectly names and shows the option; update
the class-level Javadoc in SupportedFieldValidator to reference the correct
proto option `(armeria.xds.supported.field)` and adjust the example to show the
option used inside the message-body via the supported wrapper message as defined
in SupportedFieldProto.supported.field (i.e., demonstrate a message with option
(armeria.xds.supported.field) = { field: 1 };), and remove the mistaken
`(armeria.xds.supported_fields)` and the combined field/option example so the
docs match the actual SupportedFieldProto.supported.field extension and the
validator's behavior.

In `@xds-validator/build.gradle`:
- Line 2: The build uses implementation for protobuf but
XdsValidatorIndex#assertValid(Message) exposes com.google.protobuf.Message to
consumers; change the dependency for protobuf (currently referenced as
libs.protobuf.java in build.gradle) from implementation to api so downstream
projects compiling against the XdsValidatorIndex interface will have the
protobuf types on their compile classpath.

---

Outside diff comments:
In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java`:
- Around line 150-171: validateFieldValue is flagging every enum value as
unsupported when the enum has no supported.enum_value annotations because
unsupportedEnumValue returns true if the list does not contain the value; change
unsupportedEnumValue(EnumValueDescriptor ev) to treat an empty supported-values
list as "no opinion" by returning false when the retrieved List<Integer>
supportedValues is null or empty, and only perform contains-check when the list
has entries (use
ev.getType().getOptions().getExtension(SupportedFieldProto.supported.enumValue)
and check for null/empty before contains); this will ensure validateFieldValue
only invokes handler for enums where at least one enum_value is explicitly
annotated.

In
`@xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto`:
- Around line 216-223: The (armeria.xds.supported.field) option is placed
between field comments and field declarations (e.g., before the
certificate_chain field), which breaks the association of leading comments with
the fields; move every occurrence of the (armeria.xds.supported.field) option
into the corresponding message header (immediately after other message-level
options) for the TlsCertificate, SubjectAltNameMatcher, and
CertificateValidationContext messages (all 13 occurrences) so the field
documentation remains attached to the fields.

---

Nitpick comments:
In `@xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java`:
- Around line 49-55: Change PgvValidator.assertValid to accept
com.google.protobuf.Message instead of Object: update the method signature of
PgvValidator.assertValid(Message message), adjust the call to
delegate.validatorFor(message) and subsequent validator invocation to use the
Message type, and keep the existing try/catch that converts ValidationException
into IllegalArgumentException; this aligns the API with
XdsValidatorIndex.assertValid(Message) and prevents passing non-protobuf objects
to delegate.validatorFor.
- Around line 49-55: The catch in PgvValidator.assertValid currently rethrows
ValidationException as new IllegalArgumentException(e) which loses a clear
top-level message; update the catch to build a descriptive message that includes
pgv's error text and the protobuf descriptor name for the failing resource, e.g.
retrieve the descriptor via ((com.google.protobuf.Message)
message).getDescriptorForType().getFullName() when message is a protobuf and
format a message like "Invalid xDS resource <DescriptorName>: <pgv message>"
then throw new IllegalArgumentException(formattedMessage, e) so the original
cause is preserved.

In `@xds-api/src/main/proto/envoy/config/core/v3/base.proto`:
- Around line 407-434: Move the option placement for HeaderValue.key so it sits
immediately above the field declaration and immediately below the `// Header
name.` doc comment (i.e., place `option (armeria.xds.supported.field) = 1;`
after the comment and just before `string key = 1 ...`) to match the placement
used for `value` and `raw_value` and keep `HeaderValue`'s field-option ordering
consistent across the message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7d6b55ea-c25b-42b8-8684-d29110d2fa7f

📥 Commits

Reviewing files that changed from the base of the PR and between 4fd3666 and fe32d03.

📒 Files selected for processing (32)
  • it/xds-client/src/test/resources/META-INF/services/com.linecorp.armeria.xds.validator.XdsValidatorIndex
  • it/xds-no-validation/src/test/java/com/linecorp/armeria/xds/it/NoopXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/DefaultXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java
  • xds-api/src/main/proto/armeria/xds/supported.proto
  • xds-api/src/main/proto/envoy/config/bootstrap/v3/bootstrap.proto
  • xds-api/src/main/proto/envoy/config/cluster/v3/cluster.proto
  • xds-api/src/main/proto/envoy/config/core/v3/address.proto
  • xds-api/src/main/proto/envoy/config/core/v3/base.proto
  • xds-api/src/main/proto/envoy/config/core/v3/config_source.proto
  • xds-api/src/main/proto/envoy/config/core/v3/grpc_service.proto
  • xds-api/src/main/proto/envoy/config/core/v3/health_check.proto
  • xds-api/src/main/proto/envoy/config/endpoint/v3/endpoint.proto
  • xds-api/src/main/proto/envoy/config/endpoint/v3/endpoint_components.proto
  • xds-api/src/main/proto/envoy/config/listener/v3/api_listener.proto
  • xds-api/src/main/proto/envoy/config/listener/v3/listener.proto
  • xds-api/src/main/proto/envoy/config/route/v3/route.proto
  • xds-api/src/main/proto/envoy/config/route/v3/route_components.proto
  • xds-api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/common.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/secret.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto
  • xds-api/src/main/proto/envoy/type/matcher/v3/regex.proto
  • xds-api/src/main/proto/envoy/type/matcher/v3/string.proto
  • xds-api/src/main/proto/envoy/type/v3/percent.proto
  • xds-api/src/main/proto/envoy/type/v3/range.proto
  • xds-api/src/test/proto/armeria/xds/testing/test_supported.proto
  • xds-validator/build.gradle
  • xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidatorIndex.java
  • xds/src/main/java/com/linecorp/armeria/xds/XdsValidatorIndexRegistry.java

Comment thread xds-validator/build.gradle Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java (2)

44-57: Consider documenting the pgv-first short-circuit behavior.

When pgvValidator.assertValid(message) fails, any unsupported-field violations present in the same message are never collected or surfaced. For a strict/test validator whose value proposition is "report everything at once," it would be worth a short Javadoc note clarifying that structural PGV errors take precedence and short-circuit supported-field reporting. No functional change required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java`
around lines 44 - 57, Add Javadoc to the StrictXdsValidatorIndex.assertValid
method explaining that pgvValidator.assertValid(message) runs first and
short-circuits further supported-field validation: if PGV structural validation
fails, supported-field violations will not be collected or reported; mention
this is intentional for prioritizing structural errors and that no functional
changes are made. Reference the pgvValidator field and the
SupportedFieldValidator-based check in the doc comment so readers know which
checks run and in what order.

48-56: Minor: consider including the offending value / a stable ordering in the aggregated message.

The violations list uses descriptorName + ": " + fieldPath, dropping the value passed to the handler. For a test-mode validator, including a truncated value (or at least the type/oneof case) in the error message would make failures easier to diagnose when the same field path appears in multiple sub-messages. As-is, duplicates collapse visually into identical entries. Optional.

Illustrative tweak
-                SupportedFieldValidator.of((descriptorName, fieldPath, value) ->
-                        violations.add(descriptorName + ": " + fieldPath));
+                SupportedFieldValidator.of((descriptorName, fieldPath, value) ->
+                        violations.add(descriptorName + ": " + fieldPath +
+                                       (value != null ? " (=" + value + ')' : "")));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java`
around lines 48 - 56, The aggregated error message in StrictXdsValidatorIndex
collects only descriptorName and fieldPath into the violations list, making
duplicate entries hard to distinguish; update the SupportedFieldValidator
handler (the lambda passed to SupportedFieldValidator.of) to include a concise
representation of the offending value (e.g., value.getClass().getSimpleName() or
a truncated toString/first N chars) when adding to violations, and after
validator.validate(message) sort and deduplicate the violations list to produce
a stable, readable order before throwing the IllegalArgumentException that
currently contains "Unsupported xDS fields detected: " + String.join(", ",
violations); reference SupportedFieldValidator, the violations variable,
validator.validate(message), and the IllegalArgumentException in your change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java`:
- Around line 44-57: Add Javadoc to the StrictXdsValidatorIndex.assertValid
method explaining that pgvValidator.assertValid(message) runs first and
short-circuits further supported-field validation: if PGV structural validation
fails, supported-field violations will not be collected or reported; mention
this is intentional for prioritizing structural errors and that no functional
changes are made. Reference the pgvValidator field and the
SupportedFieldValidator-based check in the doc comment so readers know which
checks run and in what order.
- Around line 48-56: The aggregated error message in StrictXdsValidatorIndex
collects only descriptorName and fieldPath into the violations list, making
duplicate entries hard to distinguish; update the SupportedFieldValidator
handler (the lambda passed to SupportedFieldValidator.of) to include a concise
representation of the offending value (e.g., value.getClass().getSimpleName() or
a truncated toString/first N chars) when adding to violations, and after
validator.validate(message) sort and deduplicate the violations list to produce
a stable, readable order before throwing the IllegalArgumentException that
currently contains "Unsupported xDS fields detected: " + String.join(", ",
violations); reference SupportedFieldValidator, the violations variable,
validator.validate(message), and the IllegalArgumentException in your change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ebbdc4d7-046d-490a-bcae-a08fb4b6eb1e

📥 Commits

Reviewing files that changed from the base of the PR and between fe32d03 and 4a74337.

📒 Files selected for processing (17)
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/DefaultXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java
  • xds-api/src/main/proto/armeria/xds/supported.proto
  • xds-api/src/main/proto/envoy/config/cluster/v3/cluster.proto
  • xds-api/src/main/proto/envoy/config/core/v3/address.proto
  • xds-api/src/main/proto/envoy/config/core/v3/base.proto
  • xds-api/src/main/proto/envoy/config/core/v3/config_source.proto
  • xds-api/src/main/proto/envoy/config/core/v3/grpc_service.proto
  • xds-api/src/main/proto/envoy/config/core/v3/health_check.proto
  • xds-api/src/main/proto/envoy/config/endpoint/v3/endpoint_components.proto
  • xds-api/src/main/proto/envoy/config/route/v3/route_components.proto
  • xds-api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/secret.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto
  • xds-api/src/main/proto/envoy/type/matcher/v3/string.proto
  • xds-validator/build.gradle
✅ Files skipped from review due to trivial changes (7)
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/secret.proto
  • xds-api/src/main/proto/envoy/config/core/v3/address.proto
  • xds-api/src/main/proto/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto
  • xds-api/src/main/proto/envoy/type/matcher/v3/string.proto
  • xds-api/src/main/proto/envoy/config/core/v3/config_source.proto
  • xds-api/src/main/proto/envoy/config/endpoint/v3/endpoint_components.proto
  • xds-api/src/main/proto/envoy/config/route/v3/route_components.proto
🚧 Files skipped from review as they are similar to previous changes (6)
  • xds-validator/build.gradle
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/SupportedFieldValidator.java
  • xds-api/src/main/proto/armeria/xds/supported.proto
  • xds-api/src/main/proto/envoy/config/core/v3/base.proto
  • xds-api/src/main/proto/envoy/extensions/transport_sockets/tls/v3/tls.proto
  • xds-api/src/main/proto/envoy/config/core/v3/health_check.proto

@jrhee17 jrhee17 marked this pull request as ready for review April 23, 2026 06:25
Copy link
Copy Markdown
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

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

👍👍

/**
* A strict {@link XdsValidatorIndex} that composes pgv (protoc-gen-validate) structural validation
* with supported-field validation. All unsupported field violations are collected and reported
* together in a single {@link IllegalArgumentException}.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optional) What do you think of introducing a dedicated exception type to identify the validation error more easily.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Note that exceptions don't really impact actually request flow, so I don't really expect users to react based on the exceptions. Updated anyways.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java`:
- Around line 34-53: Add explicit null checks to the public factory methods to
make NPEs deterministic: in XdsValidationException.of(Message, Throwable) call
Objects.requireNonNull(resource, "resource") and Objects.requireNonNull(cause,
"cause") before using them and use their values to build the message; in
XdsValidationException.of(Message, String) call Objects.requireNonNull(resource,
"resource") and Objects.requireNonNull(message, "message"); and in
XdsValidationException.of(String) call Objects.requireNonNull(message,
"message"). Ensure the exception messages use the parameter name strings exactly
as shown so the errors are deterministic and user-facing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 609121c9-2b4c-4a54-a18a-920ae77787c4

📥 Commits

Reviewing files that changed from the base of the PR and between 4a74337 and 78aa0fb.

📒 Files selected for processing (5)
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/UnsupportedFieldHandler.java
  • xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java
  • xds/src/test/java/com/linecorp/armeria/xds/XdsValidatorIndexRegistryTest.java
✅ Files skipped from review due to trivial changes (1)
  • xds/src/test/java/com/linecorp/armeria/xds/XdsValidatorIndexRegistryTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/PgvValidator.java
  • xds-api/src/main/java/com/linecorp/armeria/xds/api/StrictXdsValidatorIndex.java

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java (1)

36-40: ⚠️ Potential issue | 🟡 Minor

Make of(Message, Throwable) robust when cause message is null.

If cause.getMessage() is null, the resulting text becomes <type>: null, which is not very actionable. Fall back to the cause class name.

Suggested patch
     public static XdsValidationException of(Message resource, Throwable cause) {
         requireNonNull(resource, "resource");
         requireNonNull(cause, "cause");
+        final String causeMessage = cause.getMessage();
         return new XdsValidationException(
-                resource.getDescriptorForType().getFullName() + ": " + cause.getMessage(), cause);
+                resource.getDescriptorForType().getFullName() + ": " +
+                (causeMessage != null ? causeMessage : cause.getClass().getName()), cause);
     }

As per coding guidelines, "Exceptions: when throwing, use meaningful messages that include the offending value/expectation; use validation-style messages like "value: %s (expected: ...)"."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java`
around lines 36 - 40, The factory method XdsValidationException.of(Message,
Throwable) currently concatenates cause.getMessage() which can be null; update
this method so it uses a non-null message by falling back to the cause class
name when cause.getMessage() is null (e.g., use cause.getMessage() != null ?
cause.getMessage() : cause.getClass().getName()), then build the exception
message as resource.getDescriptorForType().getFullName() + ": " +
resolvedCauseMessage and pass the original cause through to the
XdsValidationException constructor.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java`:
- Around line 36-40: The factory method XdsValidationException.of(Message,
Throwable) currently concatenates cause.getMessage() which can be null; update
this method so it uses a non-null message by falling back to the cause class
name when cause.getMessage() is null (e.g., use cause.getMessage() != null ?
cause.getMessage() : cause.getClass().getName()), then build the exception
message as resource.getDescriptorForType().getFullName() + ": " +
resolvedCauseMessage and pass the original cause through to the
XdsValidationException constructor.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 68d99b7a-f209-47e1-b881-61bbcd4dfecb

📥 Commits

Reviewing files that changed from the base of the PR and between 78aa0fb and 6346707.

📒 Files selected for processing (1)
  • xds-validator/src/main/java/com/linecorp/armeria/xds/validator/XdsValidationException.java

Copy link
Copy Markdown
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

👍 👍 👍


private static final PgvValidator INSTANCE = new PgvValidator();

private final ValidatorIndex delegate = new ReflectiveValidatorIndex();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

static?

@jrhee17 jrhee17 merged commit a93eae5 into line:main May 4, 2026
16 of 17 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (8150425) to head (88c95b9).
⚠️ Report is 426 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main   #6736       +/-   ##
============================================
- Coverage     74.46%       0   -74.47%     
============================================
  Files          1963       0     -1963     
  Lines         82437       0    -82437     
  Branches      10764       0    -10764     
============================================
- Hits          61385       0    -61385     
+ Misses        15918       0    -15918     
+ Partials       5134       0     -5134     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants