From 50951d145efe7b04d9e7fc2e33772aa42f4bb40b Mon Sep 17 00:00:00 2001 From: nicornk Date: Tue, 3 Mar 2026 16:13:36 +0100 Subject: [PATCH 1/3] feat: add api_me_scope to MultipassClient for me/scope endpoint Co-Authored-By: Claude Opus 4.6 --- .../src/foundry_dev_tools/clients/multipass.py | 12 ++++++++++++ tests/integration/clients/test_multipass.py | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py index e62dfbf9..4e2d10c2 100644 --- a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py +++ b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py @@ -95,6 +95,18 @@ def api_me(self, **kwargs) -> requests.Response: **kwargs, ) + def api_me_scope(self, **kwargs) -> requests.Response: + """Gets the current user's scope. + + Args: + **kwargs: gets passed to :py:meth:`APIClient.api_request` + """ + return self.api_request( + "GET", + "me/scope", + **kwargs, + ) + def search( self, query: str, principal_types: set[api_types.PrincipalTypes] | None = None, **kwargs ) -> Iterator[dict]: diff --git a/tests/integration/clients/test_multipass.py b/tests/integration/clients/test_multipass.py index fd3895ce..1bee28f9 100644 --- a/tests/integration/clients/test_multipass.py +++ b/tests/integration/clients/test_multipass.py @@ -45,6 +45,15 @@ def _tear_down(): raise +def test_me_scope(): + resp = TEST_SINGLETON.ctx.multipass.api_me_scope() + + assert resp.status_code == 200 + + scope = resp.json() + assert isinstance(scope, dict) + + def test_organizations(): user_info = TEST_SINGLETON.ctx.multipass.get_user_info() From b20c3f271d8763963564e92e1fe81155e8c650b9 Mon Sep 17 00:00:00 2001 From: nicornk Date: Tue, 3 Mar 2026 16:28:46 +0100 Subject: [PATCH 2/3] docs: document api_me_scope response structure and add type assertion to test Co-Authored-By: Claude Opus 4.6 --- .../foundry_dev_tools/clients/multipass.py | 35 +++++++++++++++++++ tests/integration/clients/test_multipass.py | 2 ++ 2 files changed, 37 insertions(+) diff --git a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py index 4e2d10c2..7ea52988 100644 --- a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py +++ b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py @@ -100,6 +100,41 @@ def api_me_scope(self, **kwargs) -> requests.Response: Args: **kwargs: gets passed to :py:meth:`APIClient.api_request` + + Returns: + :py:class:`requests.Response`: + The response JSON is a recursive scope structure with a ``type`` field. + + .. code-block:: python + + # User token: + {"type": "universal"} + + # Scoped token (e.g. TPA with authorization_code grant): + { + "type": "union", + "scopes": [ + { + "type": "intersection", + "scopes": [ + {"type": "operation", "operations": ["api:read-data", ...]}, + {"type": "operation", "operations": ["api:read-data", ...]}, + ], + }, + { + "type": "intersection", + "scopes": [ + { + "type": "resource", + "resourceIds": ["ri.multipass..organization.root"], + "includeChildren": True, + }, + {"type": "operation", "operations": ["organization:discover", ...]}, + ], + }, + ], + } + """ return self.api_request( "GET", diff --git a/tests/integration/clients/test_multipass.py b/tests/integration/clients/test_multipass.py index 1bee28f9..1cf4c33a 100644 --- a/tests/integration/clients/test_multipass.py +++ b/tests/integration/clients/test_multipass.py @@ -52,6 +52,8 @@ def test_me_scope(): scope = resp.json() assert isinstance(scope, dict) + assert "type" in scope + assert scope["type"] in ("universal", "union", "intersection", "operation", "resource") def test_organizations(): From 59de943aa318890e7114b3ce10e9d42cc7554d56 Mon Sep 17 00:00:00 2001 From: nicornk Date: Tue, 3 Mar 2026 16:34:27 +0100 Subject: [PATCH 3/3] style: use plain requests.Response in docstring for consistency Co-Authored-By: Claude Opus 4.6 --- .../src/foundry_dev_tools/clients/multipass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py index 7ea52988..515c7ac9 100644 --- a/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py +++ b/libs/foundry-dev-tools/src/foundry_dev_tools/clients/multipass.py @@ -102,7 +102,7 @@ def api_me_scope(self, **kwargs) -> requests.Response: **kwargs: gets passed to :py:meth:`APIClient.api_request` Returns: - :py:class:`requests.Response`: + requests.Response: The response JSON is a recursive scope structure with a ``type`` field. .. code-block:: python