Skip to content

Commit 5151e94

Browse files
cupofcatgruebel
andauthored
feat(flagd): Add features to customize auth to Sync API servers (#203)
* feat(flagd): Add features to customize auth to Sync API servers Signed-off-by: Maks Osowski <[email protected]> * chore(flagd): Fix var names, type checking, and linting Signed-off-by: Maks Osowski <[email protected]> --------- Signed-off-by: Maks Osowski <[email protected]> Co-authored-by: Anton Grübel <[email protected]>
1 parent 6495dc0 commit 5151e94

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import typing
44
from enum import Enum
55

6+
import grpc
7+
68

79
class ResolverType(Enum):
810
RPC = "rpc"
@@ -45,9 +47,11 @@ class CacheType(Enum):
4547
ENV_VAR_RETRY_BACKOFF_MAX_MS = "FLAGD_RETRY_BACKOFF_MAX_MS"
4648
ENV_VAR_RETRY_GRACE_PERIOD_SECONDS = "FLAGD_RETRY_GRACE_PERIOD"
4749
ENV_VAR_SELECTOR = "FLAGD_SOURCE_SELECTOR"
50+
ENV_VAR_PROVIDER_ID = "FLAGD_SOURCE_PROVIDER_ID"
4851
ENV_VAR_STREAM_DEADLINE_MS = "FLAGD_STREAM_DEADLINE_MS"
4952
ENV_VAR_TLS = "FLAGD_TLS"
5053
ENV_VAR_TLS_CERT = "FLAGD_SERVER_CERT_PATH"
54+
ENV_VAR_DEFAULT_AUTHORITY = "FLAGD_DEFAULT_AUTHORITY"
5155

5256
T = typing.TypeVar("T")
5357

@@ -81,6 +85,7 @@ def __init__( # noqa: PLR0913
8185
port: typing.Optional[int] = None,
8286
tls: typing.Optional[bool] = None,
8387
selector: typing.Optional[str] = None,
88+
provider_id: typing.Optional[str] = None,
8489
resolver: typing.Optional[ResolverType] = None,
8590
offline_flag_source_path: typing.Optional[str] = None,
8691
offline_poll_interval_ms: typing.Optional[int] = None,
@@ -93,6 +98,8 @@ def __init__( # noqa: PLR0913
9398
cache: typing.Optional[CacheType] = None,
9499
max_cache_size: typing.Optional[int] = None,
95100
cert_path: typing.Optional[str] = None,
101+
default_authority: typing.Optional[str] = None,
102+
channel_credentials: typing.Optional[grpc.ChannelCredentials] = None,
96103
):
97104
self.host = env_or_default(ENV_VAR_HOST, DEFAULT_HOST) if host is None else host
98105

@@ -227,3 +234,17 @@ def __init__( # noqa: PLR0913
227234
self.selector = (
228235
env_or_default(ENV_VAR_SELECTOR, None) if selector is None else selector
229236
)
237+
238+
self.provider_id = (
239+
env_or_default(ENV_VAR_PROVIDER_ID, None)
240+
if provider_id is None
241+
else provider_id
242+
)
243+
244+
self.default_authority = (
245+
env_or_default(ENV_VAR_DEFAULT_AUTHORITY, None)
246+
if default_authority is None
247+
else default_authority
248+
)
249+
250+
self.channel_credentials = channel_credentials

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/provider.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import typing
2525
import warnings
2626

27+
import grpc
28+
2729
from openfeature.evaluation_context import EvaluationContext
2830
from openfeature.event import ProviderEventDetails
2931
from openfeature.flag_evaluation import FlagResolutionDetails
@@ -50,6 +52,7 @@ def __init__( # noqa: PLR0913
5052
timeout: typing.Optional[int] = None,
5153
retry_backoff_ms: typing.Optional[int] = None,
5254
selector: typing.Optional[str] = None,
55+
provider_id: typing.Optional[str] = None,
5356
resolver_type: typing.Optional[ResolverType] = None,
5457
offline_flag_source_path: typing.Optional[str] = None,
5558
stream_deadline_ms: typing.Optional[int] = None,
@@ -59,6 +62,8 @@ def __init__( # noqa: PLR0913
5962
retry_backoff_max_ms: typing.Optional[int] = None,
6063
retry_grace_period: typing.Optional[int] = None,
6164
cert_path: typing.Optional[str] = None,
65+
default_authority: typing.Optional[str] = None,
66+
channel_credentials: typing.Optional[grpc.ChannelCredentials] = None,
6267
):
6368
"""
6469
Create an instance of the FlagdProvider
@@ -91,13 +96,16 @@ def __init__( # noqa: PLR0913
9196
retry_backoff_max_ms=retry_backoff_max_ms,
9297
retry_grace_period=retry_grace_period,
9398
selector=selector,
99+
provider_id=provider_id,
94100
resolver=resolver_type,
95101
offline_flag_source_path=offline_flag_source_path,
96102
stream_deadline_ms=stream_deadline_ms,
97103
keep_alive_time=keep_alive_time,
98104
cache=cache,
99105
max_cache_size=max_cache_size,
100106
cert_path=cert_path,
107+
default_authority=default_authority,
108+
channel_credentials=channel_credentials,
101109
)
102110
self.enriched_context: dict = {}
103111

providers/openfeature-provider-flagd/src/openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def __init__(
4242
self.streamline_deadline_seconds = config.stream_deadline_ms * 0.001
4343
self.deadline = config.deadline_ms * 0.001
4444
self.selector = config.selector
45+
self.provider_id = config.provider_id
4546
self.emit_provider_ready = emit_provider_ready
4647
self.emit_provider_error = emit_provider_error
4748
self.emit_provider_stale = emit_provider_stale
@@ -55,13 +56,23 @@ def __init__(
5556
def _generate_channel(self, config: Config) -> grpc.Channel:
5657
target = f"{config.host}:{config.port}"
5758
# Create the channel with the service config
58-
options = [
59+
options: list[tuple[str, typing.Any]] = [
5960
("grpc.keepalive_time_ms", config.keep_alive_time),
6061
("grpc.initial_reconnect_backoff_ms", config.retry_backoff_ms),
6162
("grpc.max_reconnect_backoff_ms", config.retry_backoff_max_ms),
6263
("grpc.min_reconnect_backoff_ms", config.stream_deadline_ms),
6364
]
64-
if config.tls:
65+
if config.default_authority is not None:
66+
options.append(("grpc.default_authority", config.default_authority))
67+
68+
if config.channel_credentials is not None:
69+
channel_args = {
70+
"options": options,
71+
"credentials": config.channel_credentials,
72+
}
73+
channel = grpc.secure_channel(target, **channel_args)
74+
75+
elif config.tls:
6576
channel_args = {
6677
"options": options,
6778
"credentials": grpc.ssl_channel_credentials(),
@@ -157,7 +168,11 @@ def listen(self) -> None:
157168
if self.streamline_deadline_seconds > 0
158169
else {}
159170
)
160-
request_args = {"selector": self.selector} if self.selector is not None else {}
171+
request_args = {}
172+
if self.selector is not None:
173+
request_args["selector"] = self.selector
174+
if self.provider_id is not None:
175+
request_args["provider_id"] = self.provider_id
161176

162177
while self.active:
163178
try:

0 commit comments

Comments
 (0)