-
Notifications
You must be signed in to change notification settings - Fork 124
[Integration][Okta] Added live events for okta integration #2204
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
[Integration][Okta] Added live events for okta integration #2204
Conversation
…ps://github.com/port-labs/ocean into PORT-16361-add-support-for-okta-resource-resync
…ttps://github.com/port-labs/ocean into PORT-16361-add-support-for-okta-resource-resync-new
You are nearing your monthly Qodo Merge usage quota. For more information, please visit here. PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
You are nearing your monthly Qodo Merge usage quota. For more information, please visit here. PR Code Suggestions ✨Explore these optional code suggestions:
|
…to PORT-16361-add-support-for-okta-resource-new-live-event
…ttps://github.com/port-labs/ocean into PORT-16361-add-support-for-okta-resource-resync-new
…to PORT-16361-add-support-for-okta-resource-new-live-event
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.
Pull Request Overview
This PR adds live events support for the Okta integration by implementing webhook processors for both user and group events. The integration can now receive real-time event notifications from Okta and automatically sync changes to Port Ocean entities.
- Added webhook processors for user and group lifecycle events
- Implemented custom webhook manager with Okta verification challenge support
- Created automatic event hook setup and management in Okta
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
main.py | Added webhook processor registration and event hook creation on startup |
integration.py | Implemented custom webhook manager and handler mixins for Okta verification |
utils.py | Added Okta event types and subscription definitions |
webhook_processors/ | Created complete webhook processing infrastructure for users and groups |
tests/ | Added comprehensive test coverage for webhook processors |
spec.yaml | Added optional webhook secret configuration |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
integrations/okta/okta/webhook_processors/base_webhook_processor.py
Outdated
Show resolved
Hide resolved
integrations/okta/okta/webhook_processors/base_webhook_processor.py
Outdated
Show resolved
Hide resolved
integrations/okta/okta/webhook_processors/base_webhook_processor.py
Outdated
Show resolved
Hide resolved
async def should_process_event(self, event: WebhookEvent) -> bool: | ||
"""Authenticate webhook using optional Authorization header if provided. | ||
|
||
Okta Event Hooks support an authScheme that forwards a static header (e.g., Authorization) | ||
with each call. If a webhook_secret is configured, we expect the Authorization header | ||
to match it exactly. If no secret configured, accept events. | ||
""" | ||
if event._original_request is None: | ||
return False | ||
|
||
webhook_secret = ocean.integration_config.get("webhook_secret") | ||
if not webhook_secret: | ||
logger.info( | ||
"No secret configured for Okta incoming webhooks; accepting event without signature validation." | ||
) | ||
return True | ||
|
||
provided = event.headers.get("authorization", "") | ||
return provided == webhook_secret |
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.
use this to check for the event types, whether they matter to the handler
for event_object in events: | ||
event_type = event_object.get("eventType") | ||
if not isinstance(event_type, str) or event_type not in allowed: | ||
continue | ||
for target in event_object.get("target", []): | ||
if target.get("type") == target_type and target.get("id"): | ||
return True |
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.
They send different event types for a single webhook ?
allowed_event_types: Iterable[str], | ||
target_type: str, | ||
) -> bool: | ||
events = payload.get("data", {}).get("events") |
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.
the event payload can be empty ?
updated: list[dict[str, Any]] = [] | ||
deleted: list[dict[str, Any]] = [] | ||
|
||
for event_object in payload.get("data", {}).get("events", []): |
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.
at this point, we should be 100% sure data and event are not empty, this is check in validate_payload
event_type = event_object.get("eventType", "") | ||
for target in event_object.get("target", []): |
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.
we should be sure here, use indexing
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.
create utils for the repeated logics if possible
async def validate_payload(self, payload: EventPayload) -> bool: | ||
"""Basic validation: ensure payload has data.events list.""" | ||
return isinstance(payload, dict) and isinstance(payload["data"]["events"], list) |
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.
in the handlers I see you confidently expect eventType
and target
to be present,
validate their existence here to eliminate the possibility of a Keyerror in the handlers
for event_object in payload["data"]["events"]: | ||
event_type = event_object["eventType"] | ||
for target in event_object["target"]: | ||
if target["type"] == "UserGroup" and target["id"]: | ||
group_id = target["id"] | ||
if event_type == OktaEventType.GROUP_LIFECYCLE_DELETE.value: | ||
deleted.append({"id": group_id}) |
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.
repeated logic
targets = event_object["target"] | ||
for target in targets: | ||
if target["type"] == "UserGroup" and target["id"]: | ||
return True |
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.
repeated logic ?
targets = event_object["target"] | ||
for target in targets: | ||
if target["type"] == "User" and target["id"]: | ||
return True |
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.
repeated logic ?
for target in targets: | ||
is_user_target = target["type"] == "User" and target["id"] | ||
if not is_user_target: | ||
continue |
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.
this appears to be a repeated logic, lets a util for 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.
LGTM
event_type = event_object["eventType"] | ||
targets = event_object["target"] |
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.
.get
…' of https://github.com/port-labs/ocean into PORT-16361-add-support-for-okta-resource-new-live-event
User description
Description
What - Added live events for okta integration to cover both user and group kinds
Why -
How - Created webhook processors to process relevant events
Type of change
Please leave one option from the following and delete the rest:
All tests should be run against the port production environment(using a testing org).
Core testing checklist
Integration testing checklist
examples
folder in the integration directory.Preflight checklist
Screenshots
Include screenshots from your environment showing how the resources of the integration will look.
API Documentation
Provide links to the API documentation used for this integration.
PR Type
Enhancement
Description
Added live events support for Okta integration
Implemented webhook processors for user and group events
Created custom webhook manager with Okta verification challenge
Added automatic event hook creation and management
Diagram Walkthrough
File Walkthrough
8 files
Added custom webhook manager and handler mixins
Integrated webhook processors and event hook setup
Added Okta event types and subscription definitions
Created webhook processors package initialization
Implemented base webhook processor with authentication
Created group-specific webhook event processor
Created user-specific webhook event processor
Added Okta event hook management client
1 files
Added webhook secret configuration option