From 0bc22d21c5728e763dca0733c4cc77da110e0c10 Mon Sep 17 00:00:00 2001 From: saif <11242541+saifsmailbox98@users.noreply.github.com> Date: Mon, 2 Nov 2026 23:58:43 +0530 Subject: [PATCH] feat(agent-vault)!: sessions carry one accessBundle --- infisical_sdk/api_types.py | 22 +++++++++------------ infisical_sdk/resources/agent_vault.py | 4 ++-- tests/test_agent_vault.py | 27 ++++++++++++++++++++------ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/infisical_sdk/api_types.py b/infisical_sdk/api_types.py index f6896c2..7191e46 100644 --- a/infisical_sdk/api_types.py +++ b/infisical_sdk/api_types.py @@ -529,9 +529,8 @@ class AgentVaultSessionActor(BaseModel): @dataclass class AgentVaultSessionAccessBundle(BaseModel): - """An access bundle carried by an Agent Vault session""" + """The access bundle an Agent Vault session carries. id is None once the bundle is deleted.""" name: str - position: int id: Optional[str] = None @dataclass @@ -544,18 +543,16 @@ class AgentVaultSession(BaseModel): actor: Optional[AgentVaultSessionActor] = None expiresAt: Optional[str] = None revokedAt: Optional[str] = None - accessBundles: Optional[List[AgentVaultSessionAccessBundle]] = None + accessBundle: Optional[AgentVaultSessionAccessBundle] = None @classmethod def from_dict(cls, data: Dict) -> 'AgentVaultSession': - """Create model from dictionary with nested actor and access bundles. accessBundles is None if the response leaves it out.""" + """Create model from dictionary with nested actor and access bundle. accessBundle is None if the response leaves it out.""" session_data = data.copy() if data.get('actor') is not None: session_data['actor'] = AgentVaultSessionActor.from_dict(data['actor']) - if data.get('accessBundles') is not None: - session_data['accessBundles'] = [ - AgentVaultSessionAccessBundle.from_dict(bundle) for bundle in data['accessBundles'] - ] + if data.get('accessBundle') is not None: + session_data['accessBundle'] = AgentVaultSessionAccessBundle.from_dict(data['accessBundle']) return super().from_dict(session_data) @@ -567,15 +564,14 @@ class CreatedAgentVaultSession(BaseModel): createdAt: str label: Optional[str] = None expiresAt: Optional[str] = None - accessBundles: List[AgentVaultSessionAccessBundle] = field(default_factory=list) + accessBundle: Optional[AgentVaultSessionAccessBundle] = None @classmethod def from_dict(cls, data: Dict) -> 'CreatedAgentVaultSession': - """Create model from dictionary with nested access bundles""" + """Create model from dictionary with nested access bundle""" session_data = data.copy() - session_data['accessBundles'] = [ - AgentVaultSessionAccessBundle.from_dict(bundle) for bundle in data.get('accessBundles', []) - ] + if data.get('accessBundle') is not None: + session_data['accessBundle'] = AgentVaultSessionAccessBundle.from_dict(data['accessBundle']) return super().from_dict(session_data) diff --git a/infisical_sdk/resources/agent_vault.py b/infisical_sdk/resources/agent_vault.py index f0938d3..d727ab6 100644 --- a/infisical_sdk/resources/agent_vault.py +++ b/infisical_sdk/resources/agent_vault.py @@ -268,7 +268,7 @@ def create( The created session, including its token. The token is only returned once. """ request_body = { - "accessBundles": [access_bundle], + "accessBundle": access_bundle, "ttl": ttl, "label": label, } @@ -311,7 +311,7 @@ def revoke(self, session_id: str) -> AgentVaultSession: session_id: The ID of the session to revoke. Returns: - The revoked session. Its accessBundles is None, because the response leaves the bundles out; call get for them. + The revoked session. Its accessBundle is None, because the response leaves the bundle out; call get for it. """ result = self.requests.post( path=f"/api/v1/agent-vault/sessions/{session_id}/revoke", diff --git a/tests/test_agent_vault.py b/tests/test_agent_vault.py index 7adad32..2871a06 100644 --- a/tests/test_agent_vault.py +++ b/tests/test_agent_vault.py @@ -9,7 +9,7 @@ "label": None, "status": "active", "createdAt": "2026-10-27T00:00:00.000Z", - "accessBundles": [], + "accessBundle": {"id": "0d3f8a51-7c2e-4b9a-8e16-5a4c3b2d1f07", "name": "release"}, } @@ -73,12 +73,27 @@ def test_proxies_rotate_token_is_not_retried_once_the_request_may_have_reached_t assert api.session.post.call_count == 1 -def test_sessions_revoke_leaves_access_bundles_unset_when_the_response_omits_them(api, agent_vault, json_response): - revoked = {key: value for key, value in SESSION.items() if key != "accessBundles"} +def test_sessions_revoke_leaves_the_access_bundle_unset_when_the_response_omits_it(api, agent_vault, json_response): + revoked = {key: value for key, value in SESSION.items() if key != "accessBundle"} api.session.post.return_value = json_response({"session": dict(revoked, status="revoked")}) - assert agent_vault.sessions.revoke(SESSION["id"]).accessBundles is None + assert agent_vault.sessions.revoke(SESSION["id"]).accessBundle is None -def test_sessions_get_keeps_an_empty_access_bundles_list(api, agent_vault, json_response): +def test_sessions_get_reads_the_access_bundle(api, agent_vault, json_response): api.session.get.return_value = json_response({"session": SESSION}) - assert agent_vault.sessions.get(SESSION["id"]).accessBundles == [] + bundle = agent_vault.sessions.get(SESSION["id"]).accessBundle + assert (bundle.id, bundle.name) == (SESSION["accessBundle"]["id"], "release") + + +def test_sessions_get_keeps_the_name_of_a_deleted_access_bundle(api, agent_vault, json_response): + api.session.get.return_value = json_response({"session": dict(SESSION, accessBundle={"id": None, "name": "release"})}) + bundle = agent_vault.sessions.get(SESSION["id"]).accessBundle + assert (bundle.id, bundle.name) == (None, "release") + + +def test_sessions_create_sends_one_access_bundle(api, agent_vault, json_response): + created = {"id": SESSION["id"], "token": "agv_token", "createdAt": SESSION["createdAt"], "accessBundle": SESSION["accessBundle"]} + api.session.post.return_value = json_response({"session": created}) + session = agent_vault.sessions.create(access_bundle="release", ttl="1h") + assert api.session.post.call_args.kwargs["json"] == {"accessBundle": "release", "ttl": "1h"} + assert session.accessBundle.name == "release"