From c152d099ecf206cfc871152df8b1f182d2ae4e43 Mon Sep 17 00:00:00 2001 From: pbrassel <52356233+pbrassel@users.noreply.github.com> Date: Mon, 7 Sep 2026 17:14:52 +0200 Subject: [PATCH 1/5] fix!: `scope` and `root_url` were removed and `backchannel_logout_uri` and `post_logout_uri` were added for clients BREAKING CHANGE: The `Client` model changed. --- flame_hub/_auth_client.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/flame_hub/_auth_client.py b/flame_hub/_auth_client.py index 798f1de..1216501 100644 --- a/flame_hub/_auth_client.py +++ b/flame_hub/_auth_client.py @@ -194,6 +194,8 @@ class CreateClient(AuthBaseModel): grant_types: str | None auth_method: ClientAuthMethod token_binding_method: ClientTokenBindingMethod + backchannel_logout_uri: str | None + post_logout_redirect_uri: str | None realm_id: t.Annotated[uuid.UUID, Field(), WrapValidator(uuid_validator)] @@ -208,9 +210,9 @@ class Client(AuthBaseModel): secret_hashed: bool grant_types: str | None secret_encrypted: bool - scope: str | None + backchannel_logout_uri: str | None + post_logout_redirect_uri: str | None base_url: str | None - root_url: str | None auth_method: ClientAuthMethod token_binding_method: ClientTokenBindingMethod created_at: datetime @@ -231,6 +233,8 @@ class UpdateClient(AuthBaseModel): grant_types: str | None | UNSET_T = UNSET auth_method: ClientAuthMethod | UNSET_T = UNSET token_binding_method: ClientTokenBindingMethod | UNSET_T = UNSET + backchannel_logout_uri: str | None | UNSET_T = UNSET + post_logout_redirect_uri: str | None | UNSET_T = UNSET class AuthClient(BaseClient): @@ -605,6 +609,8 @@ def create_client( grant_types: str | None = None, auth_method: ClientAuthMethod = "secret", token_binding_method: ClientTokenBindingMethod = "none", + post_logout_redirect_uri: str | None = None, + backchannel_logout_uri: str | None = None, **params: te.Unpack[BaseKwargs], ) -> Client: return self._create_resource( @@ -622,6 +628,8 @@ def create_client( grant_types=grant_types, auth_method=auth_method, token_binding_method=token_binding_method, + post_logout_redirect_uri=post_logout_redirect_uri, + backchannel_logout_uri=backchannel_logout_uri, ), "clients", **params, @@ -657,6 +665,8 @@ def update_client( grant_types: str | None | UNSET_T = UNSET, auth_method: ClientAuthMethod | UNSET_T = UNSET, token_binding_method: ClientTokenBindingMethod | UNSET_T = UNSET, + post_logout_redirect_uri: str | None | UNSET_T = UNSET, + backchannel_logout_uri: str | None | UNSET_T = UNSET, **params: te.Unpack[BaseKwargs], ) -> Client: return self._update_resource( @@ -673,6 +683,8 @@ def update_client( grant_types=grant_types, auth_method=auth_method, token_binding_method=token_binding_method, + post_logout_redirect_uri=post_logout_redirect_uri, + backchannel_logout_uri=backchannel_logout_uri, ), "clients", client_id, From 8eb5b0c7862dc0d51c70b39c3b3446021ce54c1a Mon Sep 17 00:00:00 2001 From: pbrassel <52356233+pbrassel@users.noreply.github.com> Date: Mon, 7 Sep 2026 17:20:49 +0200 Subject: [PATCH 2/5] test: associated resources are now included for project nodes, analysis nodes and analysis bucket files --- tests/test_core.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 1ac691e..1190841 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -402,7 +402,6 @@ def test_find_project_nodes(core_client, project_node, project_node_includables) ) -@pytest.mark.xfail(reason="node and project are not included in this case") def test_get_project_node(core_client, project_node, project_node_includables): project_node_get = core_client.get_project_node(project_node.id) @@ -561,7 +560,6 @@ def test_find_analysis_nodes(core_client, analysis_node, analysis_node_includabl ) -@pytest.mark.xfail(reason="node and analysis are not included in this case") def test_get_analysis_node(core_client, analysis_node, analysis_node_includables): analysis_node_get = core_client.get_analysis_node(analysis_node.id) @@ -640,7 +638,6 @@ def test_find_analysis_buckets(core_client, analysis_code_bucket, analysis_bucke ) -@pytest.mark.xfail(reason="analysis and analysis bucket are not included in this case") def test_get_analysis_bucket_file(core_client, analysis_bucket_file, analysis_bucket_file_includables): analysis_bucket_file_get = core_client.get_analysis_bucket_file(analysis_bucket_file.id) From 9160cd136ed11d287071d5347290e430fef077f6 Mon Sep 17 00:00:00 2001 From: pbrassel <52356233+pbrassel@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:17:36 +0200 Subject: [PATCH 3/5] test: fix auth flow error message and code --- tests/test_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_flow.py b/tests/test_flow.py index f2397b3..fa2d77a 100644 --- a/tests/test_flow.py +++ b/tests/test_flow.py @@ -96,7 +96,7 @@ def test_password_auth_reissue_raise_error(password_auth, auth_base_url): with pytest.raises(HubAPIError) as e: new_client.get(auth_base_url) - assert "The JWT is invalid" in str(e.value) + assert "invalid_grant" in str(e.value) assert e.value.error_response.status_code == httpx.codes.BAD_REQUEST.value @@ -128,4 +128,4 @@ def test_static_auth_raise_error(auth_base_url): client.get_users() assert "The JWT is invalid" in str(e.value) - assert e.value.error_response.status_code == httpx.codes.BAD_REQUEST.value + assert e.value.error_response.status_code == httpx.codes.UNAUTHORIZED.value From 05ba4bb63c3aeca8bae119b7c32ad4261788300c Mon Sep 17 00:00:00 2001 From: pbrassel <52356233+pbrassel@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:19:37 +0200 Subject: [PATCH 4/5] chore: bump tested hub version --- .env.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.test b/.env.test index 90c9caa..6ad347f 100644 --- a/.env.test +++ b/.env.test @@ -7,5 +7,5 @@ PYTEST_ADMIN_PASSWORD=start123 PYTEST_DEFAULT_MASTER_IMAGE=python/base PYTEST_ASYNC_MAX_RETRIES=5 PYTEST_ASYNC_RETRY_DELAY_MILLIS=500 -PYTEST_HUB_VERSION=0.13.0 +PYTEST_HUB_VERSION=0.15.0 PYTEST_RESPONSE_TIMEOUT=5 From 7c856f1c2126fb8fbb72117d684db83bb62b6ee9 Mon Sep 17 00:00:00 2001 From: pbrassel <52356233+pbrassel@users.noreply.github.com> Date: Tue, 8 Sep 2026 10:31:07 +0200 Subject: [PATCH 5/5] docs: update error response example --- docs/user_guide.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 5d90d5e..e36a091 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -379,11 +379,12 @@ possible, including status code and additional information in the response body. .. code-block:: console - received status code 400 (undefined): Can't find realm entity by realmId + received status code 500 (internal_error): Can't find realm entity by realmId { - "status_code": 400, - "code": "undefined", - "message": "Can't find realm entity by realmId" + "code": "internal_error", + "status_code": 500, + "message": "Can't find realm entity by realmId", + "issues": [] } In this example a :py:exc:`.HubAPIError` is raised because there is no realm with an ID that matches the dynamically