Skip to content

Commit

Permalink
fix(python): Fix URL formatting + authorized key (#2707)
Browse files Browse the repository at this point in the history
* feat: Add api_key options to be able to use authentication when calling the relay proxy

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>

* fix: formatting URL was broken

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>

---------

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
  • Loading branch information
thomaspoignant authored Nov 23, 2024
1 parent 0fcbe58 commit 924c691
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,14 @@ def _collect_data(self):
meta={"provider": "open-feature-python-sdk"},
events=self._event_queue,
)
headers = {"Content-Type": "application/json"}
if self._options.api_key:
headers["Authorization"] = "Bearer {}".format(self._options.api_key)

response = self._http_client.request(
method="POST",
url=urljoin(str(self._options.endpoint), "/v1/data/collector"),
headers={"Content-Type": "application/json"},
headers=headers,
body=goff_request.model_dump_json(),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ class GoFeatureFlagOptions(BaseModel):
# config changes.
# default: false
disable_cache_invalidation: typing.Optional[bool] = False

# api_key (optional) If the relay proxy is configured to authenticate the requests, you should provide
# an API Key to the provider. Please ask the administrator of the relay proxy to provide an API Key.
# Default: None
api_key: typing.Optional[str] = None
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,18 @@ def generic_go_feature_flag_resolver(
response_body = self._cache[evaluation_context_hash]
is_from_cache = True
else:
headers = {"Content-Type": "application/json"}
if self.options.api_key is not None:
headers["Authorization"] = "Bearer {}".format(self.options.api_key)
url = "{}{}".format(
str(self.options.endpoint).rstrip("/"),
"/v1/feature/{}/eval".format(flag_key),
)

response = self._http_client.request(
method="POST",
url=urljoin(
str(self.options.endpoint),
"/v1/feature/{}/eval".format(flag_key),
),
headers={"Content-Type": "application/json"},
url=url,
headers=headers,
body=goff_request.model_dump_json(),
)

Expand Down Expand Up @@ -261,10 +266,15 @@ def _build_websocket_uri(self):
_build_websocket_uri is a helper to build the websocket uri to connect to the GO Feature Flag relay proxy.
:return: a string representing the websocket uri
"""
http_uri = urljoin(
str(self.options.endpoint),
"/ws/v1/flag/change",
url = "/ws/v1/flag/change"
if self.options.api_key is not None:
url = "{}?apiKey={}".format(url, self.options.api_key)

http_uri = "{}{}".format(
str(self.options.endpoint).rstrip("/"),
url,
)

http_uri = http_uri.replace("http", "ws")
http_uri = http_uri.replace("https", "wss")
return http_uri
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ services:
- POLLINGINTERVAL=1000
- RETRIEVER_KIND=file
- RETRIEVER_PATH=/config.goff.yaml
- AUTHORIZEDKEYS_EVALUATION=apikey1
volumes:
- ./config.goff.yaml:/config.goff.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def _generic_test(
endpoint="https://gofeatureflag.org/",
data_flush_interval=100,
disable_cache_invalidation=True,
api_key="apikey1",
),
)
api.set_provider(goff_provider)
Expand Down Expand Up @@ -610,6 +611,31 @@ def _create_hook_context():
assert len(hook._event_queue) == 1


@patch("urllib3.poolmanager.PoolManager.request")
def test_url_parsing(mock_request):
flag_key = "bool_targeting_match"
mock_request.return_value = Mock(status="200", data=_read_mock_file(flag_key))
default_value = False
goff_provider = GoFeatureFlagProvider(
options=GoFeatureFlagOptions(
endpoint="https://gofeatureflag.org/ff/",
data_flush_interval=100,
disable_cache_invalidation=True,
api_key="apikey1",
),
)
api.set_provider(goff_provider)
client = api.get_client(domain="test-client")
t = client.get_boolean_details(
flag_key=flag_key,
default_value=default_value,
evaluation_context=_default_evaluation_ctx,
)
got = mock_request.call_args[1]["url"]
want = "https://gofeatureflag.org/ff/v1/feature/bool_targeting_match/eval"
assert got == want


def _read_mock_file(flag_key: str) -> str:
# This hacky if is here to make test run inside pycharm and from the root of the project
if os.getcwd().endswith("/tests"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def test_test_websocket_cache_invalidation(goff):
endpoint=goff,
data_flush_interval=100,
disable_data_collection=True,
api_key="apikey1",
)
)
api.set_provider(goff_provider)
Expand Down

0 comments on commit 924c691

Please sign in to comment.