feat: make vault events available in SDK#588
feat: make vault events available in SDK#588vivekkhimani wants to merge 3 commits intoworkos:mainfrom
Conversation
| id: str | ||
| object: Literal["organization"] | ||
| name: str | ||
| external_id: Optional[str] = None |
There was a problem hiding this comment.
Let me know if you all disagree moving this up in OrganizationCommon
Greptile SummaryThis PR expands the Events module with 9 new Vault event types, and fixes two pre-existing gaps in Key changes:
Confidence Score: 4/5
Important Files Changed
Class Diagram%%{init: {'theme': 'neutral'}}%%
classDiagram
class WorkOSModel
class EventModel~T~ {
+str id
+Literal["event"] object
+T data
+str created_at
}
class VaultNamesListedPayload {
+str actor_id
+str actor_source
+str actor_name
}
class VaultDataDeletedPayload {
+str actor_id
+str actor_source
+str actor_name
+str kv_name
}
class VaultDekDecryptedPayload {
+str actor_id
+str actor_source
+str actor_name
+str key_id
}
class VaultDataReadPayload {
+str actor_id
+str actor_source
+str actor_name
+str kv_name
+str key_id
}
class VaultDataCreatedPayload {
+str actor_id
+str actor_source
+str actor_name
+str kv_name
+str key_id
+Optional~KeyContext~ key_context
}
class VaultDekReadPayload {
+str actor_id
+str actor_source
+str actor_name
+List~str~ key_ids
+Optional~KeyContext~ key_context
}
class VaultKekCreatedPayload {
+str actor_id
+str actor_source
+str actor_name
+str key_name
+str key_id
}
WorkOSModel <|-- VaultNamesListedPayload
WorkOSModel <|-- VaultDataDeletedPayload
WorkOSModel <|-- VaultDekDecryptedPayload
WorkOSModel <|-- VaultDataReadPayload
WorkOSModel <|-- VaultDataCreatedPayload
WorkOSModel <|-- VaultDekReadPayload
WorkOSModel <|-- VaultKekCreatedPayload
EventModel~VaultNamesListedPayload~ <|-- VaultNamesListedEvent : event = "vault.names.listed"
EventModel~VaultDataDeletedPayload~ <|-- VaultDataDeletedEvent : event = "vault.data.deleted"
EventModel~VaultDataDeletedPayload~ <|-- VaultMetadataReadEvent : event = "vault.metadata.read"
EventModel~VaultDekDecryptedPayload~ <|-- VaultDekDecryptedEvent : event = "vault.dek.decrypted"
EventModel~VaultDataReadPayload~ <|-- VaultDataReadEvent : event = "vault.data.read"
EventModel~VaultDataCreatedPayload~ <|-- VaultDataCreatedEvent : event = "vault.data.created"
EventModel~VaultDataCreatedPayload~ <|-- VaultDataUpdatedEvent : event = "vault.data.updated"
EventModel~VaultDekReadPayload~ <|-- VaultDekReadEvent : event = "vault.dek.read"
EventModel~VaultKekCreatedPayload~ <|-- VaultKekCreatedEvent : event = "vault.kek.created"
Last reviewed commit: da8c1e8 |
| class VaultMetadataReadEvent(EventModel[VaultDataDeletedPayload]): | ||
| event: Literal["vault.metadata.read"] |
There was a problem hiding this comment.
Semantic type mismatch on VaultMetadataReadEvent.data
VaultMetadataReadEvent.data is typed as VaultDataDeletedPayload, which is semantically misleading for SDK consumers. A user inspecting the type of event.data on a vault.metadata.read event will find it annotated as a "deleted" payload, which is confusing when navigating type hints or IDE autocomplete.
The ConnectionPayloadWithLegacyFields precedent cited in the PR description works because its name is generic/neutral; here the reused class name carries a specific (and incorrect) semantic meaning for the second event it covers. A type alias VaultMetadataReadPayload = VaultDataDeletedPayload in vault_payload.py (and exported/imported accordingly) would preserve the single-class implementation while giving the event a correctly-named data type:
# vault_payload.py
VaultMetadataReadPayload = VaultDataDeletedPayload# event.py
class VaultMetadataReadEvent(EventModel[VaultMetadataReadPayload]):
event: Literal["vault.metadata.read"]| @@ -86,3 +91,135 @@ def test_list_events_organization_membership_missing_custom_attributes( | |||
| event = events.data[0] | |||
| assert isinstance(event, OrganizationMembershipCreatedEvent) | |||
| assert event.data.custom_attributes == {} | |||
There was a problem hiding this comment.
Test coverage gap for distinct payload shapes
The PR adds 9 new event types but only 3 are covered by tests. The two payload classes that have unique structures and are not tested at all are VaultDekDecryptedPayload (used by vault.dek.decrypted) and VaultKekCreatedPayload (used by vault.kek.created). Both have distinct field sets not covered by any of the three tests:
VaultDekDecryptedPayloadhaskey_id: str(nokey_ids, nokey_context)VaultKekCreatedPayloadhaskey_name: strandkey_id: str
Additionally, vault.data.updated (which reuses VaultDataCreatedPayload) and vault.metadata.read (which reuses VaultDataDeletedPayload) have no tests confirming the event discriminator parses correctly to the expected class. Adding fixture-backed tests for these cases would match the coverage level of other event groups in this file.
Description
vault.data.createdvault.data.deletedvault.data.readvault.data.updatedvault.dek.decryptedvault.dek.readvault.kek.createdvault.metadata.readvault.names.listedEventRolemissingcreated_at/updated_atfields that the API returns on role eventsOrganizationCommonmissingexternal_idfield that the API returns on organization events(it previously existed only on the
Organizationsubclass, not on the event payload model)Closes #573
Vault event details
Seven payload classes cover all nine events. Where two events share the same shape, they reuse a payload class (following the same pattern as
ConnectionPayloadWithLegacyFields, which is used for bothconnection.activatedandconnection.deactivated).Shared payload mappings:
VaultDataCreatedPayloadvault.data.createdvault.data.updatedVaultDataDeletedPayloadvault.data.deletedvault.metadata.readAll payloads were verified against:
https://workos.com/docs/events#vault
Existing event fixes
While auditing Vault events against the docs, every other event type was also reviewed. Two gaps were identified and fixed (please let me know if you want to not do it as a part of this PR):
1.
EventRoleEventRolewas missing the fields:created_atupdated_atBoth were added as
Optional[str]to remain consistent with the SDK’s defensive typing approach and avoid breaking existing consumers.2.
OrganizationCommonOrganizationCommonwas missing theexternal_idfield.Changes made:
external_idfromOrganization(where it already existed) intoOrganizationCommonOrganizationThis ensures organization event payloads include
external_id.Test plan
data.createdwithkey_contextdek.readwithkey_idsnames.listedwith actor-only fieldsuv run ruff format . && uv run ruff check .passesuv run mypypasses (strict mode, 163 source files)Documentation
Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.
If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.