Skip to content

Commit 1ce12f2

Browse files
committed
make enableHttps a Boolean
1 parent 36fae11 commit 1ce12f2

File tree

2 files changed

+145
-38
lines changed

2 files changed

+145
-38
lines changed

temporal-serviceclient/src/main/java/io/temporal/serviceclient/ServiceStubsOptions.java

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,14 @@ public class ServiceStubsOptions {
3939

4040
protected final @Nullable Consumer<ManagedChannelBuilder<?>> channelInitializer;
4141

42-
/** Indicates whether basic HTTPS/SSL/TLS should be enabled * */
43-
protected final boolean enableHttps;
42+
/**
43+
* Indicates whether basic HTTPS/SSL/TLS should be enabled. Null means not explicitly set by the
44+
* user, allowing runtime derivation of the effective value.
45+
*/
46+
protected final Boolean enableHttps;
47+
48+
/** Indicates whether an API key was provided, used for automatic TLS enablement */
49+
protected final boolean apiKeyProvided;
4450

4551
/** The user provided context for SSL/TLS over gRPC * */
4652
protected final SslContext sslContext;
@@ -113,6 +119,7 @@ public class ServiceStubsOptions {
113119
this.target = that.target;
114120
this.channelInitializer = that.channelInitializer;
115121
this.enableHttps = that.enableHttps;
122+
this.apiKeyProvided = that.apiKeyProvided;
116123
this.sslContext = that.sslContext;
117124
this.healthCheckAttemptTimeout = that.healthCheckAttemptTimeout;
118125
this.systemInfoTimeout = that.systemInfoTimeout;
@@ -134,7 +141,8 @@ public class ServiceStubsOptions {
134141
ManagedChannel channel,
135142
String target,
136143
@Nullable Consumer<ManagedChannelBuilder<?>> channelInitializer,
137-
boolean enableHttps,
144+
Boolean enableHttps,
145+
boolean apiKeyProvided,
138146
SslContext sslContext,
139147
Duration healthCheckAttemptTimeout,
140148
Duration healthCheckTimeout,
@@ -154,6 +162,7 @@ public class ServiceStubsOptions {
154162
this.target = target;
155163
this.channelInitializer = channelInitializer;
156164
this.enableHttps = enableHttps;
165+
this.apiKeyProvided = apiKeyProvided;
157166
this.sslContext = sslContext;
158167
this.healthCheckAttemptTimeout = healthCheckAttemptTimeout;
159168
this.healthCheckTimeout = healthCheckTimeout;
@@ -202,11 +211,23 @@ public Consumer<ManagedChannelBuilder<?>> getChannelInitializer() {
202211
}
203212

204213
/**
205-
* @return if gRPC should use SSL/TLS; Ignored and assumed {@code true} if {@link
206-
* #getSslContext()} is set
214+
* Returns whether gRPC should use SSL/TLS. This method computes the effective value based on:
215+
*
216+
* <ul>
217+
* <li>If explicitly set via {@link Builder#setEnableHttps(boolean)}, returns that value
218+
* <li>If an API key was provided and no custom SSL context or channel is set, returns {@code
219+
* true}
220+
* <li>Otherwise returns {@code false}
221+
* </ul>
222+
*
223+
* <p>Note: This is ignored and assumed {@code true} if {@link #getSslContext()} is set.
224+
*
225+
* @return if gRPC should use SSL/TLS
207226
*/
208227
public boolean getEnableHttps() {
209-
return enableHttps;
228+
return (enableHttps != null)
229+
? enableHttps
230+
: (apiKeyProvided && sslContext == null && channel == null);
210231
}
211232

212233
/**
@@ -325,12 +346,13 @@ public boolean equals(Object o) {
325346
if (this == o) return true;
326347
if (o == null || getClass() != o.getClass()) return false;
327348
ServiceStubsOptions that = (ServiceStubsOptions) o;
328-
return enableHttps == that.enableHttps
349+
return apiKeyProvided == that.apiKeyProvided
329350
&& enableKeepAlive == that.enableKeepAlive
330351
&& keepAlivePermitWithoutStream == that.keepAlivePermitWithoutStream
331352
&& Objects.equals(channel, that.channel)
332353
&& Objects.equals(target, that.target)
333354
&& Objects.equals(channelInitializer, that.channelInitializer)
355+
&& Objects.equals(enableHttps, that.enableHttps)
334356
&& Objects.equals(sslContext, that.sslContext)
335357
&& Objects.equals(healthCheckAttemptTimeout, that.healthCheckAttemptTimeout)
336358
&& Objects.equals(healthCheckTimeout, that.healthCheckTimeout)
@@ -353,6 +375,7 @@ public int hashCode() {
353375
target,
354376
channelInitializer,
355377
enableHttps,
378+
apiKeyProvided,
356379
sslContext,
357380
healthCheckAttemptTimeout,
358381
healthCheckTimeout,
@@ -382,6 +405,8 @@ public String toString() {
382405
+ channelInitializer
383406
+ ", enableHttps="
384407
+ enableHttps
408+
+ ", apiKeyProvided="
409+
+ apiKeyProvided
385410
+ ", sslContext="
386411
+ sslContext
387412
+ ", healthCheckAttemptTimeout="
@@ -444,6 +469,7 @@ protected Builder(ServiceStubsOptions options) {
444469
this.target = options.target;
445470
this.channelInitializer = options.channelInitializer;
446471
this.enableHttps = options.enableHttps;
472+
this.apiKeyProvided = options.apiKeyProvided;
447473
this.sslContext = options.sslContext;
448474
this.healthCheckAttemptTimeout = options.healthCheckAttemptTimeout;
449475
this.healthCheckTimeout = options.healthCheckTimeout;
@@ -456,8 +482,15 @@ protected Builder(ServiceStubsOptions options) {
456482
this.connectionBackoffResetFrequency = options.connectionBackoffResetFrequency;
457483
this.grpcReconnectFrequency = options.grpcReconnectFrequency;
458484
this.headers = options.headers;
459-
this.grpcMetadataProviders = options.grpcMetadataProviders;
460-
this.grpcClientInterceptors = options.grpcClientInterceptors;
485+
// Make mutable copies of collections to allow adding more items
486+
this.grpcMetadataProviders =
487+
options.grpcMetadataProviders != null && !options.grpcMetadataProviders.isEmpty()
488+
? new ArrayList<>(options.grpcMetadataProviders)
489+
: null;
490+
this.grpcClientInterceptors =
491+
options.grpcClientInterceptors != null && !options.grpcClientInterceptors.isEmpty()
492+
? new ArrayList<>(options.grpcClientInterceptors)
493+
: null;
461494
this.metricsScope = options.metricsScope;
462495
}
463496

@@ -805,7 +838,8 @@ public ServiceStubsOptions build() {
805838
this.channel,
806839
this.target,
807840
this.channelInitializer,
808-
this.enableHttps != null ? this.enableHttps : false,
841+
this.enableHttps,
842+
this.apiKeyProvided,
809843
this.sslContext,
810844
this.healthCheckAttemptTimeout,
811845
this.healthCheckTimeout,
@@ -853,14 +887,6 @@ public ServiceStubsOptions validateAndBuildWithDefaults() {
853887
Collection<ClientInterceptor> grpcClientInterceptors =
854888
MoreObjects.firstNonNull(this.grpcClientInterceptors, Collections.emptyList());
855889

856-
// Resolve enableHttps: explicit value, auto-enable with API key, or default false
857-
boolean enableHttps = false;
858-
if (this.enableHttps != null) {
859-
enableHttps = this.enableHttps;
860-
} else if (this.apiKeyProvided && this.sslContext == null && this.channel == null) {
861-
enableHttps = true;
862-
}
863-
864890
Scope metricsScope = this.metricsScope != null ? this.metricsScope : new NoopScope();
865891
Duration healthCheckAttemptTimeout =
866892
this.healthCheckAttemptTimeout != null
@@ -875,7 +901,8 @@ public ServiceStubsOptions validateAndBuildWithDefaults() {
875901
this.channel,
876902
target,
877903
this.channelInitializer,
878-
enableHttps,
904+
this.enableHttps,
905+
this.apiKeyProvided,
879906
this.sslContext,
880907
healthCheckAttemptTimeout,
881908
healthCheckTimeout,

temporal-serviceclient/src/test/java/io/temporal/serviceclient/ServiceStubsOptionsTest.java

Lines changed: 99 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package io.temporal.serviceclient;
22

33
import static org.junit.Assert.*;
4-
import static org.mockito.Mockito.mock;
54

6-
import io.grpc.ManagedChannel;
7-
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
85
import org.junit.Test;
96

107
public class ServiceStubsOptionsTest {
@@ -68,33 +65,116 @@ public void testExplicitTLSEnableWithoutAPIKey() {
6865
}
6966

7067
@Test
71-
public void testTLSNotAutoEnabledWhenSslContextProvided() {
72-
// When user provides custom sslContext, they're handling TLS themselves
73-
// so enableHttps should not be auto-enabled
74-
SslContext sslContext = mock(SslContext.class);
75-
ServiceStubsOptions options =
68+
public void testBuilderFromOptionsPreservesDefaultTLSBehavior() {
69+
// Step 1: Create options with no API key and no TLS setting
70+
ServiceStubsOptions options1 =
7671
WorkflowServiceStubsOptions.newBuilder()
7772
.setTarget("localhost:7233")
73+
.validateAndBuildWithDefaults();
74+
75+
// Verify TLS is disabled (no API key)
76+
assertFalse(options1.getEnableHttps());
77+
78+
// Step 2: Create new builder from existing options and add API key
79+
ServiceStubsOptions options2 =
80+
WorkflowServiceStubsOptions.newBuilder(options1)
7881
.addApiKey(() -> "test-api-key")
79-
.setSslContext(sslContext)
8082
.validateAndBuildWithDefaults();
8183

82-
// enableHttps stays false because sslContext handles TLS
83-
assertFalse(options.getEnableHttps());
84-
assertNotNull(options.getSslContext());
84+
// TLS should auto-enable because user never explicitly set TLS=false,
85+
// even though options1 had enableHttps=false (derived, not explicit)
86+
assertTrue(
87+
"TLS should auto-enable when API key is added to builder from options that had default TLS behavior",
88+
options2.getEnableHttps());
8589
}
8690

8791
@Test
88-
public void testTLSNotAutoEnabledWhenCustomChannelProvided() {
89-
// When user provides custom channel, they're managing connection themselves
90-
// so enableHttps should not be auto-enabled
91-
ManagedChannel channel = mock(ManagedChannel.class);
92-
ServiceStubsOptions options =
92+
public void testBuilderFromOptionsWithExplicitTLSDisableStaysDisabled() {
93+
// Step 1: Create options with explicit TLS=false
94+
ServiceStubsOptions options1 =
9395
WorkflowServiceStubsOptions.newBuilder()
94-
.setChannel(channel)
96+
.setTarget("localhost:7233")
97+
.setEnableHttps(false)
98+
.validateAndBuildWithDefaults();
99+
100+
assertFalse(options1.getEnableHttps());
101+
102+
// Step 2: Create new builder from existing options and add API key
103+
ServiceStubsOptions options2 =
104+
WorkflowServiceStubsOptions.newBuilder(options1)
95105
.addApiKey(() -> "test-api-key")
96106
.validateAndBuildWithDefaults();
97107

98-
assertFalse(options.getEnableHttps());
108+
// TLS should stay disabled because user explicitly set TLS=false
109+
assertFalse(
110+
"TLS should stay disabled when explicitly set to false, even with API key",
111+
options2.getEnableHttps());
112+
}
113+
114+
@Test
115+
public void testBuilderFromOptionsWithExplicitTLSEnableStaysEnabled() {
116+
// Step 1: Create options with explicit TLS=true
117+
ServiceStubsOptions options1 =
118+
WorkflowServiceStubsOptions.newBuilder()
119+
.setTarget("localhost:7233")
120+
.setEnableHttps(true)
121+
.validateAndBuildWithDefaults();
122+
123+
assertTrue(options1.getEnableHttps());
124+
125+
// Step 2: Create new builder from existing options (no API key)
126+
ServiceStubsOptions options2 =
127+
WorkflowServiceStubsOptions.newBuilder(options1).validateAndBuildWithDefaults();
128+
129+
// TLS should stay enabled because user explicitly set TLS=true
130+
assertTrue("TLS should stay enabled when explicitly set to true", options2.getEnableHttps());
131+
}
132+
133+
@Test
134+
public void testSpringBootStyleAutoTLSWithApiKey() {
135+
ServiceStubsOptions options1 =
136+
WorkflowServiceStubsOptions.newBuilder()
137+
.setTarget("my-namespace.tmprl.cloud:7233")
138+
.addApiKey(() -> "my-api-key")
139+
.validateAndBuildWithDefaults();
140+
141+
assertTrue(
142+
"TLS should auto-enable when API key is provided without explicit TLS setting",
143+
options1.getEnableHttps());
144+
145+
// Scenario 2: API key provided, TLS explicitly enabled (should stay enabled)
146+
ServiceStubsOptions options2 =
147+
WorkflowServiceStubsOptions.newBuilder()
148+
.setTarget("my-namespace.tmprl.cloud:7233")
149+
.setEnableHttps(true)
150+
.addApiKey(() -> "my-api-key")
151+
.validateAndBuildWithDefaults();
152+
153+
assertTrue(
154+
"TLS should be enabled when explicitly set to true with API key",
155+
options2.getEnableHttps());
156+
157+
// Scenario 3: API key provided, TLS explicitly disabled (should stay disabled)
158+
ServiceStubsOptions options3 =
159+
WorkflowServiceStubsOptions.newBuilder()
160+
.setTarget("localhost:7233")
161+
.setEnableHttps(false)
162+
.addApiKey(() -> "my-api-key")
163+
.validateAndBuildWithDefaults();
164+
165+
assertFalse(
166+
"TLS should stay disabled when explicitly set to false, even with API key",
167+
options3.getEnableHttps());
168+
169+
// Scenario 4: No API key, no explicit TLS setting (should be disabled)
170+
ServiceStubsOptions options4 =
171+
WorkflowServiceStubsOptions.newBuilder()
172+
.setTarget("localhost:7233")
173+
// Note: No API key, no setEnableHttps()
174+
.validateAndBuildWithDefaults();
175+
176+
assertFalse(
177+
"TLS should be disabled when no API key and no explicit TLS setting",
178+
options4.getEnableHttps());
99179
}
100180
}

0 commit comments

Comments
 (0)