Skip to content

feat: FGA_5 list_resources_for_membership, list_memberships_for_resource, list_memberships_for_resource_by_external_id#571

Merged
swaroopAkkineniWorkos merged 16 commits intoENT-5224-python-sdk-for-fga-worktree-fuck-aroundfrom
fga-pr5
Mar 4, 2026
Merged

feat: FGA_5 list_resources_for_membership, list_memberships_for_resource, list_memberships_for_resource_by_external_id#571
swaroopAkkineniWorkos merged 16 commits intoENT-5224-python-sdk-for-fga-worktree-fuck-aroundfrom
fga-pr5

Conversation

@swaroopAkkineniWorkos
Copy link

…list_memberships_for_resource_by_external_id

Description

Documentation

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

[ ] Yes

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

…list_memberships_for_resource_by_external_id
@swaroopAkkineniWorkos
Copy link
Author

@greptile review

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@workos workos deleted a comment from greptile-apps bot Feb 23, 2026
@swaroopAkkineniWorkos
Copy link
Author

@greptile re-review

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@swaroopAkkineniWorkos swaroopAkkineniWorkos marked this pull request as ready for review February 23, 2026 17:52
@swaroopAkkineniWorkos swaroopAkkineniWorkos requested a review from a team as a code owner February 23, 2026 17:52
@swaroopAkkineniWorkos swaroopAkkineniWorkos requested review from atainter and gjtorikian and removed request for a team February 23, 2026 17:52
Copy link
Contributor

@csrbarber csrbarber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#556 (comment) is relevant to this PR

@workos workos deleted a comment from greptile-apps bot Mar 2, 2026
@swaroopAkkineniWorkos
Copy link
Author

@greptile re-review plz

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 2, 2026

Greptile Summary

This PR adds three new FGA methods to the Authorization and AsyncAuthorization classes — list_resources_for_membership, list_memberships_for_resource, and list_memberships_for_resource_by_external_id — along with the supporting types and test coverage. It also refactors the previously inline ParentResourceById/ParentResourceByExternalId TypedDicts into their own module (parent_resource_identifier.py).

Key changes:

  • list_resources_for_membership: fetches paginated resources accessible to a given organization membership under an optional parent resource, using partial() to bind the positional args for pagination continuation.
  • list_memberships_for_resource: fetches paginated memberships that have access to a resource by its internal ID.
  • list_memberships_for_resource_by_external_id: the same, but addressed via organization_id + resource_type_slug + external_id path params.
  • ParentResourceIdentifier types moved to a dedicated file and re-exported from the package __init__.
  • MockAuthorizationOrganizationMembershipList fixture added for the new membership-list tests.

Minor issues found:

  • An unused helper function _mock_membership in the test file should be cleaned up.
  • The mock_resources_list_two fixture in TestListResourcesForMembership uses the deprecated Pydantic v1 .dict() method; the adjacent fixture in TestListMembershipsForResource already uses .model_dump() correctly.

Confidence Score: 5/5

  • This PR is safe to merge; all new methods follow established patterns and no logic or security issues were found.
  • The implementation is consistent with the existing codebase patterns (partial-based pagination, separate sync/async classes, TypedDict filters). Both sync and async variants are implemented symmetrically. Test coverage is thorough across all three methods. The two flagged issues are minor style concerns in the test file only and do not affect runtime behaviour.
  • No files require special attention.

Important Files Changed

Filename Overview
src/workos/authorization.py Adds list_resources_for_membership, list_memberships_for_resource, and list_memberships_for_resource_by_external_id to both sync and async Authorization classes, using partial() correctly for pagination continuations. No logic issues found.
src/workos/types/authorization/init.py Exports AuthorizationOrganizationMembership and ParentResourceIdentifier (along with its sub-types) — correct and consistent with existing patterns.
src/workos/types/authorization/parent_resource_identifier.py Extracts ParentResourceById, ParentResourceByExternalId, and ParentResourceIdentifier Union into their own module; straightforward refactor of types previously inline in authorization.py.
tests/test_authorization_resource_memberships.py Comprehensive test coverage for all three new methods and both parent-resource identifier variants; contains an unused _mock_membership helper and uses the deprecated .dict() serialization in one fixture.
tests/utils/fixtures/mock_organization_membership.py Adds MockAuthorizationOrganizationMembershipList fixture with two pre-populated AuthorizationOrganizationMembership entries; correct use of model_dump().

Sequence Diagram

sequenceDiagram
    participant Caller
    participant Authorization
    participant HTTPClient
    participant WorkOSAPI

    Note over Caller,WorkOSAPI: list_resources_for_membership
    Caller->>Authorization: list_resources_for_membership(org_membership_id, permission_slug, parent_resource)
    Authorization->>HTTPClient: GET /authorization/organization_memberships/{id}/resources?permission_slug=...&parent_resource_id=...
    HTTPClient->>WorkOSAPI: HTTP GET
    WorkOSAPI-->>HTTPClient: paginated AuthorizationResource list
    HTTPClient-->>Authorization: response dict
    Authorization-->>Caller: WorkOSListResource[AuthorizationResource]

    Note over Caller,WorkOSAPI: list_memberships_for_resource
    Caller->>Authorization: list_memberships_for_resource(resource_id, permission_slug, assignment?)
    Authorization->>HTTPClient: GET /authorization/resources/{id}/organization_memberships?permission_slug=...
    HTTPClient->>WorkOSAPI: HTTP GET
    WorkOSAPI-->>HTTPClient: paginated OrganizationMembership list
    HTTPClient-->>Authorization: response dict
    Authorization-->>Caller: WorkOSListResource[AuthorizationOrganizationMembership]

    Note over Caller,WorkOSAPI: list_memberships_for_resource_by_external_id
    Caller->>Authorization: list_memberships_for_resource_by_external_id(org_id, resource_type_slug, external_id, permission_slug)
    Authorization->>HTTPClient: GET /authorization/organizations/{org_id}/resources/{type}/{ext_id}/organization_memberships
    HTTPClient->>WorkOSAPI: HTTP GET
    WorkOSAPI-->>HTTPClient: paginated OrganizationMembership list
    HTTPClient-->>Authorization: response dict
    Authorization-->>Caller: WorkOSListResource[AuthorizationOrganizationMembership]
Loading

Last reviewed commit: a973327

Comment on lines +16 to +33
def _mock_membership(
membership_id: str = "om_01ABC",
user_id: str = "user_123",
organization_id: str = "org_456",
organization_name: str = "Acme Inc",
status: str = "active",
) -> dict:
return {
"object": "organization_membership",
"id": membership_id,
"user_id": user_id,
"organization_id": organization_id,
"organization_name": organization_name,
"status": status,
"custom_attributes": None,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused helper function

The _mock_membership function is defined but never called anywhere in the test file. The tests instead rely on MockAuthorizationOrganizationMembershipList directly via the mock_memberships_list_two fixture. This dead code should either be removed or used in a test case.

Suggested change
def _mock_membership(
membership_id: str = "om_01ABC",
user_id: str = "user_123",
organization_id: str = "org_456",
organization_name: str = "Acme Inc",
status: str = "active",
) -> dict:
return {
"object": "organization_membership",
"id": membership_id,
"user_id": user_id,
"organization_id": organization_id,
"organization_name": organization_name,
"status": status,
"custom_attributes": None,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
}

(Remove lines 16–33 entirely)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it expected that this is not used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not expected - this is genuinely unused code. After reviewing the full test file, all tests rely on the mock_memberships_list_two fixture which returns MockAuthorizationOrganizationMembershipList().model_dump(). The _mock_membership helper function is never called anywhere.

Looking at similar test files in the codebase (like test_authorization_resource.py), they follow the same pattern: using fixture-based mock objects from classes like MockAuthorizationResource() rather than helper functions. The _mock_membership function appears to be leftover code that was either never used or replaced by the fixture approach.

You should remove it.


@pytest.fixture
def mock_resources_list_two(self):
return MockAuthorizationResourceList().dict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecated .dict() instead of .model_dump()

.dict() is a Pydantic v1 alias and is deprecated in Pydantic v2. The sibling fixture in TestListMembershipsForResource already uses .model_dump() correctly (line 446). Use .model_dump() here for consistency and to avoid deprecation warnings.

Suggested change
return MockAuthorizationResourceList().dict()
return MockAuthorizationResourceList().model_dump()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems valid

Copy link
Contributor

@atainter atainter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few minor things

parent_resource_type_slug: str
class AuthorizationOrganizationMembershipListFilters(ListArgs, total=False):
permission_slug: str
assignment: Optional[Literal["direct", "indirect"]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth making assignment a type since we'll most likely add it to the list resources for membership endpoint soon.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also referenced a few places so we won't have to redeclare the literals

Comment on lines +16 to +33
def _mock_membership(
membership_id: str = "om_01ABC",
user_id: str = "user_123",
organization_id: str = "org_456",
organization_name: str = "Acme Inc",
status: str = "active",
) -> dict:
return {
"object": "organization_membership",
"id": membership_id,
"user_id": user_id,
"organization_id": organization_id,
"organization_name": organization_name,
"status": status,
"custom_attributes": None,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it expected that this is not used?


@pytest.fixture
def mock_resources_list_two(self):
return MockAuthorizationResourceList().dict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems valid


assert response.object == "list"
assert len(response.data) == 2
assert response.data[0].id == "om_01ABC"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

worth checking all other fields are deserialized on these happy path tests?

@swaroopAkkineniWorkos swaroopAkkineniWorkos changed the title FGA_5: list_resources_for_membership, list_memberships_for_resource, list_memberships_for_resource_by_external_id feat: FGA_5 list_resources_for_membership, list_memberships_for_resource, list_memberships_for_resource_by_external_id Mar 4, 2026
@swaroopAkkineniWorkos swaroopAkkineniWorkos merged commit 08f1c84 into ENT-5224-python-sdk-for-fga-worktree-fuck-around Mar 4, 2026
11 checks passed
@swaroopAkkineniWorkos swaroopAkkineniWorkos deleted the fga-pr5 branch March 4, 2026 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants