Skip to content

Commit cc19379

Browse files
authored
💥 Enable TLS if api key provided (#1229)
* enable TLS if api key provided * move check to bridge config call * whoops - assign target_url and tls_config * fix existing tests
1 parent 27096aa commit cc19379

File tree

6 files changed

+63
-6
lines changed

6 files changed

+63
-6
lines changed

‎temporalio/client.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ async def connect(
125125
default_workflow_query_reject_condition: Optional[
126126
temporalio.common.QueryRejectCondition
127127
] = None,
128-
tls: Union[bool, TLSConfig] = False,
128+
tls: Union[bool, TLSConfig, None] = None,
129129
retry_config: Optional[RetryConfig] = None,
130130
keep_alive_config: Optional[KeepAliveConfig] = KeepAliveConfig.default,
131131
rpc_metadata: Mapping[str, Union[str, bytes]] = {},
@@ -166,9 +166,11 @@ async def connect(
166166
condition for workflow queries if not set during query. See
167167
:py:meth:`WorkflowHandle.query` for details on the rejection
168168
condition.
169-
tls: If false, the default, do not use TLS. If true, use system
170-
default TLS configuration. If TLS configuration present, that
171-
TLS configuration will be used.
169+
tls: If ``None``, the default, TLS will be enabled automatically
170+
when ``api_key`` is provided, otherwise TLS is disabled. If
171+
``False``, do not use TLS. If ``True``, use system default TLS
172+
configuration. If TLS configuration present, that TLS
173+
configuration will be used.
172174
retry_config: Retry configuration for direct service calls (when
173175
opted in) or all high-level calls made by this client (which all
174176
opt-in to retries by default). If unset, a default retry

‎temporalio/service.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class ConnectConfig:
136136

137137
target_host: str
138138
api_key: Optional[str] = None
139-
tls: Union[bool, TLSConfig] = False
139+
tls: Union[bool, TLSConfig, None] = None
140140
retry_config: Optional[RetryConfig] = None
141141
keep_alive_config: Optional[KeepAliveConfig] = KeepAliveConfig.default
142142
rpc_metadata: Mapping[str, Union[str, bytes]] = field(default_factory=dict)
@@ -172,6 +172,10 @@ def _to_bridge_config(self) -> temporalio.bridge.client.ClientConfig:
172172
elif self.tls:
173173
target_url = f"https://{self.target_host}"
174174
tls_config = TLSConfig()._to_bridge_config()
175+
# Enable TLS by default when API key is provided and tls not explicitly set
176+
elif self.tls is None and self.api_key is not None:
177+
target_url = f"https://{self.target_host}"
178+
tls_config = TLSConfig()._to_bridge_config()
175179
else:
176180
target_url = f"http://{self.target_host}"
177181
tls_config = None

‎tests/api/test_grpc_stub.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ async def test_grpc_metadata():
129129
f"localhost:{port}",
130130
api_key="my-api-key",
131131
rpc_metadata={"my-meta-key": "my-meta-val"},
132+
tls=False,
132133
)
133134
workflow_server.assert_last_metadata(
134135
{

‎tests/test_envconfig.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ async def test_e2e_multi_profile_different_client_connections(client: Client):
10241024
assert dev_client.service_client.config.target_host == target_host
10251025
assert dev_client.namespace == "dev"
10261026
assert dev_client.service_client.config.api_key is None
1027-
assert dev_client.service_client.config.tls is False
1027+
assert dev_client.service_client.config.tls is None
10281028

10291029
assert prod_client.service_client.config.target_host == target_host
10301030
assert prod_client.namespace == "prod"

‎tests/test_plugins.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ async def connect_service_client(
5656
next: Callable[[ConnectConfig], Awaitable[ServiceClient]],
5757
) -> ServiceClient:
5858
config.api_key = "replaced key"
59+
config.tls = False
5960
return await next(config)
6061

6162

‎tests/test_service.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,55 @@ async def test_grpc_status(client: Client, env: WorkflowEnvironment):
171171
)
172172

173173

174+
def test_connect_config_tls_enabled_by_default_when_api_key_provided():
175+
"""Test that TLS is enabled by default when API key is provided and tls is not configured."""
176+
config = temporalio.service.ConnectConfig(
177+
target_host="localhost:7233",
178+
api_key="test-api-key",
179+
)
180+
# TLS should be auto-enabled when api_key is provided and tls not explicitly set
181+
bridge_config = config._to_bridge_config()
182+
assert bridge_config.target_url == "https://localhost:7233"
183+
assert bridge_config.tls_config is not None
184+
185+
186+
def test_connect_config_tls_can_be_explicitly_disabled_even_when_api_key_provided():
187+
"""Test that TLS can be explicitly disabled even when API key is provided."""
188+
config = temporalio.service.ConnectConfig(
189+
target_host="localhost:7233",
190+
api_key="test-api-key",
191+
tls=False,
192+
)
193+
# TLS should remain disabled when explicitly set to False
194+
assert config.tls is False
195+
196+
197+
def test_connect_config_tls_disabled_by_default_when_no_api_key():
198+
"""Test that TLS is disabled by default when no API key is provided."""
199+
config = temporalio.service.ConnectConfig(
200+
target_host="localhost:7233",
201+
)
202+
# TLS should remain disabled when no api_key is provided
203+
bridge_config = config._to_bridge_config()
204+
assert bridge_config.target_url == "http://localhost:7233"
205+
assert bridge_config.tls_config is None
206+
207+
208+
def test_connect_config_tls_explicit_config_preserved():
209+
"""Test that explicit TLS configuration is preserved regardless of API key."""
210+
tls_config = temporalio.service.TLSConfig(
211+
server_root_ca_cert=b"test-cert",
212+
domain="test-domain",
213+
)
214+
config = temporalio.service.ConnectConfig(
215+
target_host="localhost:7233",
216+
api_key="test-api-key",
217+
tls=tls_config,
218+
)
219+
# Explicit TLS config should be preserved
220+
assert config.tls == tls_config
221+
222+
174223
async def test_rpc_execution_not_unknown(client: Client):
175224
"""
176225
Execute each rpc method and expect a failure, but ensure the failure is not that the rpc method is unknown

0 commit comments

Comments
 (0)