From bd2caea485e3e96fcf52d06492d11fbae5c8cafe Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:23:34 +0000 Subject: [PATCH 1/2] chore(generated): regenerate shared files for AdminPortal, Agents, ApiKeys, AuditLogs, Authorization, ClientApi, Connect, DirectorySync, Events, FeatureFlags, Groups, MultiFactorAuth, OrganizationDomains, OrganizationMembership, Organizations, Pipes, PipesProvider, PlatformTeams, Radar, SSO, UserManagement, Vault, Webhooks, Widgets --- .last-synced-sha | 2 +- .oagen-manifest.json | 6 ++ src/workos/admin_portal/_resource.py | 4 +- src/workos/agents/_resource.py | 60 +++++++++++++++++++ src/workos/agents/models/__init__.py | 1 + .../agents/models/agent_registration.py | 9 +++ src/workos/authorization/models/__init__.py | 1 - src/workos/common/__init__.py | 3 + src/workos/common/models/__init__.py | 3 + ...updated_context_previous_attribute_data.py | 17 +++++- ...d_context_previous_attribute_data_owner.py | 7 +++ tests/fixtures/agent_registration.json | 1 + tests/fixtures/flag_updated.json | 5 ++ tests/fixtures/flag_updated_context.json | 5 ++ ...ag_updated_context_previous_attribute.json | 5 ++ ...dated_context_previous_attribute_data.json | 5 ++ ...context_previous_attribute_data_owner.json | 5 ++ tests/test_agents.py | 23 +++++++ tests/test_agents_models_round_trip.py | 26 ++++++++ tests/test_authorization_models_round_trip.py | 21 ------- tests/test_common_models_round_trip.py | 42 ++++++++++++- 21 files changed, 224 insertions(+), 27 deletions(-) create mode 100644 src/workos/common/models/flag_updated_context_previous_attribute_data_owner.py create mode 100644 tests/fixtures/flag_updated_context_previous_attribute_data_owner.json diff --git a/.last-synced-sha b/.last-synced-sha index 54a4cc9f1..9174e8a25 100644 --- a/.last-synced-sha +++ b/.last-synced-sha @@ -1 +1 @@ -d430b394483f6e00ff7f9e2ca8d4340ff8f7aa54 +4ecccdfeab4244ffaf428c96b1615bf0440b4c0f diff --git a/.oagen-manifest.json b/.oagen-manifest.json index 787ef6ee5..b3f0dd09c 100644 --- a/.oagen-manifest.json +++ b/.oagen-manifest.json @@ -417,6 +417,7 @@ "src/workos/common/models/flag_updated_context_actor_source.py", "src/workos/common/models/flag_updated_context_previous_attribute.py", "src/workos/common/models/flag_updated_context_previous_attribute_data.py", + "src/workos/common/models/flag_updated_context_previous_attribute_data_owner.py", "src/workos/common/models/flag_updated_data.py", "src/workos/common/models/flag_updated_data_owner.py", "src/workos/common/models/generate_link_intent.py", @@ -1302,6 +1303,7 @@ "tests/fixtures/flag_updated_context_actor.json", "tests/fixtures/flag_updated_context_previous_attribute.json", "tests/fixtures/flag_updated_context_previous_attribute_data.json", + "tests/fixtures/flag_updated_context_previous_attribute_data_owner.json", "tests/fixtures/flag_updated_data.json", "tests/fixtures/flag_updated_data_owner.json", "tests/fixtures/generate_link.json", @@ -1696,6 +1698,10 @@ "sdkMethod": "get_registration", "service": "agents" }, + "POST /agents/registrations/{id}/revoke": { + "sdkMethod": "revoke_registration", + "service": "agents" + }, "GET /agents/instances": { "sdkMethod": "list_instances", "service": "agents" diff --git a/src/workos/admin_portal/_resource.py b/src/workos/admin_portal/_resource.py index 6c4558f47..bcdaecf4f 100644 --- a/src/workos/admin_portal/_resource.py +++ b/src/workos/admin_portal/_resource.py @@ -89,7 +89,7 @@ def revoke_link( external_user_id: str, request_options: RequestOptions | None = None, ) -> None: - """Revoke Portal Links + """Revoke a Portal Link Revokes every Portal Link generated for the given organization with the given `external_user_id`, and immediately ends any Admin Portal sessions that were started from those links. Use this when an admin is deprovisioned from your application: unopened links stop working, and their already-open portal sessions are ended. Only links that were generated with an `external_user_id` can be revoked, so pass one to `generate_link` for every admin you may later need to deprovision. @@ -193,7 +193,7 @@ async def revoke_link( external_user_id: str, request_options: RequestOptions | None = None, ) -> None: - """Revoke Portal Links + """Revoke a Portal Link Revokes every Portal Link generated for the given organization with the given `external_user_id`, and immediately ends any Admin Portal sessions that were started from those links. Use this when an admin is deprovisioned from your application: unopened links stop working, and their already-open portal sessions are ended. Only links that were generated with an `external_user_id` can be revoked, so pass one to `generate_link` for every admin you may later need to deprovision. diff --git a/src/workos/agents/_resource.py b/src/workos/agents/_resource.py index 8f962d4e0..6251aa8f9 100644 --- a/src/workos/agents/_resource.py +++ b/src/workos/agents/_resource.py @@ -493,6 +493,36 @@ def get_registration( request_options=request_options, ) + def revoke_registration( + self, + id: str, + *, + request_options: RequestOptions | None = None, + ) -> AgentRegistration: + """Revoke an agent registration + + Revoke an agent registration by ID. Revocation is permanent: the registration, its identity assertions, and every access token or API key issued from it stop working, and the agent must register again. Revoking an already revoked registration succeeds and returns the original `revoked_at`. The registration is scoped to the environment of the API key used to authenticate the request. + + Args: + id: The unique ID of the agent registration. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + AgentRegistration + + Raises: + NotFoundError: If the resource is not found (404). + AuthenticationError: If the API key is invalid (401). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + return self._client.request( + method="post", + path=("agents", "registrations", str(id), "revoke"), + model=AgentRegistration, + request_options=request_options, + ) + def list_instances( self, *, @@ -1175,6 +1205,36 @@ async def get_registration( request_options=request_options, ) + async def revoke_registration( + self, + id: str, + *, + request_options: RequestOptions | None = None, + ) -> AgentRegistration: + """Revoke an agent registration + + Revoke an agent registration by ID. Revocation is permanent: the registration, its identity assertions, and every access token or API key issued from it stop working, and the agent must register again. Revoking an already revoked registration succeeds and returns the original `revoked_at`. The registration is scoped to the environment of the API key used to authenticate the request. + + Args: + id: The unique ID of the agent registration. + request_options: Per-request options. Supports extra_headers, timeout, max_retries, and base_url override. + + Returns: + AgentRegistration + + Raises: + NotFoundError: If the resource is not found (404). + AuthenticationError: If the API key is invalid (401). + RateLimitExceededError: If rate limited (429). + ServerError: If the server returns a 5xx error. + """ + return await self._client.request( + method="post", + path=("agents", "registrations", str(id), "revoke"), + model=AgentRegistration, + request_options=request_options, + ) + async def list_instances( self, *, diff --git a/src/workos/agents/models/__init__.py b/src/workos/agents/models/__init__.py index 305678252..7d039a817 100644 --- a/src/workos/agents/models/__init__.py +++ b/src/workos/agents/models/__init__.py @@ -1,5 +1,6 @@ # This file is auto-generated by oagen. Do not edit. +from workos.common.models.list_metadata import ListMetadata as ListMetadata from workos.common.models.pagination_order import PaginationOrder as PaginationOrder from .agent_admin_link_claim_attempt_to_external_user_request import ( diff --git a/src/workos/agents/models/agent_registration.py b/src/workos/agents/models/agent_registration.py index d7a1d1ad9..b494ea354 100644 --- a/src/workos/agents/models/agent_registration.py +++ b/src/workos/agents/models/agent_registration.py @@ -27,6 +27,8 @@ class AgentRegistration: """Identifier of the organization the agent is registered to.""" status: AgentRegistrationStatus """The current verification status of the registration.""" + revoked_at: datetime | None + """The timestamp when the registration was revoked, or `null` if it has not been revoked.""" kind: AgentRegistrationKind """The kind of agent registration.""" claim: AgentRegistrationClaim | None @@ -47,6 +49,9 @@ def from_dict(cls, data: dict[str, Any]) -> AgentRegistration: ), organization_id=data["organization_id"], status=AgentRegistrationStatus(data["status"]), + revoked_at=_parse_datetime(_v_revoked_at) + if (_v_revoked_at := data["revoked_at"]) is not None + else None, kind=AgentRegistrationKind(data["kind"]), claim=AgentRegistrationClaim.from_dict(cast(dict[str, Any], _v_claim)) if (_v_claim := data["claim"]) is not None @@ -66,6 +71,10 @@ def to_dict(self) -> dict[str, Any]: result["status"] = ( self.status.value if isinstance(self.status, Enum) else self.status ) + if self.revoked_at is not None: + result["revoked_at"] = _format_datetime(self.revoked_at) + else: + result["revoked_at"] = None result["kind"] = self.kind.value if isinstance(self.kind, Enum) else self.kind if self.claim is not None: result["claim"] = self.claim.to_dict() diff --git a/src/workos/authorization/models/__init__.py b/src/workos/authorization/models/__init__.py index f043ea653..25a0efb8d 100644 --- a/src/workos/authorization/models/__init__.py +++ b/src/workos/authorization/models/__init__.py @@ -6,7 +6,6 @@ from workos.common.models.authorization_permission import ( AuthorizationPermission as AuthorizationPermission, ) -from workos.common.models.list_metadata import ListMetadata as ListMetadata from workos.common.models.slim_role import SlimRole as SlimRole from .assign_role import AssignRole as AssignRole diff --git a/src/workos/common/__init__.py b/src/workos/common/__init__.py index ec1968c6e..0959790df 100644 --- a/src/workos/common/__init__.py +++ b/src/workos/common/__init__.py @@ -470,6 +470,9 @@ from .models import ( FlagUpdatedContextPreviousAttributeData as FlagUpdatedContextPreviousAttributeData, ) +from .models import ( + FlagUpdatedContextPreviousAttributeDataOwner as FlagUpdatedContextPreviousAttributeDataOwner, +) from .models import FlagUpdatedData as FlagUpdatedData from .models import FlagUpdatedDataOwner as FlagUpdatedDataOwner from .models import GenerateLinkIntent as GenerateLinkIntent diff --git a/src/workos/common/models/__init__.py b/src/workos/common/models/__init__.py index 1f9ea5965..8dc35a22e 100644 --- a/src/workos/common/models/__init__.py +++ b/src/workos/common/models/__init__.py @@ -676,6 +676,9 @@ from .flag_updated_context_previous_attribute_data import ( FlagUpdatedContextPreviousAttributeData as FlagUpdatedContextPreviousAttributeData, ) +from .flag_updated_context_previous_attribute_data_owner import ( + FlagUpdatedContextPreviousAttributeDataOwner as FlagUpdatedContextPreviousAttributeDataOwner, +) from .flag_updated_data import FlagUpdatedData as FlagUpdatedData from .flag_updated_data_owner import FlagUpdatedDataOwner as FlagUpdatedDataOwner from .generate_link_intent import GenerateLinkIntent as GenerateLinkIntent diff --git a/src/workos/common/models/flag_updated_context_previous_attribute_data.py b/src/workos/common/models/flag_updated_context_previous_attribute_data.py index 7c84b0c8d..32df84771 100644 --- a/src/workos/common/models/flag_updated_context_previous_attribute_data.py +++ b/src/workos/common/models/flag_updated_context_previous_attribute_data.py @@ -3,10 +3,14 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any +from typing import Any, cast from workos._types import _raise_deserialize_error +from .flag_updated_context_previous_attribute_data_owner import ( + FlagUpdatedContextPreviousAttributeDataOwner, +) + @dataclass(slots=True) class FlagUpdatedContextPreviousAttributeData: @@ -18,6 +22,8 @@ class FlagUpdatedContextPreviousAttributeData: """The previous description of the flag.""" tags: list[str] | None = None """The previous tags of the flag.""" + owner: FlagUpdatedContextPreviousAttributeDataOwner | None = None + """The previous owner of the flag, or `null` if it had none.""" enabled: bool | None = None """Whether the flag was previously enabled.""" default_value: bool | None = None @@ -31,6 +37,11 @@ def from_dict(cls, data: dict[str, Any]) -> FlagUpdatedContextPreviousAttributeD name=data.get("name"), description=data.get("description"), tags=data.get("tags"), + owner=FlagUpdatedContextPreviousAttributeDataOwner.from_dict( + cast(dict[str, Any], _v_owner) + ) + if (_v_owner := data.get("owner")) is not None + else None, enabled=data.get("enabled"), default_value=data.get("default_value"), ) @@ -48,6 +59,10 @@ def to_dict(self) -> dict[str, Any]: result["description"] = None if self.tags is not None: result["tags"] = self.tags + if self.owner is not None: + result["owner"] = self.owner.to_dict() + else: + result["owner"] = None if self.enabled is not None: result["enabled"] = self.enabled if self.default_value is not None: diff --git a/src/workos/common/models/flag_updated_context_previous_attribute_data_owner.py b/src/workos/common/models/flag_updated_context_previous_attribute_data_owner.py new file mode 100644 index 000000000..4850ceb25 --- /dev/null +++ b/src/workos/common/models/flag_updated_context_previous_attribute_data_owner.py @@ -0,0 +1,7 @@ +# This file is auto-generated by oagen. Do not edit. + +from typing import TypeAlias + +from .feature_flag_owner import FeatureFlagOwner + +FlagUpdatedContextPreviousAttributeDataOwner: TypeAlias = FeatureFlagOwner diff --git a/tests/fixtures/agent_registration.json b/tests/fixtures/agent_registration.json index cb6c56d6a..89d432c2d 100644 --- a/tests/fixtures/agent_registration.json +++ b/tests/fixtures/agent_registration.json @@ -8,6 +8,7 @@ }, "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", "status": "verified", + "revoked_at": null, "kind": "service_auth", "claim": { "id": "agent_reg_claim_01EHWNCE74X7JSDV0X3SZ3KJNY", diff --git a/tests/fixtures/flag_updated.json b/tests/fixtures/flag_updated.json index 1d76b24b7..53d420e7b 100644 --- a/tests/fixtures/flag_updated.json +++ b/tests/fixtures/flag_updated.json @@ -38,6 +38,11 @@ "beta", "release" ], + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, "enabled": true, "default_value": false } diff --git a/tests/fixtures/flag_updated_context.json b/tests/fixtures/flag_updated_context.json index 498a9fcea..55e6d9ff9 100644 --- a/tests/fixtures/flag_updated_context.json +++ b/tests/fixtures/flag_updated_context.json @@ -13,6 +13,11 @@ "beta", "release" ], + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, "enabled": true, "default_value": false } diff --git a/tests/fixtures/flag_updated_context_previous_attribute.json b/tests/fixtures/flag_updated_context_previous_attribute.json index 5e18bba38..4e58df79c 100644 --- a/tests/fixtures/flag_updated_context_previous_attribute.json +++ b/tests/fixtures/flag_updated_context_previous_attribute.json @@ -6,6 +6,11 @@ "beta", "release" ], + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, "enabled": true, "default_value": false } diff --git a/tests/fixtures/flag_updated_context_previous_attribute_data.json b/tests/fixtures/flag_updated_context_previous_attribute_data.json index 959192e39..bc38a6f3f 100644 --- a/tests/fixtures/flag_updated_context_previous_attribute_data.json +++ b/tests/fixtures/flag_updated_context_previous_attribute_data.json @@ -5,6 +5,11 @@ "beta", "release" ], + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" + }, "enabled": true, "default_value": false } diff --git a/tests/fixtures/flag_updated_context_previous_attribute_data_owner.json b/tests/fixtures/flag_updated_context_previous_attribute_data_owner.json new file mode 100644 index 000000000..7c01c46fb --- /dev/null +++ b/tests/fixtures/flag_updated_context_previous_attribute_data_owner.json @@ -0,0 +1,5 @@ +{ + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe" +} diff --git a/tests/test_agents.py b/tests/test_agents.py index cc29fdd00..641fa8049 100644 --- a/tests/test_agents.py +++ b/tests/test_agents.py @@ -202,6 +202,18 @@ def test_get_registration(self, workos, httpx_mock): assert request.method == "GET" assert request.url.path.endswith("/agents/registrations/test_id") + def test_revoke_registration(self, workos, httpx_mock): + httpx_mock.add_response( + json=load_fixture("agent_registration.json"), + ) + result = workos.agents.revoke_registration("test_id") + assert isinstance(result, AgentRegistration) + assert result.id == "agent_reg_01EHWNCE74X7JSDV0X3SZ3KJNY" + assert result.organization_id == "org_01EHQMYV6MBK39QC5PZXHY59C3" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith("/agents/registrations/test_id/revoke") + def test_list_instances(self, workos, httpx_mock): httpx_mock.add_response( json=load_fixture("list_agent_instance.json"), @@ -546,6 +558,17 @@ async def test_get_registration(self, async_workos, httpx_mock): assert request.method == "GET" assert request.url.path.endswith("/agents/registrations/test_id") + @pytest.mark.asyncio + async def test_revoke_registration(self, async_workos, httpx_mock): + httpx_mock.add_response(json=load_fixture("agent_registration.json")) + result = await async_workos.agents.revoke_registration("test_id") + assert isinstance(result, AgentRegistration) + assert result.id == "agent_reg_01EHWNCE74X7JSDV0X3SZ3KJNY" + assert result.organization_id == "org_01EHQMYV6MBK39QC5PZXHY59C3" + request = httpx_mock.get_request() + assert request.method == "POST" + assert request.url.path.endswith("/agents/registrations/test_id/revoke") + @pytest.mark.asyncio async def test_list_instances(self, async_workos, httpx_mock): httpx_mock.add_response(json=load_fixture("list_agent_instance.json")) diff --git a/tests/test_agents_models_round_trip.py b/tests/test_agents_models_round_trip.py index 8a5128a19..84ab071f8 100644 --- a/tests/test_agents_models_round_trip.py +++ b/tests/test_agents_models_round_trip.py @@ -26,10 +26,31 @@ AgentTokenValidation, ClaimViewResponse, ClaimViewResponseOrganization, + ListMetadata, ) class TestModelRoundTrip: + def test_list_metadata_round_trip(self): + data = load_fixture("list_metadata.json") + instance = ListMetadata.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = ListMetadata.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_list_metadata_minimal_payload(self): + data = {} + instance = ListMetadata.from_dict(data) + assert instance.to_dict() is not None + + def test_list_metadata_preserves_nullable_fields(self): + data = {"after": None, "before": None} + instance = ListMetadata.from_dict(data) + serialized = instance.to_dict() + assert serialized["after"] is None + assert serialized["before"] is None + def test_agent_registration_round_trip(self): data = load_fixture("agent_registration.json") instance = AgentRegistration.from_dict(data) @@ -49,6 +70,7 @@ def test_agent_registration_minimal_payload(self): }, "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", "status": "verified", + "revoked_at": None, "kind": "service_auth", "claim": None, "created_at": "2026-01-15T12:00:00.000Z", @@ -60,6 +82,7 @@ def test_agent_registration_minimal_payload(self): assert serialized["agent_identity"] == data["agent_identity"] assert serialized["organization_id"] == data["organization_id"] assert serialized["status"] == data["status"] + assert serialized["revoked_at"] == data["revoked_at"] assert serialized["kind"] == data["kind"] assert serialized["claim"] == data["claim"] assert serialized["created_at"] == data["created_at"] @@ -76,6 +99,7 @@ def test_agent_registration_preserves_nullable_fields(self): }, "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", "status": "verified", + "revoked_at": None, "kind": "service_auth", "claim": None, "created_at": "2026-01-15T12:00:00.000Z", @@ -83,6 +107,7 @@ def test_agent_registration_preserves_nullable_fields(self): } instance = AgentRegistration.from_dict(data) serialized = instance.to_dict() + assert serialized["revoked_at"] is None assert serialized["claim"] is None def test_agent_registration_round_trips_unknown_enum_values(self): @@ -96,6 +121,7 @@ def test_agent_registration_round_trips_unknown_enum_values(self): }, "organization_id": "org_01EHQMYV6MBK39QC5PZXHY59C3", "status": "unexpected_agent_registration_status", + "revoked_at": None, "kind": "service_auth", "claim": { "id": "agent_reg_claim_01EHWNCE74X7JSDV0X3SZ3KJNY", diff --git a/tests/test_authorization_models_round_trip.py b/tests/test_authorization_models_round_trip.py index 677f2ab84..1c6d024dd 100644 --- a/tests/test_authorization_models_round_trip.py +++ b/tests/test_authorization_models_round_trip.py @@ -10,7 +10,6 @@ GroupRoleAssignment, GroupRoleAssignmentList, GroupRoleAssignmentResource, - ListMetadata, Permission, ReplaceGroupRoleAssignmentEntry, Role, @@ -48,26 +47,6 @@ def test_replace_group_role_assignment_entry_omits_absent_optional_non_nullable_ assert "resource_external_id" not in serialized assert "resource_type_slug" not in serialized - def test_list_metadata_round_trip(self): - data = load_fixture("list_metadata.json") - instance = ListMetadata.from_dict(data) - serialized = instance.to_dict() - assert serialized == data - restored = ListMetadata.from_dict(serialized) - assert restored.to_dict() == serialized - - def test_list_metadata_minimal_payload(self): - data = {} - instance = ListMetadata.from_dict(data) - assert instance.to_dict() is not None - - def test_list_metadata_preserves_nullable_fields(self): - data = {"after": None, "before": None} - instance = ListMetadata.from_dict(data) - serialized = instance.to_dict() - assert serialized["after"] is None - assert serialized["before"] is None - def test_authorization_check_round_trip(self): data = load_fixture("authorization_check.json") instance = AuthorizationCheck.from_dict(data) diff --git a/tests/test_common_models_round_trip.py b/tests/test_common_models_round_trip.py index 14f0eedcd..702810657 100644 --- a/tests/test_common_models_round_trip.py +++ b/tests/test_common_models_round_trip.py @@ -189,6 +189,7 @@ FlagUpdatedContextActor, FlagUpdatedContextPreviousAttribute, FlagUpdatedContextPreviousAttributeData, + FlagUpdatedContextPreviousAttributeDataOwner, FlagUpdatedData, FlagUpdatedDataOwner, GroupCreated, @@ -8698,6 +8699,11 @@ def test_flag_updated_minimal_payload(self): "name": "My Feature Flag", "description": "Enables the new feature.", "tags": ["beta", "release"], + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe", + }, "enabled": True, "default_value": False, } @@ -8897,7 +8903,14 @@ def test_flag_updated_context_previous_attribute_data_minimal_payload(self): def test_flag_updated_context_previous_attribute_data_omits_absent_optional_non_nullable_fields( self, ): - data = {"description": "Enables the new feature."} + data = { + "description": "Enables the new feature.", + "owner": { + "email": "jane@example.com", + "first_name": "Jane", + "last_name": "Doe", + }, + } instance = FlagUpdatedContextPreviousAttributeData.from_dict(data) serialized = instance.to_dict() assert "name" not in serialized @@ -8912,12 +8925,39 @@ def test_flag_updated_context_previous_attribute_data_preserves_nullable_fields( "name": "My Feature Flag", "description": None, "tags": ["beta", "release"], + "owner": None, "enabled": True, "default_value": False, } instance = FlagUpdatedContextPreviousAttributeData.from_dict(data) serialized = instance.to_dict() assert serialized["description"] is None + assert serialized["owner"] is None + + def test_flag_updated_context_previous_attribute_data_owner_round_trip(self): + data = load_fixture("flag_updated_context_previous_attribute_data_owner.json") + instance = FlagUpdatedContextPreviousAttributeDataOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized == data + restored = FlagUpdatedContextPreviousAttributeDataOwner.from_dict(serialized) + assert restored.to_dict() == serialized + + def test_flag_updated_context_previous_attribute_data_owner_minimal_payload(self): + data = {"email": "jane@example.com", "first_name": None, "last_name": None} + instance = FlagUpdatedContextPreviousAttributeDataOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized["email"] == data["email"] + assert serialized["first_name"] == data["first_name"] + assert serialized["last_name"] == data["last_name"] + + def test_flag_updated_context_previous_attribute_data_owner_preserves_nullable_fields( + self, + ): + data = {"email": "jane@example.com", "first_name": None, "last_name": None} + instance = FlagUpdatedContextPreviousAttributeDataOwner.from_dict(data) + serialized = instance.to_dict() + assert serialized["first_name"] is None + assert serialized["last_name"] is None def test_group_created_round_trip(self): data = load_fixture("group_created.json") From a1438ae541221ec48c0cb5584c8e9defe0831f04 Mon Sep 17 00:00:00 2001 From: "workos-sdk-automation[bot]" <255426317+workos-sdk-automation[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:23:40 +0000 Subject: [PATCH 2/2] chore(generated): add release notes fragment --- ...-19T13-23-40-26ae9d6780ace6ef8419c462017f93619d5367b2.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changelog-pending/2026-10-19T13-23-40-26ae9d6780ace6ef8419c462017f93619d5367b2.md diff --git a/.changelog-pending/2026-10-19T13-23-40-26ae9d6780ace6ef8419c462017f93619d5367b2.md b/.changelog-pending/2026-10-19T13-23-40-26ae9d6780ace6ef8419c462017f93619d5367b2.md new file mode 100644 index 000000000..1d0489785 --- /dev/null +++ b/.changelog-pending/2026-10-19T13-23-40-26ae9d6780ace6ef8419c462017f93619d5367b2.md @@ -0,0 +1,6 @@ +* [#752](https://github.com/workos/workos-python/pull/752) fix(generated): regenerate from spec + + **Features** + * **[agents](https://workos.com/docs/reference/agents)**: + * Added `revoked_at` to `AgentRegistration` + * Added endpoint `POST /agents/registrations/{id}/revoke`