-
Notifications
You must be signed in to change notification settings - Fork 25
Implement the remaining Audit Logs functionality #515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Greptile SummaryThis PR completes the Audit Logs API implementation by adding support for schemas, actions, retention configuration, and audit log configuration endpoints. The implementation follows the SDK's established patterns with both sync and async variants for all new methods. Key Changes:
Implementation Quality:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client as Client (Sync/Async)
participant AuditLogs as AuditLogs Module
participant HTTPClient as HTTP Client
participant API as WorkOS API
Note over Client,API: Create Event Flow
Client->>AuditLogs: create_event(organization_id, event, idempotency_key)
AuditLogs->>HTTPClient: POST /audit_logs/events
HTTPClient->>API: HTTP Request with event data
API-->>HTTPClient: 200 OK
HTTPClient-->>AuditLogs: Response
AuditLogs-->>Client: None
Note over Client,API: Schema Management Flow
Client->>AuditLogs: create_schema(action, targets, actor, metadata)
AuditLogs->>HTTPClient: POST /audit_logs/actions/{action}/schemas
HTTPClient->>API: HTTP Request with schema definition
API-->>HTTPClient: 201 Created
HTTPClient-->>AuditLogs: AuditLogSchema JSON
AuditLogs->>AuditLogs: AuditLogSchema.model_validate()
AuditLogs-->>Client: AuditLogSchema object
Note over Client,API: List Actions Flow
Client->>AuditLogs: list_actions(limit, before, after, order)
AuditLogs->>HTTPClient: GET /audit_logs/actions with params
HTTPClient->>API: HTTP Request
API-->>HTTPClient: List response with actions
HTTPClient-->>AuditLogs: Response with data array
AuditLogs->>AuditLogs: WorkOSListResource creation
Note over AuditLogs: Includes AuditLogAction objects<br/>with nested AuditLogSchema
AuditLogs-->>Client: Paginated list resource
Note over Client,API: Retention Configuration Flow
Client->>AuditLogs: set_retention(organization_id, retention_period_in_days)
AuditLogs->>HTTPClient: PUT /organizations/{org_id}/audit_logs_retention
HTTPClient->>API: HTTP Request with retention period
API-->>HTTPClient: 200 OK with retention config
HTTPClient-->>AuditLogs: AuditLogRetention JSON
AuditLogs->>AuditLogs: AuditLogRetention.model_validate()
AuditLogs-->>Client: AuditLogRetention object
Note over Client,API: Configuration Retrieval Flow
Client->>AuditLogs: get_configuration(organization_id)
AuditLogs->>HTTPClient: GET /organizations/{org_id}/audit_log_configuration
HTTPClient->>API: HTTP Request
API-->>HTTPClient: 200 OK with full config
HTTPClient-->>AuditLogs: AuditLogConfiguration JSON
Note over AuditLogs: Includes optional log_stream<br/>with state and type info
AuditLogs->>AuditLogs: AuditLogConfiguration.model_validate()
AuditLogs-->>Client: AuditLogConfiguration object
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional Comments (1)
-
tests/test_audit_logs.py, line 7 (link)style: Check that
AsyncAuditLogsis tested. Other test modules use@pytest.mark.sync_and_async(AuditLogs, AsyncAuditLogs)decorator to test both sync and async implementations. Without this marker, only sync tests run.
11 files reviewed, 1 comment
|
Gonna update with that feedback from greptile, una momento |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
11 files reviewed, no comments
|
Alright, this is ready to go whenever ✌️ Gonna move on to other improvements 🔜 |
Starting in Python 3.14, use of `asyncio.iscoroutinefunction` emits a deprecation warning (c.f. python/cpython#122858). The recommendation is to use inspect.iscoroutinefunction instead.
95e10a3 to
733353f
Compare
gjtorikian
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
asked some clarifying questions, neither approving nor rejecting!
src/workos/audit_logs.py
Outdated
| action: str, | ||
| targets: Sequence[Mapping[str, Any]], | ||
| actor: Optional[Mapping[str, Any]] = None, | ||
| metadata: Optional[Mapping[str, Any]] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For targets, actor, and metadata, couldn't these use the schemas AuditLogSchemaTarget, AuditLogSchemaActor, and AuditLogSchemaMetadata, rather than the open-ended mapping of str: Any? (Note that these params are reused in other places in this PR, too, I just picked one example.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, my initial thinking when implementing this that these arguments were exactly as flexible as the types indicated (e.g. action is literally an arbitrary string, metadata is an arbitrary mapping). Leaving them this way enabled folks to write bog-standard/flexible Python code like:
workos.audit_logs.create_schema(
action="document.updated",
targets=[
{
"type": "document",
"metadata": {"title": "string"},
}
],
actor={"metadata": {"role": "string"}},
metadata={"invoice_id": "string"},
)This did lack type safety, but it felt like a type alias was un-necessary redirection (and created the false impression of type safety), and using the direct model (e.g. AuditLogSchemaTarget) would mean folks need to both import those models and then construct the call like so:
from workos.types.audit_logs import (
AuditLogSchemaTarget,
AuditLogSchemaActor,
AuditLogSchemaMetadata,
AuditLogSchemaMetadataProperty,
)
workos.audit_logs.create_schema(
action="document.updated",
targets=[
AuditLogSchemaTarget(
type="document",
metadata=AuditLogSchemaMetadata(
type="object",
properties={
"title": AuditLogSchemaMetadataProperty(type="string")
},
),
)
],
actor=AuditLogSchemaActor(
metadata=AuditLogSchemaMetadata(
type="object",
properties={
"role": AuditLogSchemaMetadataProperty(type="string")
},
)
),
)I think you'll agree, this feels bad, especially compared with the Node/Typescript implementation.
Having said that, your comment (and the subsequent digging it triggered) reminded me that I can actually provide just a little extra help via a TypedDict, which led me to create types like:
class AuditLogSchemaTargetInput(TypedDict):
type: str
metadata: NotRequired[MetadataSchemaInput]
class AuditLogSchemaActorInput(TypedDict):
metadata: MetadataSchemaInputWhich means that now folks get value suggestions in their IDE and also validation that they're constructing the mappings correctly, while still passing normal mappings in:
workos.audit_logs.create_schema(
action="document.updated",
targets=[
{
"type": "document",
"metadata": {"title": "string"},
}
],
actor={"metadata": {"role": "string"}},
metadata={"invoice_id": "string"},
)I think this ultimately provides the balance of ergonomics and safety we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sick 🤙
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note that these params are reused in other places in this PR, too, I just picked one example.)
Almost forgot to comment on this as well. The other functions I examined didn't, in practice, benefit from the kind of type safety the create_schema endpoint specifically did. But I'm happy to dig deeper there if you have feelings (or just think we should have type aliases in general).
| warnings.filterwarnings( | ||
| "ignore", | ||
| message='Field name "schema" in "AuditLogAction" shadows an attribute', | ||
| category=UserWarning, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given these changes, and the fact that that warning will be removed,
As of v2.12, this warning was removed! Do you think we can update our pydantic dependency (from 2.10.4, bleh) and remove this warning? Or does updating our dependency affect downstream users (necessitating a major version bump)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does updating our dependency affect downstream users (necessitating a major version bump)?
Imo, bumping up the minimum Pydantic version wouldn't, on the face of it, require a major SDK version bump, but given the popularity of Pydantic, it's possible that it could break downstream users who are pinned to a lower version.
My 2¢ is that we should leave it for now and then revisit a version bump later when we're dropping support for EOL Python versions.
That said, I'm happy to make that change in a separate PR if you feel strongly about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's roll it into the next major bump.
Introduces TypedDict definitions for the simplified schema input format:
- AuditLogSchemaTargetInput for target definitions
- AuditLogSchemaActorInput for actor definitions
- MetadataSchemaInput for metadata field type mappings
Also adds serialize_schema_options() to transform the simplified format
(e.g., {"status": "string"}) to the full JSON Schema format expected
by the API.
Replaces generic Mapping[str, Any] parameters with the new typed inputs. Uses shared serialize_schema_options() function instead of inline JSON building, reducing duplication between sync and async implementations.
The API can return null for actor in AuditLogSchema (when no custom metadata defined) and for retention_period_in_days in AuditLogRetention (when not configured). Updated models to accept None.
Updates create_schema tests to use the new simplified input format and verifies the serialization to full JSON Schema format. Adds edge case tests for nullable fields (actor in schema, retention_period_in_days).
Description
This will update the Audit Logs module to complete the endpoints available in the API reference.
Important review callout
This change creates an
AuditLogActiontype, which usesschemaas a field name directly. Why is this important to call out? Because in previous versions of Pydantic,schemawas a reserved word used internally by the PydanticBaseModel. In v2 or Pydantic, they replaced the use ofschemawithmodel_json_schema()and added an internal user warning about shadowing that field being deprecated.Given these changes, and the fact that that warning will be removed, I opted to use the
schemafield directly and catch/silence the warning at runtime to avoid any noise for our library consumers.The benefit here is that now, a developer can use
action.schema.versionwhen working with an AuditLogAction object (which matches our API response exactly) as opposed to having to use an alias likeaction.action_schema.version.Alternates I considered
As just mentioned, I originally avoided the issue by using a
Fieldwith a definedaliasin cf5ce9b. That would enable the library to ingest the API response, which usesschemaas the key, without issue, but would require developers using the library to useaction_schemaas the object property.To my mind, this tradeoff is worth it and when they remove the warning in that internal class field at some point we can remove the warning and continue normally. Having said that, I made the change in a separate commit so it would be easily dropped if we decide
action_schemais more appropriate.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.