Skip to content

Add integration tests with Istiod#6730

Open
jrhee17 wants to merge 7 commits intoline:mainfrom
jrhee17:feat/istio-it
Open

Add integration tests with Istiod#6730
jrhee17 wants to merge 7 commits intoline:mainfrom
jrhee17:feat/istio-it

Conversation

@jrhee17
Copy link
Copy Markdown
Contributor

@jrhee17 jrhee17 commented Apr 20, 2026

This PR should be reviewed after #6708

Motivation:

Armeria's xDS client could not communicate with a real Istio control plane end-to-end. Several gaps prevented this:

  1. TLS configuration mismatch — When building ClientTlsSpec from xDS UpstreamTlsContext, Armeria ignored the ALPN protocols specified in the xDS config and always enforced JSSE hostname verification (HTTPS algorithm). Updated so that Istio's alpn filter is mirrored, and verifies peer identity via SPIFFE rather than hostname, so JSSE verification must be disabled for mTLS to succeed.
  2. Listener filter chain extractionListenerXdsResource only extracted HttpConnectionManager from api_listener, ignoring non-API listeners that carry HCM inside filter_chains. Istio's sidecar-generated listeners use filter chains exclusively.
  3. No real Istio integration tests — The existing it/xds-istio module only tested basic cluster startup and Envoy sidecar reachability, but never exercised Armeria's xDS client against Istiod.

Modifications:

Core (core)

  • Add overrideAlpnProtocols and endpointIdentificationAlgorithm to ClientTlsSpec / ClientTlsSpecBuilder, allowing xDS-derived TLS configs to override session-protocol-based ALPN and disable JSSE hostname verification.
  • Make AbstractTlsSpec.alpnProtocols() non-final so ClientTlsSpec can override it.
  • Use clientTlsSpec.endpointIdentificationAlgorithm() in SslContextUtil instead of hardcoded "HTTPS".

xDS (xds)

  • TLS from UpstreamTlsContext: TransportSocketSnapshot receives the UpstreamTlsContext and uses its ALPN list (filtering out istio-peer-exchange). Endpoint identification algorithm defaults to "" (disabled) for xDS transport sockets, re-enabled to "HTTPS" only when system root CAs are used.
  • Filter chain HCM extraction: ListenerXdsResource.extractHcmFromFilterChains() scans filter chains for envoy.filters.network.http_connection_manager to support non-API listeners.
  • Support pipe (Unix domain socket) addresses in xDS endpoint resolution.
  • Add toDebugString() to the Snapshot interface and all implementations for protobuf-level introspection.
  • Remove unused protoc-pgv-java-stub dependency from xds and xds-api.

Istio integration tests (it/xds-istio)

  • Add XdsClientToSidecarTest — bootstraps Armeria's xDS client from the Istio-generated bootstrap, loads cluster/listener snapshots, and makes HTTP requests routed via xDS through the Envoy sidecar.
  • Add XdsGrpcProxylessTest — tests Armeria's xDS client in Istio gRPC proxyless mode (grpc-agent template, no Envoy).
  • Add XdsNativeGrpcProxylessTest — tests native gRPC proxyless mode via grpc-java for comparison.
  • Add GrpcProxylessPodCustomizer, NoopXdsValidatorIndex, and IstioNoOpFilterFactories as supporting infrastructure for the new tests.
  • Disable Delta xDS in IstioPodCustomizer to avoid a hot-loop caused by Istio's wildcard CDS/LDS behavior.
  • Switch K8s client to ArmeriaHttpClientFactory with retry for improved reliability.

Result:

  • Armeria's xDS client can now connect to a real Istio control plane, resolve endpoints (including UDS pipes), establish mTLS using SDS-provisioned certificates, and route HTTP requests through the Envoy sidecar — all validated by new integration tests.
  • ClientTlsSpec gains overrideAlpnProtocols() and endpointIdentificationAlgorithm() for fine-grained TLS control needed by xDS-based mTLS.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 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

This PR enhances client TLS configuration with ALPN protocol override and endpoint identification algorithm support, extends xDS snapshot classes with debug string methods, adds comprehensive Istio integration testing infrastructure (including gRPC proxyless mode), and introduces test utilities for xDS resource parsing and filter factories. ALPN override allows runtime protocol selection, replacing the static defaults derived from protocol configuration.

Changes

Cohort / File(s) Summary
Client TLS Configuration
core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java, core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java, core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java, core/src/main/java/com/linecorp/armeria/internal/common/util/SslContextUtil.java
Added overrideAlpnProtocols and endpointIdentificationAlgorithm fields to TLS specs; ClientTlsSpec now overrides alpnProtocols() to return override set when non-empty; AbstractTlsSpec.alpnProtocols() changed from final to allow overrides; SslContextUtil applies endpoint identification algorithm from spec instead of hardcoded value.
xDS Snapshot Debug Support
xds/src/main/java/com/linecorp/armeria/xds/Snapshot.java, xds/src/main/java/com/linecorp/armeria/xds/SnapshotUtil.java, xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/EndpointSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/ListenerSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/RouteSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/VirtualHostSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/RouteEntry.java, xds/src/main/java/com/linecorp/armeria/xds/TransportSocketMatchSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/TlsCertificateSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/CertificateValidationContextSnapshot.java
Snapshot interface now requires toDebugString() method (removed @FunctionalInterface); new SnapshotUtil provides debug string helpers; all snapshot classes implement toDebugString() to provide detailed debug output with full protobuf resources.
TransportSocket and TLS Context Handling
xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java, xds/src/main/java/com/linecorp/armeria/xds/TransportSocketStream.java, xds/src/main/java/com/linecorp/armeria/xds/internal/XdsCommonUtil.java
TransportSocketSnapshot now accepts optional UpstreamTlsContext and applies ALPN protocols from it; TransportSocketStream passes tlsContext to snapshot constructor; XdsCommonUtil adds ALPN_OVERRIDE_KEY attribute to allow runtime ALPN protocol override.
xDS Listener and Certificate Validation
xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java, xds/src/main/java/com/linecorp/armeria/xds/CertificateValidationContextSnapshot.java
ListenerXdsResource now uses multi-source lookup for HttpConnectionManager (api_listener or filter_chains); CertificateValidationContextSnapshot supports legacy match_subject_alt_names field when no typed matchers present; toString() behavior simplified.
Istio Integration Testing
it/xds-istio/build.gradle, it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/GrpcProxylessPodCustomizer.java, it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/IstioPodCustomizer.java, it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/K8sClusterHelper.java
Added GrpcProxylessPodCustomizer for Istio gRPC proxyless mode; IstioPodCustomizer now sets ISTIO_DELTA_XDS to false (uses SotW); K8sClusterHelper uses Armeria WebClient with retry decorator instead of Fabric8 native timeouts; build.gradle adds json-path dependency for test XDS functionality.
xDS Integration Tests
it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/EnvoyDebugTest.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsGrpcProxylessTest.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsNativeGrpcProxylessTest.java, it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.filter.HttpFilterFactory
Added comprehensive integration tests: XdsClientToSidecarTest validates client-to-sidecar xDS path; XdsGrpcProxylessTest tests gRPC proxyless mode; XdsNativeGrpcProxylessTest tests native gRPC bootstrap; EnvoyDebugTest adds webClient helper with retry decorator; HttpFilterFactory SPI registration added.
Test Utilities and XDS Resources
it/xds-client/src/main/java/com/linecorp/armeria/xds/it/XdsResourceReader.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsResourceReader.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/NoopXdsValidatorIndex.java, it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/filter/IstioFilterFactories.java, it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.validator.XdsValidatorIndex
Generic protobuf parsing utilities changed from GeneratedMessage to Message base type; test XdsResourceReader added for YAML/JSON parsing with JsonPath support for xDS gRPC bootstrap rewriting; NoopXdsValidatorIndex validator implementation added; IstioFilterFactories provides SPI-registered HTTP filter implementations for Istio/Envoy filters including ALPN override support.
xDS Endpoint and Dependency Management
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsHealthCheckedEndpointGroupBuilder.java, dependencies.toml, it/xds-client/build.gradle, xds-api/build.gradle, xds/build.gradle, settings.gradle
XdsHealthCheckedEndpointGroupBuilder now supports pipe (domain socket) addresses via Address.hasPipe() detection; removed protoc-pgv stub dependencies from test classpaths; added json-path 3.0.0 dependency; it/xds-istio marked with 'relocate' flag in settings.gradle.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Armeria Client
    participant CTLS as ClientTlsSpec
    participant Builder as ClientTlsSpecBuilder
    participant SslUtil as SslContextUtil
    participant OpenSSL as OpenSSL Context

    Client->>Builder: alpnProtocols(customProtocols)
    Builder->>Builder: store overrideAlpnProtocols
    Client->>Builder: endpointIdentificationAlgorithm(algo)
    Builder->>Builder: store algorithm
    Client->>Builder: build()
    Builder->>CTLS: new ClientTlsSpec(...,overrides,algo)
    CTLS->>CTLS: initialize baseAlpnProtocols,overrideAlpnProtocols
    Client->>SslUtil: createClientSslContext(ClientTlsSpec)
    SslUtil->>CTLS: alpnProtocols()
    CTLS-->>SslUtil: return overrideAlpnProtocols (if non-empty)
    SslUtil->>CTLS: endpointIdentificationAlgorithm()
    CTLS-->>SslUtil: return algorithm
    SslUtil->>OpenSSL: setAlpnProtocols(protocols)
    SslUtil->>OpenSSL: setEndpointIdentificationAlgorithm(algo)
    SslUtil-->>Client: SslContext
Loading
sequenceDiagram
    participant Test as Integration Test
    participant Istio as Istio Cluster
    participant Pod as gRPC Proxyless Pod
    participant Agent as gRPC Agent
    participant XDS as XDS Server

    Test->>Istio: start cluster with GrpcProxylessPodCustomizer
    Istio->>Pod: create pod
    Pod->>Pod: inject grpc-agent template annotation
    Istio->>Agent: start lightweight pilot-agent
    Agent->>XDS: fetch gRPC bootstrap config
    XDS-->>Agent: bootstrap.json
    Test->>Pod: wait for pod healthy
    Pod->>Pod: check istio-proxy container ready
    Pod-->>Test: healthy
    Test->>Pod: send request via xDS listener
    Pod->>Agent: route through agent
    Agent->>Pod: deliver to target
    Pod-->>Test: response 200 OK
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

new feature, breaking change

Suggested reviewers

  • trustin
  • ikhoon
  • minwoox

Poem

🐰 A bunny hops through TLS trees,
Where ALPN protocols dance with ease,
xDS snapshots now debug with care,
Istio pods float through the air,
Proxyless paths to endpoints true! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.62% 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 pull request title 'Add integration tests with Istiod' accurately describes the main objective of adding Istio integration tests, though it does not capture the broader scope of TLS configuration improvements and xDS enhancements also included.
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.
Description check ✅ Passed The PR description accurately details the motivation, modifications, and results of the changeset, describing TLS configuration improvements, listener extraction fixes, and new integration tests.

✏️ 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.

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: 6

Caution

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

⚠️ Outside diff range comments (1)
xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java (1)

159-166: ⚠️ Potential issue | 🟡 Minor

Log message interpolation is broken.

The message uses "\\{}", which emits a literal backslash followed by {} rather than an SLF4J placeholder — and there are no arguments passed to logger.warn anyway, so the {} would not be substituted regardless. Users will see Set system_root_certs: \{} to use ... in logs. Drop the placeholder (it isn't parameterized) and clean the string up.

Suggested change
-            logger.warn("TLS peer verification is disabled because validation context has no trusted CA " +
-                        "and system_root_certs is unset. Set system_root_certs: \\{} to use the " +
-                        "default Java TLS roots.");
+            logger.warn("TLS peer verification is disabled because the validation context has no trusted " +
+                        "CA and system_root_certs is unset. Set system_root_certs: {} to use the default " +
+                        "Java TLS roots.", "{}");

Or, if the intent is just to document the YAML snippet, hard-code it in the string without any placeholder:

-            logger.warn("TLS peer verification is disabled because validation context has no trusted CA " +
-                        "and system_root_certs is unset. Set system_root_certs: \\{} to use the " +
-                        "default Java TLS roots.");
+            logger.warn("TLS peer verification is disabled because the validation context has no trusted " +
+                        "CA and system_root_certs is unset. Set 'system_root_certs: {}' to use the " +
+                        "default Java TLS roots.");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`
around lines 159 - 166, The log message in
TransportSocketSnapshot.warnNoVerifyOnce wrongly includes an escaped SLF4J
placeholder ("\\{}") and no arguments, producing a literal "\{}" in logs; update
the logger.warn call in warnNoVerifyOnce (and leave warnedNoVerify handling) to
use a plain string without any placeholder so the YAML snippet appears correctly
(e.g., "Set system_root_certs: {} to use the default Java TLS roots." with the
braces literal, or better hard-code the snippet "Set system_root_certs: true to
use the default Java TLS roots." depending on intended wording).
🧹 Nitpick comments (11)
xds/src/main/java/com/linecorp/armeria/xds/TlsCertificateSnapshot.java (1)

76-79: toString() is now effectively empty.

After removing the resource field (and dropping omitNullValues()), this returns just TlsCertificateSnapshot{}. Consider including at least a non-verbose identifier (e.g. tlsKeyPair presence or a resource name) so logs using the default toString() remain useful; the full protobuf already lives in toDebugString().

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

In `@xds/src/main/java/com/linecorp/armeria/xds/TlsCertificateSnapshot.java`
around lines 76 - 79, The current TlsCertificateSnapshot.toString() returns an
empty brace; update toString() to include a compact identifier such as whether
tlsKeyPair is present and/or a resource name (e.g. add("tlsKeyPairPresent",
tlsKeyPair != null) and/or add("resourceName", resourceName)) using
MoreObjects.toStringHelper(this) so logs remain useful while keeping the full
protobuf output in toDebugString(); locate the toString() method in class
TlsCertificateSnapshot and add these non-verbose fields.
xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java (1)

141-142: Render transport socket matches with their debug strings.

transportSocketMatches currently falls back to TransportSocketMatchSnapshot.toString(), so the nested transport sockets do not get the new protobuf-focused debug expansion.

Proposed fix
                           .add("transportSocket", transportSocket.toDebugString())
-                          .add("transportSocketMatches", transportSocketMatches)
+                          .add("transportSocketMatches",
+                               SnapshotUtil.debugStrings(transportSocketMatches,
+                                                         TransportSocketMatchSnapshot::toDebugString))
                           .toString();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java` around lines
141 - 142, ClusterSnapshot currently logs transportSocketMatches using its
default toString, losing the protobuf-focused debug expansion; update the
pretty-printing to map each TransportSocketMatchSnapshot to its debug string
(e.g., replace the direct use of transportSocketMatches in the
StringBuilder/MoreObjects.add call with a transformed collection produced by
transportSocketMatches.stream().map(TransportSocketMatchSnapshot::toDebugString).collect(...))
so nested transport sockets render with their debug strings; locate the code
around the .add("transportSocket", transportSocket.toDebugString()) and change
the .add("transportSocketMatches", transportSocketMatches) usage to the
mapped-toDebugString version.
xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java (2)

208-216: Verify Paths.get(...).toAbsolutePath() behavior for relative pipe paths.

When the Envoy Pipe.path is absolute (the common/expected case), this is a no-op. When it is relative, toAbsolutePath() resolves against the JVM's working directory, which likely differs from whatever the control plane intended — silently producing a bogus endpoint rather than surfacing a configuration error. Consider either:

  • requiring an absolute path and throwing an IllegalArgumentException with the offending value if it is relative, or
  • dropping the toAbsolutePath() call and letting DomainSocketAddress.of(path) receive the path verbatim (it already rejects empty paths).

If the absolute-path resolution is intentional (e.g., to normalize ./sock), a brief comment would help.

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

In
`@xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java`
around lines 208 - 216, The current use of
Paths.get(address.getPipe().getPath()).toAbsolutePath() can silently resolve
relative pipe paths against the JVM working dir and produce bogus endpoints;
update XdsEndpointUtil so that when address.hasPipe() is true you validate the
provided pipe path is absolute and throw an IllegalArgumentException containing
the offending value if Paths.get(address.getPipe().getPath()).isAbsolute() is
false, then keep using
DomainSocketAddress.of(pipePath).asEndpoint().withAttr(...) for the validated
absolute path (or add a short comment explaining the deliberate normalization if
you prefer to retain toAbsolutePath()).

144-149: Include cluster context in the error message.

Other unsupported cases in this file include the cluster name and type (see the default branch of convertEndpointGroup). Mirroring that here makes diagnostics consistent.

Suggested change
-                if (address.hasPipe()) {
-                    throw new UnsupportedOperationException(
-                            "Pipe addresses are not supported for STRICT_DNS cluster type");
-                }
+                if (address.hasPipe()) {
+                    throw new UnsupportedOperationException(
+                            "Cluster (" + cluster.getName() + ") uses a pipe address with " +
+                            "STRICT_DNS; pipe addresses are only supported with STATIC or EDS.");
+                }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java`
around lines 144 - 149, The UnsupportedOperationException thrown when an
lbEndpoint has a pipe address lacks cluster context; update the exception
message inside XdsEndpointUtil (the block handling
lbEndpoint.getEndpoint().getAddress() where it checks address.hasPipe()) to
include the cluster name and cluster type (same fields used in
convertEndpointGroup) so diagnostics match other unsupported-case
messages—retrieve the cluster name and type available in the surrounding scope
and interpolate them into the error message (e.g., "Pipe addresses are not
supported for STRICT_DNS cluster type: cluster=<name> type=<type>").
xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java (2)

107-120: Minor: prefer ImmutableList.toImmutableList() for ALPN filtering.

ImmutableList is already imported and the rest of the Armeria codebase prefers Guava immutable collectors over Collectors.toList() (which returns a mutable ArrayList). Also consider short-circuiting when alpn is empty to avoid the stream allocation on the common no-ALPN case.

Suggested change
-        if (upstreamTlsContext != null) {
-            // Armeria doesn't implement "istio-peer-exchange" for now.
-            final List<String> alpn = upstreamTlsContext.getCommonTlsContext().getAlpnProtocolsList();
-            final List<String> filteredAlpn = alpn.stream()
-                                                  .filter(a -> !istioPeerExchange.equals(a))
-                                                  .collect(Collectors.toList());
-            specBuilder.alpnProtocols(filteredAlpn);
-        }
+        if (upstreamTlsContext != null) {
+            // Armeria doesn't implement "istio-peer-exchange" for now.
+            final List<String> alpn = upstreamTlsContext.getCommonTlsContext().getAlpnProtocolsList();
+            if (!alpn.isEmpty()) {
+                final List<String> filteredAlpn = alpn.stream()
+                                                      .filter(a -> !ISTIO_PEER_EXCHANGE.equals(a))
+                                                      .collect(ImmutableList.toImmutableList());
+                specBuilder.alpnProtocols(filteredAlpn);
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`
around lines 107 - 120, In buildClientTlsSpec, avoid Collectors.toList() and
unnecessary stream allocation: after obtaining
upstreamTlsContext.getCommonTlsContext().getAlpnProtocolsList(), short-circuit
if alpn is empty (skip filtering and don't call specBuilder.alpnProtocols),
otherwise use ImmutableList.toImmutableList() to collect filtered values
(filtering out istioPeerExchange) and pass the resulting immutable list to
specBuilder.alpnProtocols(filteredAlpn). This replaces the mutable ArrayList
creation with Guava's immutable collector and avoids allocating a stream for the
common empty case.

50-50: Constant naming.

istioPeerExchange is private static final and should follow Java's UPPER_SNAKE_CASE convention used throughout this module (e.g., HTTP_CONNECTION_MANAGER_TYPE_URL in ListenerXdsResource). Rename to ISTIO_PEER_EXCHANGE.

Suggested change
-    private static final String istioPeerExchange = "istio-peer-exchange";
+    private static final String ISTIO_PEER_EXCHANGE = "istio-peer-exchange";

And update the reference in buildClientTlsSpec accordingly.

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

In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java` at
line 50, Rename the private static final field istioPeerExchange in
TransportSocketSnapshot to follow Java constant naming (ISTIO_PEER_EXCHANGE) and
update all references, particularly the usage inside buildClientTlsSpec, to use
the new constant name; ensure the field remains static final and update any
imports or qualifiers as necessary so compilation and behavior are unchanged.
core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java (1)

101-117: Minor: missing this == o short-circuit in equals.

Functionally correct (super.equals handles identity correctly), but the idiomatic pattern in Armeria and across this codebase is to short-circuit on reference equality before doing class and field comparisons.

Suggested change
     `@Override`
     public boolean equals(`@Nullable` Object o) {
+        if (this == o) {
+            return true;
+        }
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
         if (!super.equals(o)) {
             return false;
         }
         final ClientTlsSpec that = (ClientTlsSpec) o;
         return Objects.equal(overrideAlpnProtocols, that.overrideAlpnProtocols) &&
                Objects.equal(endpointIdentificationAlgorithm, that.endpointIdentificationAlgorithm);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java` around
lines 101 - 117, The equals implementation in ClientTlsSpec should short-circuit
on reference equality; update the equals(`@Nullable` Object o) method in class
ClientTlsSpec to first check "if (this == o) return true;" before the null/class
checks so identity is handled immediately, then proceed with the existing
getClass() check, call to super.equals(o), and the field comparisons for
overrideAlpnProtocols and endpointIdentificationAlgorithm; no other logic
changes required (ensure hashCode remains unchanged).
xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java (1)

138-152: Consider scanning default_filter_chain as well.

extractHcmFromFilterChains only iterates listener.getFilterChainsList() and ignores listener.getDefaultFilterChain(). Envoy listeners can carry the HCM on the default filter chain (used when no FilterChainMatch matches), so a listener that only configures HCM there would end up with connectionManager == null and therefore no routing. If this isn't expected to occur in the targeted (Istio sidecar / gRPC proxyless) scenarios, a brief javadoc note clarifying the scope would help.

Also note that returning only the first HCM across all filter chains silently drops any per-filter-chain HCM divergence (different RDS/route configs per SNI/transport match). That seems intentional for the proxyless path but is worth documenting.

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

In `@xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java` around
lines 138 - 152, The extractHcmFromFilterChains method currently only inspects
listener.getFilterChainsList(), missing listener.getDefaultFilterChain(); update
extractHcmFromFilterChains to also check listener.getDefaultFilterChain() for an
HttpConnectionManager (same name/type-url checks and unpack via
XdsValidatorIndexRegistry.unpack) and return it if found; additionally, add a
brief javadoc to extractHcmFromFilterChains explaining that it returns the first
HCM encountered (scanning defaultFilterChain then explicit filterChains) and
that per-filter-chain HCM divergence (different RDS/routes) will be ignored by
this method.
core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java (2)

76-80: Consider null-checking individual ALPN entries and rejecting empty strings.

ImmutableSet.copyOf accepts any non-null Collection but throws NPE only if an element is null — a blank/empty element would silently propagate all the way to the Netty ApplicationProtocolConfig. Validating here gives a clearer error surface for a public API.

Suggested change
     public ClientTlsSpecBuilder alpnProtocols(Collection<String> alpnProtocols) {
         requireNonNull(alpnProtocols, "alpnProtocols");
-        overrideAlpnProtocols = ImmutableSet.copyOf(alpnProtocols);
+        final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+        for (String p : alpnProtocols) {
+            requireNonNull(p, "alpnProtocols contains null");
+            checkArgument(!p.isEmpty(), "alpnProtocols contains an empty string");
+            builder.add(p);
+        }
+        overrideAlpnProtocols = builder.build();
         return this;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java`
around lines 76 - 80, The alpnProtocols method currently allows blank/empty
strings to be passed through to overrideAlpnProtocols; update
ClientTlsSpecBuilder.alpnProtocols to validate each element: after
requireNonNull(alpnProtocols), iterate the collection and requireNonNull each
protocol string and reject empty or all-whitespace strings (throw
IllegalArgumentException with a clear message), then set overrideAlpnProtocols =
ImmutableSet.copyOf(alpnProtocols); this ensures null entries and blank ALPN
identifiers are rejected at the public API boundary.

92-102: Document and/or validate accepted values for endpointIdentificationAlgorithm.

JSSE currently recognizes only "HTTPS", "LDAPS", and "" for SSLParameters.setEndpointIdentificationAlgorithm. Any other value will only fail later during SSL handshake. For a public, @UnstableApi method it'd be helpful to either:

  • explicitly enumerate acceptable values (or at least reject obvious garbage like whitespace-only), or
  • expand the Javadoc to note that the value is passed through to JSSE verbatim and unsupported values will fail at connect time.

The current doc only mentions "HTTPS" and "", which may leave users guessing whether e.g. "LDAPS" is supported.

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

In `@core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java`
around lines 92 - 102, Update
ClientTlsSpecBuilder.endpointIdentificationAlgorithm to either validate or
document accepted JSSE values: add input validation that trims and rejects
null/blank strings and only allows the known set {"HTTPS","LDAPS",""} (throw
IllegalArgumentException for others), or expand the method Javadoc to explicitly
enumerate the accepted values and state that the string is passed verbatim to
SSLParameters.setEndpointIdentificationAlgorithm and unsupported values will
fail at connect time; reference the endpointIdentificationAlgorithm field, the
endpointIdentificationAlgorithm(String) setter, and
SSLParameters.setEndpointIdentificationAlgorithm in the doc or validation error
message so callers can locate and understand the behavior.
it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java (1)

222-235: Remove the leftover fixed sleep.

Thread.sleep(10_000) runs after the Awaitility assertions have already passed, so it only slows the Istio integration suite by 10 seconds per run.

Proposed fix
             });
             logger.info("Outbound listener snapshot loaded: {}", snapshotRef.get());
-            Thread.sleep(10_000);
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java`
around lines 222 - 235, A leftover Thread.sleep(10_000) after the Awaitility
assertions is causing an unnecessary 10s delay; remove the Thread.sleep(10_000)
call in XdsClientToSidecarTest so the test proceeds immediately after the
await().untilAsserted block finishes (look for the await block that checks
errorRef/get, snapshotRef/get and asserts
snapshot.routeSnapshot().xdsResource().resource().getName() contains
server.serviceName(), and delete the Thread.sleep invocation that follows it).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java`:
- Around line 90-91: AbstractTlsSpec exposes an overridable alpnProtocols()
accessor but equals() and hashCode() read the alpnProtocols field directly,
causing mismatches when subclasses (e.g., ClientTlsSpec) override ALPN; update
equals() and hashCode() in AbstractTlsSpec to consult the public alpnProtocols()
accessor (and normalize the returned collection consistently, e.g., treat
null/empty the same and compare as a Set) instead of referencing the private
field, ensuring both methods reflect the overridable public state.

In `@it/xds-istio/build.gradle`:
- Around line 89-92: The task that currently includes
from(sourceSets.test.output) (the block that also dependsOn
tasks.named('copyShadedTestClasses') and uses
configurations.shadedJarTestRuntime) must use the shaded test-class output
produced by the copyShadedTestClasses task instead of the original test classes;
update that task (the one containing dependsOn
tasks.named('copyShadedTestClasses')) to replace from(sourceSets.test.output)
with the output files of tasks.named('copyShadedTestClasses') (e.g., use the
task's outputs.files or destination directory exposed by copyShadedTestClasses)
so the copied runtime uses relocated/shaded test classes rather than
sourceSets.test.output.

In
`@it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsResourceReader.java`:
- Around line 1-15: The file-level copyright header in XdsResourceReader.java
uses "LINE Corporation" but the project standard and other new files use "LY
Corporation"; update the header comment at the top of XdsResourceReader.java to
replace "LINE Corporation" with "LY Corporation" so it matches the required
project header (ensure the rest of the Apache 2.0 boilerplate remains
unchanged).
- Around line 43-95: The class XdsResourceReader is unnecessarily public for
test-only use; remove the public modifier from the class declaration (change
"public final class XdsResourceReader" to "final class XdsResourceReader") so it
becomes package-private. Leave the existing public static helper methods
(fromYaml, fromYaml<T>, fromJson) as-is; if instead you prefer to keep the class
public, add appropriate Javadoc on the class and its public methods
(XdsResourceReader, fromYaml, fromYaml(Class<T>), fromJson) describing their
test-only purpose—prefer the package-private change per the review.

In
`@xds/src/main/java/com/linecorp/armeria/xds/CertificateValidationContextSnapshot.java`:
- Around line 160-163: The current toString() in
CertificateValidationContextSnapshot now returns an empty object and loses
helpful fields; restore a concise summary (e.g., include the resource identifier
or a short summary field) in toString() while keeping the full, verbose output
in toDebugString(). Update CertificateValidationContextSnapshot.toString() to
use MoreObjects.toStringHelper(this).add("resource", resourceSummary) (or
another small summary field) instead of the empty helper, and keep the detailed
fields only in toDebugString() so logs using toString() remain informative
without exposing verbose content.

In `@xds/src/main/java/com/linecorp/armeria/xds/VirtualHostSnapshot.java`:
- Around line 90-97: The new public debug API method toDebugString() in
VirtualHostSnapshot must be annotated with `@UnstableApi`; add the `@UnstableApi`
annotation to the toDebugString() method (or the enclosing VirtualHostSnapshot
class if preferred) and add the corresponding import for the annotation so the
new public API complies with the project's unstable-API coding guideline.

---

Outside diff comments:
In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`:
- Around line 159-166: The log message in
TransportSocketSnapshot.warnNoVerifyOnce wrongly includes an escaped SLF4J
placeholder ("\\{}") and no arguments, producing a literal "\{}" in logs; update
the logger.warn call in warnNoVerifyOnce (and leave warnedNoVerify handling) to
use a plain string without any placeholder so the YAML snippet appears correctly
(e.g., "Set system_root_certs: {} to use the default Java TLS roots." with the
braces literal, or better hard-code the snippet "Set system_root_certs: true to
use the default Java TLS roots." depending on intended wording).

---

Nitpick comments:
In `@core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java`:
- Around line 101-117: The equals implementation in ClientTlsSpec should
short-circuit on reference equality; update the equals(`@Nullable` Object o)
method in class ClientTlsSpec to first check "if (this == o) return true;"
before the null/class checks so identity is handled immediately, then proceed
with the existing getClass() check, call to super.equals(o), and the field
comparisons for overrideAlpnProtocols and endpointIdentificationAlgorithm; no
other logic changes required (ensure hashCode remains unchanged).

In `@core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java`:
- Around line 76-80: The alpnProtocols method currently allows blank/empty
strings to be passed through to overrideAlpnProtocols; update
ClientTlsSpecBuilder.alpnProtocols to validate each element: after
requireNonNull(alpnProtocols), iterate the collection and requireNonNull each
protocol string and reject empty or all-whitespace strings (throw
IllegalArgumentException with a clear message), then set overrideAlpnProtocols =
ImmutableSet.copyOf(alpnProtocols); this ensures null entries and blank ALPN
identifiers are rejected at the public API boundary.
- Around line 92-102: Update
ClientTlsSpecBuilder.endpointIdentificationAlgorithm to either validate or
document accepted JSSE values: add input validation that trims and rejects
null/blank strings and only allows the known set {"HTTPS","LDAPS",""} (throw
IllegalArgumentException for others), or expand the method Javadoc to explicitly
enumerate the accepted values and state that the string is passed verbatim to
SSLParameters.setEndpointIdentificationAlgorithm and unsupported values will
fail at connect time; reference the endpointIdentificationAlgorithm field, the
endpointIdentificationAlgorithm(String) setter, and
SSLParameters.setEndpointIdentificationAlgorithm in the doc or validation error
message so callers can locate and understand the behavior.

In
`@it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java`:
- Around line 222-235: A leftover Thread.sleep(10_000) after the Awaitility
assertions is causing an unnecessary 10s delay; remove the Thread.sleep(10_000)
call in XdsClientToSidecarTest so the test proceeds immediately after the
await().untilAsserted block finishes (look for the await block that checks
errorRef/get, snapshotRef/get and asserts
snapshot.routeSnapshot().xdsResource().resource().getName() contains
server.serviceName(), and delete the Thread.sleep invocation that follows it).

In
`@xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java`:
- Around line 208-216: The current use of
Paths.get(address.getPipe().getPath()).toAbsolutePath() can silently resolve
relative pipe paths against the JVM working dir and produce bogus endpoints;
update XdsEndpointUtil so that when address.hasPipe() is true you validate the
provided pipe path is absolute and throw an IllegalArgumentException containing
the offending value if Paths.get(address.getPipe().getPath()).isAbsolute() is
false, then keep using
DomainSocketAddress.of(pipePath).asEndpoint().withAttr(...) for the validated
absolute path (or add a short comment explaining the deliberate normalization if
you prefer to retain toAbsolutePath()).
- Around line 144-149: The UnsupportedOperationException thrown when an
lbEndpoint has a pipe address lacks cluster context; update the exception
message inside XdsEndpointUtil (the block handling
lbEndpoint.getEndpoint().getAddress() where it checks address.hasPipe()) to
include the cluster name and cluster type (same fields used in
convertEndpointGroup) so diagnostics match other unsupported-case
messages—retrieve the cluster name and type available in the surrounding scope
and interpolate them into the error message (e.g., "Pipe addresses are not
supported for STRICT_DNS cluster type: cluster=<name> type=<type>").

In `@xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java`:
- Around line 141-142: ClusterSnapshot currently logs transportSocketMatches
using its default toString, losing the protobuf-focused debug expansion; update
the pretty-printing to map each TransportSocketMatchSnapshot to its debug string
(e.g., replace the direct use of transportSocketMatches in the
StringBuilder/MoreObjects.add call with a transformed collection produced by
transportSocketMatches.stream().map(TransportSocketMatchSnapshot::toDebugString).collect(...))
so nested transport sockets render with their debug strings; locate the code
around the .add("transportSocket", transportSocket.toDebugString()) and change
the .add("transportSocketMatches", transportSocketMatches) usage to the
mapped-toDebugString version.

In `@xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java`:
- Around line 138-152: The extractHcmFromFilterChains method currently only
inspects listener.getFilterChainsList(), missing
listener.getDefaultFilterChain(); update extractHcmFromFilterChains to also
check listener.getDefaultFilterChain() for an HttpConnectionManager (same
name/type-url checks and unpack via XdsValidatorIndexRegistry.unpack) and return
it if found; additionally, add a brief javadoc to extractHcmFromFilterChains
explaining that it returns the first HCM encountered (scanning
defaultFilterChain then explicit filterChains) and that per-filter-chain HCM
divergence (different RDS/routes) will be ignored by this method.

In `@xds/src/main/java/com/linecorp/armeria/xds/TlsCertificateSnapshot.java`:
- Around line 76-79: The current TlsCertificateSnapshot.toString() returns an
empty brace; update toString() to include a compact identifier such as whether
tlsKeyPair is present and/or a resource name (e.g. add("tlsKeyPairPresent",
tlsKeyPair != null) and/or add("resourceName", resourceName)) using
MoreObjects.toStringHelper(this) so logs remain useful while keeping the full
protobuf output in toDebugString(); locate the toString() method in class
TlsCertificateSnapshot and add these non-verbose fields.

In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`:
- Around line 107-120: In buildClientTlsSpec, avoid Collectors.toList() and
unnecessary stream allocation: after obtaining
upstreamTlsContext.getCommonTlsContext().getAlpnProtocolsList(), short-circuit
if alpn is empty (skip filtering and don't call specBuilder.alpnProtocols),
otherwise use ImmutableList.toImmutableList() to collect filtered values
(filtering out istioPeerExchange) and pass the resulting immutable list to
specBuilder.alpnProtocols(filteredAlpn). This replaces the mutable ArrayList
creation with Guava's immutable collector and avoids allocating a stream for the
common empty case.
- Line 50: Rename the private static final field istioPeerExchange in
TransportSocketSnapshot to follow Java constant naming (ISTIO_PEER_EXCHANGE) and
update all references, particularly the usage inside buildClientTlsSpec, to use
the new constant name; ensure the field remains static final and update any
imports or qualifiers as necessary so compilation and behavior are unchanged.
🪄 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: e231dc35-c87d-46db-a5e7-77673459b1f6

📥 Commits

Reviewing files that changed from the base of the PR and between 679b583 and 75d6fe7.

📒 Files selected for processing (40)
  • core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java
  • core/src/main/java/com/linecorp/armeria/client/ClientTlsSpecBuilder.java
  • core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java
  • core/src/main/java/com/linecorp/armeria/internal/common/util/SslContextUtil.java
  • dependencies.toml
  • it/xds-client/build.gradle
  • it/xds-client/src/main/java/com/linecorp/armeria/xds/it/XdsResourceReader.java
  • it/xds-client/src/test/java/com/linecorp/armeria/xds/it/PipeEndpointTest.java
  • it/xds-istio/build.gradle
  • it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/GrpcProxylessPodCustomizer.java
  • it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/IstioPodCustomizer.java
  • it/xds-istio/src/main/java/com/linecorp/armeria/it/istio/testing/K8sClusterHelper.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/EnvoyDebugTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/NoopXdsValidatorIndex.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsGrpcProxylessTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsNativeGrpcProxylessTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsResourceReader.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/filter/IstioNoOpFilterFactories.java
  • it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.filter.HttpFilterFactory
  • it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.validator.XdsValidatorIndex
  • settings.gradle
  • xds-api/build.gradle
  • xds/build.gradle
  • xds/src/main/java/com/linecorp/armeria/xds/CertificateValidationContextSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/EndpointSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/ListenerSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java
  • xds/src/main/java/com/linecorp/armeria/xds/RouteEntry.java
  • xds/src/main/java/com/linecorp/armeria/xds/RouteSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/Snapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/SnapshotUtil.java
  • xds/src/main/java/com/linecorp/armeria/xds/TlsCertificateSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketMatchSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketStream.java
  • xds/src/main/java/com/linecorp/armeria/xds/VirtualHostSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsEndpointUtil.java
  • xds/src/main/java/com/linecorp/armeria/xds/client/endpoint/XdsHealthCheckedEndpointGroupBuilder.java
💤 Files with no reviewable changes (3)
  • xds-api/build.gradle
  • xds/build.gradle
  • it/xds-client/build.gradle

Comment thread core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java
Comment thread it/xds-istio/build.gradle Outdated
Comment thread it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsResourceReader.java Outdated
Comment thread xds/src/main/java/com/linecorp/armeria/xds/VirtualHostSnapshot.java
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 43.33333% with 102 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.66%. Comparing base (8150425) to head (d2088a8).
⚠️ Report is 424 commits behind head on main.

Files with missing lines Patch % Lines
.../com/linecorp/armeria/xds/ListenerXdsResource.java 29.16% 15 Missing and 2 partials ⚠️
.../linecorp/armeria/xds/TransportSocketSnapshot.java 25.00% 10 Missing and 2 partials ⚠️
...java/com/linecorp/armeria/xds/ClusterSnapshot.java 0.00% 9 Missing ⚠️
...ava/com/linecorp/armeria/client/ClientTlsSpec.java 75.00% 3 Missing and 5 partials ⚠️
...eria/xds/CertificateValidationContextSnapshot.java 0.00% 7 Missing ⚠️
...main/java/com/linecorp/armeria/xds/RouteEntry.java 0.00% 7 Missing ⚠️
...a/it/istio/testing/GrpcProxylessPodCustomizer.java 62.50% 3 Missing and 3 partials ⚠️
...ava/com/linecorp/armeria/xds/ListenerSnapshot.java 0.00% 6 Missing ⚠️
...n/java/com/linecorp/armeria/xds/RouteSnapshot.java 0.00% 5 Missing ⚠️
.../com/linecorp/armeria/xds/VirtualHostSnapshot.java 0.00% 5 Missing ⚠️
... and 8 more
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6730      +/-   ##
============================================
- Coverage     74.46%   73.66%   -0.81%     
- Complexity    22234    24293    +2059     
============================================
  Files          1963     2194     +231     
  Lines         82437    91561    +9124     
  Branches      10764    11960    +1196     
============================================
+ Hits          61385    67444    +6059     
- Misses        15918    18415    +2497     
- Partials       5134     5702     +568     

☔ 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.

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 (1)
core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java (1)

90-91: Keep toString() aligned with overridable ALPN.

Now that alpnProtocols() can be overridden, Line 184 still prints the backing field instead of the effective ALPN set. This can make diagnostics misleading for subclasses that override ALPN.

Proposed diagnostic consistency fix
                           .add("tlsVersions", tlsVersions)
-                          .add("alpnProtocols", alpnProtocols)
+                          .add("alpnProtocols", alpnProtocols())
                           .add("ciphers", ciphers)

Also applies to: 181-185

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

In `@core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java` around
lines 90 - 91, The toString() implementation prints the backing field instead of
the overridable accessor; update toString() to call the alpnProtocols() method
(not the alpnProtocols field) so subclasses that override alpnProtocols() are
represented correctly—locate the toString() method in AbstractTlsSpec and
replace uses of the alpnProtocols field with a call to the alpnProtocols()
accessor (ensure any formatting/joins still operate on the returned Set).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java`:
- Around line 90-91: The toString() implementation prints the backing field
instead of the overridable accessor; update toString() to call the
alpnProtocols() method (not the alpnProtocols field) so subclasses that override
alpnProtocols() are represented correctly—locate the toString() method in
AbstractTlsSpec and replace uses of the alpnProtocols field with a call to the
alpnProtocols() accessor (ensure any formatting/joins still operate on the
returned Set).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3e5f7910-0bc2-4feb-89df-7ce193ef28df

📥 Commits

Reviewing files that changed from the base of the PR and between 75d6fe7 and 5d139ba.

📒 Files selected for processing (7)
  • core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java
  • core/src/main/java/com/linecorp/armeria/common/AbstractTlsSpec.java
  • it/xds-istio/build.gradle
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsResourceReader.java
  • xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java
✅ Files skipped from review due to trivial changes (1)
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java
🚧 Files skipped from review as they are similar to previous changes (4)
  • xds/src/main/java/com/linecorp/armeria/xds/ClusterSnapshot.java
  • it/xds-istio/build.gradle
  • core/src/main/java/com/linecorp/armeria/client/ClientTlsSpec.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java (1)

105-116: Minor: default endpointIdentificationAlgorithm("") is set unconditionally before the TLS-context branch.

The builder is initialized with endpointIdentificationAlgorithm("") (disabling hostname verification) and only re-enabled to "HTTPS" in the systemRootCerts branch. For the trustedCa != null path — which is the common SDS-provisioned case — this silently disables hostname verification even when a proper trust anchor is configured. If that's the intended behavior for xDS transport sockets (where SANs are matched via peerVerifierFactories derived from match_typed_subject_alt_names), a brief comment explaining the rationale would help future readers; otherwise consider enabling "HTTPS" whenever SAN matching isn't expressed via verifier factories.

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

In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`
around lines 105 - 116, The ClientTlsSpec builder currently disables hostname
verification unconditionally by calling endpointIdentificationAlgorithm("") at
initialization in TransportSocketSnapshot.buildClientTlsSpec; change this so
hostname verification is enabled by default (set
endpointIdentificationAlgorithm("HTTPS") on the initial ClientTlsSpecBuilder)
and only override to "" in the specific branch where you intentionally want to
disable it (e.g., the systemRootCerts or other branch that explicitly derives
peer verifier factories), and ensure the trustedCa path does not leave
endpointIdentificationAlgorithm("") unintentionally; update the logic around
ClientTlsSpec.builder(), endpointIdentificationAlgorithm("..."), and the
branches that handle systemRootCerts, trustedCa, and validationContext so the
default is "HTTPS" unless a branch explicitly requires disabling it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/filter/IstioFilterFactories.java`:
- Around line 30-35: Update the class Javadoc for IstioFilterFactories to remove
the claim that all implementations are no-op and to document that the IstioAlpn
factory returns a real HttpFilter which mutates request context state; keep note
that the other factories still return null from create() and are registered via
SPI for HttpFilterFactoryRegistry, and briefly describe the behavior difference
for IstioAlpn (i.e., it produces a filter that alters request context rather
than being silently skipped).
- Around line 69-77: The AlpnFilter currently only sets the ALPN override in
httpPreprocessor, so implement rpcPreprocessor() in the same AlpnFilter class to
mirror that behavior: in rpcPreprocessor() set
ctx.setAttr(XdsCommonUtil.ALPN_OVERRIDE_KEY, ImmutableSet.of("istio-h2",
"istio", "h2")) and then call and return delegate.execute(ctx, req) (use the
same delegate parameter names as in httpPreprocessor); ensure the method
signature matches XdsHttpFilter.rpcPreprocessor so gRPC/proxyless paths receive
the same istio.alpn override.
- Around line 102-120: The three classes EnvoyGzipCompressor,
EnvoyZstdCompressor, and EnvoyBrotliCompressor return non-canonical filter names
and must be consolidated: replace them with a single EnvoyCompressor class
(extending Base) whose filterName() returns "envoy.filters.http.compressor", and
update the SPI/service registration entry that currently lists the three classes
to reference the new EnvoyCompressor instead; ensure no other code expects the
old per-algorithm class names.

---

Nitpick comments:
In `@xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java`:
- Around line 105-116: The ClientTlsSpec builder currently disables hostname
verification unconditionally by calling endpointIdentificationAlgorithm("") at
initialization in TransportSocketSnapshot.buildClientTlsSpec; change this so
hostname verification is enabled by default (set
endpointIdentificationAlgorithm("HTTPS") on the initial ClientTlsSpecBuilder)
and only override to "" in the specific branch where you intentionally want to
disable it (e.g., the systemRootCerts or other branch that explicitly derives
peer verifier factories), and ensure the trustedCa path does not leave
endpointIdentificationAlgorithm("") unintentionally; update the logic around
ClientTlsSpec.builder(), endpointIdentificationAlgorithm("..."), and the
branches that handle systemRootCerts, trustedCa, and validationContext so the
default is "HTTPS" unless a branch explicitly requires disabling it.
🪄 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: d0b69fe5-8af6-430f-a84d-f51efea3c86c

📥 Commits

Reviewing files that changed from the base of the PR and between 19066d8 and c7d0a9a.

📒 Files selected for processing (6)
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/XdsClientToSidecarTest.java
  • it/xds-istio/src/test/java/com/linecorp/armeria/it/xds/filter/IstioFilterFactories.java
  • it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.filter.HttpFilterFactory
  • xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java
  • xds/src/main/java/com/linecorp/armeria/xds/TransportSocketSnapshot.java
  • xds/src/main/java/com/linecorp/armeria/xds/internal/XdsCommonUtil.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • it/xds-istio/src/test/resources/META-INF/services/com.linecorp.armeria.xds.filter.HttpFilterFactory
  • xds/src/main/java/com/linecorp/armeria/xds/ListenerXdsResource.java

@jrhee17 jrhee17 added this to the 1.39.0 milestone Apr 23, 2026
@jrhee17 jrhee17 marked this pull request as ready for review April 23, 2026 09:21
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.

1 participant