Conversation
Greptile SummaryThis PR adds a standalone
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant C as Client (sync/async)
participant FF as FeatureFlags module
participant H as HTTPClient
participant API as WorkOS API
C->>FF: list_feature_flags(limit, before, after, order)
FF->>H: GET /feature-flags?limit=...
H->>API: GET /feature-flags
API-->>H: { data: [...], list_metadata: {...} }
H-->>FF: response dict
FF-->>C: FeatureFlagsListResource
C->>FF: get_feature_flag(slug)
FF->>H: GET /feature-flags/{slug}
H->>API: GET /feature-flags/{slug}
API-->>H: feature flag object
H-->>FF: response dict
FF-->>C: FeatureFlag
C->>FF: enable_feature_flag(slug)
FF->>H: PUT /feature-flags/{slug}/enable (body: {})
H->>API: PUT /feature-flags/{slug}/enable
API-->>H: updated feature flag
H-->>FF: response dict
FF-->>C: FeatureFlag (enabled=true)
C->>FF: disable_feature_flag(slug)
FF->>H: PUT /feature-flags/{slug}/disable (body: {})
H->>API: PUT /feature-flags/{slug}/disable
API-->>H: updated feature flag
H-->>FF: response dict
FF-->>C: FeatureFlag (enabled=false)
C->>FF: add_feature_flag_target(slug, resource_id)
FF->>H: POST /feature-flags/{slug}/targets/{resource_id} (body: {})
H->>API: POST /feature-flags/{slug}/targets/{resource_id}
API-->>H: 200 OK
H-->>FF: (ignored)
FF-->>C: None
C->>FF: remove_feature_flag_target(slug, resource_id)
FF->>H: DELETE /feature-flags/{slug}/targets/{resource_id}
H->>API: DELETE /feature-flags/{slug}/targets/{resource_id}
API-->>H: 200 OK
H-->>FF: (ignored)
FF-->>C: None
Last reviewed commit: "improve feature flag..." |
| def add_feature_flag_target(self, slug: str, resource_id: str) -> None: | ||
| self._http_client.request( | ||
| f"{FEATURE_FLAGS_PATH}/{slug}/targets/{resource_id}", | ||
| method=REQUEST_METHOD_POST, | ||
| json={}, | ||
| ) |
There was a problem hiding this comment.
resource_id interpolated directly into URL path
resource_id is supplied by the caller and is embedded verbatim into the URL path. The docstring documents the expected format as user_<id> or org_<id>, but there is no validation or URL-encoding applied. A value containing /, ?, or # would silently alter the request URL.
The same pattern applies to slug throughout the module, and this is consistent with how other modules in the SDK build paths. Since WorkOS-generated IDs won't contain these characters in practice, the risk is low — but a lightweight guard (e.g., urllib.parse.quote) on resource_id (and similarly for slug) would make the surface more robust against malformed input:
from urllib.parse import quote
f"{FEATURE_FLAGS_PATH}/{quote(slug)}/targets/{quote(resource_id)}"This also applies to the same pattern in the AsyncFeatureFlags counterpart (line 241–244).
There was a problem hiding this comment.
This is low-risk and consistent with how some other modules handle it but if you'd like me to do this, I am happy to!
Summary
Adds a standalone
FeatureFlagsmodule to the SDK for managing feature flags via the WorkOS API. Previously, feature flag support was limited to scoped list queries onOrganizationsandUserManagement, but this change fills in the rest of the API surface.What changed
New module:
workos.feature_flagsExposes the following operations through
client.feature_flags:list_feature_flags()— paginated list of all flags (GET /feature-flags)get_feature_flag(slug)— fetch a single flag by slug (GET /feature-flags/{slug})enable_feature_flag(slug)/disable_feature_flag(slug)— toggle flags (PUT /feature-flags/{slug}/enable|disable)add_feature_flag_target(slug, resource_id)— add a user or org as a target (POST /feature-flags/{slug}/targets/{resourceId})remove_feature_flag_target(slug, resource_id)— remove a target (DELETE /feature-flags/{slug}/targets/{resourceId})Both sync and async clients are supported.
Updated
FeatureFlagmodelThe existing model was missing a few fields that the API actually returns. Added
tags,enabled, anddefault_value.Housekeeping
Moved the
FeatureFlagsListResourcetype alias out oforganizations.pyinto the newfeature_flagsmodule so there's a single definition.organizations.pyanduser_management.pynow import it from there.Test plan
tests/test_feature_flags.pycovering all 6 endpoints (sync + async)Documentation
Does this require changes to the WorkOS Docs? For example, does the API Reference or any code snippets need updates?
If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.
Closes #472