GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Implement the remaining Audit Logs functionality by birdcar · Pull Request #515 · workos/workos-python

Conversation

@birdcar

@birdcar birdcar commented Jan 14, 2026

Copy link
Copy Markdown
Contributor

Description

This will update the Audit Logs module to complete the endpoints available in the API reference.

Important review callout

This change creates an AuditLogAction type, which uses schema as a field name directly. Why is this important to call out? Because in previous versions of Pydantic, schema was a reserved word used internally by the Pydantic BaseModel. In v2 or Pydantic, they replaced the use of schema with model_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 schema field 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.version when working with an AuditLogAction object (which matches our API response exactly) as opposed to having to use an alias like action.action_schema.version.

Alternates I considered

As just mentioned, I originally avoided the issue by using a Field with a defined alias in cf5ce9b. That would enable the library to ingest the API response, which uses schema as the key, without issue, but would require developers using the library to use action_schema as 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_schema is more appropriate.

Documentation

Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.

[x] Yes

If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@birdcar birdcar self-assigned this Jan 14, 2026
@birdcar
birdcar requested a review from a team as a code owner January 14, 2026 16:12
@birdcar
birdcar requested a review from gjtorikian January 14, 2026 16:12
@birdcar birdcar added the enhancement New feature or request label Jan 14, 2026
@greptile-apps

greptile-apps Bot commented Jan 14, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Greptile Summary

This 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:

  • Added AsyncAuditLogs class implementation and enabled it in AsyncClient
  • Implemented 7 new methods across sync/async variants: create_schema, list_schemas, list_actions, get_retention, set_retention, get_configuration
  • Created 5 new Pydantic models: AuditLogAction, AuditLogSchema, AuditLogConfiguration, AuditLogStream, AuditLogRetention
  • Leveraged Pydantic v2's schema field handling by suppressing the deprecation warning for BaseModel.schema(), allowing the AuditLogAction.schema field to match the API response exactly
  • Updated test suite to use @pytest.mark.sync_and_async decorator with comprehensive test coverage for all new endpoints
  • Replaced asyncio.iscoroutinefunction with inspect.iscoroutinefunction in test utilities for better compatibility

Implementation Quality:

  • Consistent with existing codebase patterns (type hints, error handling, pagination)
  • Comprehensive test coverage including success cases, error cases, and parameter validation
  • Proper use of WorkOSListResource for paginated endpoints
  • Type-safe with proper Literal types for constrained values (retention periods, states)
  • Documentation strings on all new models and methods

Confidence Score: 5/5

  • This PR is safe to merge with no concerns
  • The implementation is thorough, well-tested, and follows all established patterns in the codebase. The Pydantic v2 schema field handling is appropriate and well-documented. All new endpoints have comprehensive test coverage for both sync and async variants, and the code follows the SDK's architecture consistently.
  • No files require special attention

Important Files Changed

Filename Overview
src/workos/async_client.py Enabled async audit logs support by replacing NotImplementedError with AsyncAuditLogs initialization
src/workos/audit_logs.py Added complete audit logs API implementation with sync/async variants for schemas, actions, retention, and configuration endpoints
src/workos/types/audit_logs/audit_log_action.py Introduced AuditLogAction type with 'schema' field, handled Pydantic v2 warning suppression
tests/test_audit_logs.py Comprehensive test coverage for all new audit logs endpoints with sync/async variants

Sequence Diagram

sequenceDiagram
    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
Loading
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot]
greptile-apps Bot reviewed Jan 14, 2026
View reviewed changes

@greptile-apps greptile-apps Bot left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

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)

  1. tests/test_audit_logs.py, line 7 (link)

    style: Check that AsyncAuditLogs is 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

Edit Code Review Agent Settings | Greptile

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@birdcar

birdcar commented Jan 14, 2026

Copy link
Copy Markdown
Contributor Author

Gonna update with that feedback from greptile, una momento

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@birdcar

birdcar commented Jan 14, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot]
greptile-apps Bot reviewed Jan 14, 2026
View reviewed changes

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

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

Edit Code Review Agent Settings | Greptile

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@birdcar

birdcar commented Jan 14, 2026

Copy link
Copy Markdown
Contributor Author

Alright, this is ready to go whenever ✌️ Gonna move on to other improvements 🔜

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

birdcar added 4 commits January 14, 2026 17:26
@birdcar
Add the rest of the Audit Logs implementation
59b572e
@birdcar
Replace asyncio.iscoroutinefunction with inspect
787a6db
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.
@birdcar
Use 'schema' field and handle pydantic's warning
61bb3b7
@birdcar
Test sync and async variants propertly
733353f
@birdcar
birdcar force-pushed the birdcar/complete-audit-log-endpoints branch from 95e10a3 to 733353f Compare January 14, 2026 23:26
gjtorikian added 2 commits January 21, 2026 15:43
@gjtorikian
Merge branch 'main' into birdcar/complete-audit-log-endpoints
e1ce952
@gjtorikian
it's in now
e251b8f
gjtorikian
gjtorikian reviewed Jan 21, 2026
View reviewed changes

@gjtorikian gjtorikian left a comment

Copy link
Copy Markdown
Contributor

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!

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread 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,

@gjtorikian gjtorikian Jan 21, 2026

Copy link
Copy Markdown
Contributor

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.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@birdcar birdcar Jan 22, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

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: MetadataSchemaInput

Which 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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@gjtorikian gjtorikian Jan 22, 2026

Copy link
Copy Markdown
Contributor

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 🤙

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@birdcar birdcar Jan 22, 2026

Copy link
Copy Markdown
Contributor Author

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).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread src/workos/types/audit_logs/audit_log_schema.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/workos/types/audit_logs/audit_log_action.py
warnings.filterwarnings(
"ignore",
message='Field name "schema" in "AuditLogAction" shadows an attribute',
category=UserWarning,

@gjtorikian gjtorikian Jan 21, 2026

Copy link
Copy Markdown
Contributor

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)?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@birdcar birdcar Jan 22, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@gjtorikian gjtorikian Jan 22, 2026

Copy link
Copy Markdown
Contributor

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
birdcar added 4 commits January 21, 2026 19:19
@birdcar
feat(audit-logs): Add typed inputs for create_schema
b06dd5f
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.
@birdcar
refactor(audit-logs): Use typed inputs in create_schema
800d577
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.
@birdcar
fix(audit-logs): Make optional fields nullable in response models
9393a52
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.
@birdcar
test(audit-logs): Update tests for simplified input format
9eb6738
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).
gjtorikian
gjtorikian approved these changes Jan 22, 2026
View reviewed changes
gjtorikian
gjtorikian approved these changes Jan 22, 2026
View reviewed changes
@gjtorikian
gjtorikian merged commit 4483636 into main Jan 22, 2026
11 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@gjtorikian
gjtorikian deleted the birdcar/complete-audit-log-endpoints branch January 22, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@greptile-apps greptile-apps[bot] greptile-apps[bot] left review comments
@gjtorikian gjtorikian gjtorikian approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@birdcar birdcar

Labels

enhancement New feature or request

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@birdcar @gjtorikian
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.