Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changes

- Protos are compiled with gRPC 1.62.3 / protobuf 3.25.X instead of the latest release. This ensures compatibility with a wider range of grpcio versions for better compatibility with other packages / libraries.
- Protos are compiled with gRPC 1.62.3 / protobuf 3.25.X instead of the latest release. This ensures compatibility with a wider range of grpcio versions for better compatibility with other packages / libraries ([#36](https://github.com/microsoft/durabletask-python/pull/36)) - by [@berndverst](https://github.com/berndverst)
- Http and grpc protocols and their secure variants are stripped from the host name parameter if provided. Secure mode is enabled if the protocol provided is https or grpcs ([#38](https://github.com/microsoft/durabletask-python/pull/38) - by [@berndverst)(https://github.com/berndverst)

### Updates

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Orchestrations can specify retry policies for activities and sub-orchestrations.

### Prerequisites

- Python 3.8
- Python 3.9
- A Durable Task-compatible sidecar, like [Dapr Workflow](https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-overview/)

### Installing the Durable Task Python client SDK
Expand Down
17 changes: 17 additions & 0 deletions durabletask/internal/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
# and should be deserialized as a SimpleNamespace
AUTO_SERIALIZED = "__durabletask_autoobject__"

SECURE_PROTOCOLS = ["https://", "grpcs://"]
INSECURE_PROTOCOLS = ["http://", "grpc://"]


def get_default_host_address() -> str:
return "localhost:4001"
Expand All @@ -27,6 +30,20 @@ def get_grpc_channel(
if host_address is None:
host_address = get_default_host_address()

for protocol in SECURE_PROTOCOLS:
if host_address.lower().startswith(protocol):
secure_channel = True
# remove the protocol from the host name
host_address = host_address[len(protocol):]
break

for protocol in INSECURE_PROTOCOLS:
if host_address.lower().startswith(protocol):
secure_channel = False
# remove the protocol from the host name
host_address = host_address[len(protocol):]
break

if secure_channel:
channel = grpc.secure_channel(host_address, grpc.ssl_channel_credentials())
else:
Expand Down
49 changes: 48 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from unittest.mock import patch
from unittest.mock import patch, ANY

from durabletask.internal.shared import (DefaultClientInterceptorImpl,
get_default_host_address,
Expand Down Expand Up @@ -39,3 +39,50 @@ def test_get_grpc_channel_with_metadata():
assert args[0] == mock_channel.return_value
assert isinstance(args[1], DefaultClientInterceptorImpl)
assert args[1]._metadata == METADATA


def test_grpc_channel_with_host_name_protocol_stripping():
with patch('grpc.insecure_channel') as mock_insecure_channel, patch(
'grpc.secure_channel') as mock_secure_channel:

host_name = "myserver.com:1234"

prefix = "grpc://"
get_grpc_channel(prefix + host_name, METADATA)
mock_insecure_channel.assert_called_with(host_name)

prefix = "http://"
get_grpc_channel(prefix + host_name, METADATA)
mock_insecure_channel.assert_called_with(host_name)

prefix = "HTTP://"
get_grpc_channel(prefix + host_name, METADATA)
mock_insecure_channel.assert_called_with(host_name)

prefix = "GRPC://"
get_grpc_channel(prefix + host_name, METADATA)
mock_insecure_channel.assert_called_with(host_name)

prefix = ""
get_grpc_channel(prefix + host_name, METADATA)
mock_insecure_channel.assert_called_with(host_name)

prefix = "grpcs://"
get_grpc_channel(prefix + host_name, METADATA)
mock_secure_channel.assert_called_with(host_name, ANY)

prefix = "https://"
get_grpc_channel(prefix + host_name, METADATA)
mock_secure_channel.assert_called_with(host_name, ANY)

prefix = "HTTPS://"
get_grpc_channel(prefix + host_name, METADATA)
mock_secure_channel.assert_called_with(host_name, ANY)

prefix = "GRPCS://"
get_grpc_channel(prefix + host_name, METADATA)
mock_secure_channel.assert_called_with(host_name, ANY)

prefix = ""
get_grpc_channel(prefix + host_name, METADATA, True)
mock_secure_channel.assert_called_with(host_name, ANY)
Loading