Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1515ed7
fix most issues
jp-agenta Mar 12, 2026
5c68ba5
clean up notifications
jp-agenta Mar 12, 2026
a510c79
Merge branch 'release/v0.94.3' into fix/shady-webhooks
jp-agenta Mar 12, 2026
44dbb72
format / lint
jp-agenta Mar 12, 2026
64d5ba9
linf fix
jp-agenta Mar 12, 2026
fb4461a
Update web/oss/src/services/automations/api.ts
jp-agenta Mar 12, 2026
c51699e
Update web/oss/src/services/automations/api.ts
jp-agenta Mar 12, 2026
c27127d
Fix flow and bugs
jp-agenta Mar 13, 2026
aa6049b
fix copy
jp-agenta Mar 13, 2026
888fcd1
move Automation location in side menu
jp-agenta Mar 13, 2026
5dd787d
fix(frontend): lint fix in SecretRevealModal
mmabrouk Mar 13, 2026
3c7d436
fix(automations): keep saved webhooks active after save
mmabrouk Mar 13, 2026
c3e0f67
feat(automations): test draft webhooks before save
mmabrouk Mar 13, 2026
6612466
feat(automations): add delivery logs to the drawer
mmabrouk Mar 13, 2026
19023e2
fix(frontend): redesign delivery logs tab — simplify detail to raw JS…
mmabrouk Mar 13, 2026
178d6c0
fix(api,frontend): redact sensitive headers from webhook delivery rec…
mmabrouk Mar 13, 2026
3c75920
fix(api): redact sensitive headers from webhook delivery records
mmabrouk Mar 13, 2026
a7f850b
fix(frontend): keep automation logs scrolling contained
mmabrouk Mar 13, 2026
e953daa
Merge pull request #3988 from Agenta-AI/fix/redact-webhook-delivery-s…
mmabrouk Mar 13, 2026
63f91df
Merge branch 'fix/shady-webhooks' into fix/automations-draft-testing
mmabrouk Mar 13, 2026
5aa7945
fix(api): remove broken merge code from webhook task
mmabrouk Mar 13, 2026
2462142
fix(api): restore webhook header redaction in shared delivery helper
mmabrouk Mar 13, 2026
2c2c519
Merge remote-tracking branch 'origin/fix/automations-draft-testing' i…
mmabrouk Mar 13, 2026
618f57d
fix(api): persist edited webhook secrets when missing secret ids
mmabrouk Mar 13, 2026
d9c0582
Merge pull request #3987 from Agenta-AI/fix/automations-delivery-logs
mmabrouk Mar 16, 2026
6ae46fe
Merge pull request #3986 from Agenta-AI/fix/automations-draft-testing
mmabrouk Mar 16, 2026
1d1d879
fix(webhooks): simplify subscription testing and drop unused flags
mmabrouk Mar 16, 2026
ee11370
chore(webhooks): apply lint fixes
mmabrouk Mar 16, 2026
1faca53
fix(webhooks): remove old test endpoints
mmabrouk Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 71 additions & 20 deletions api/oss/src/apis/fastapi/webhooks/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from oss.src.utils.common import is_ee
from oss.src.utils.exceptions import intercept_exceptions
from oss.src.utils.logging import get_module_logger
from oss.src.utils.caching import (
AGENTA_CACHE_TTL,
get_cache,
Expand Down Expand Up @@ -37,6 +38,9 @@
from ee.src.utils.permissions import check_action_access, FORBIDDEN_EXCEPTION


log = get_module_logger(__name__)


class WebhooksRouter:
def __init__(
self,
Expand All @@ -50,7 +54,7 @@ def __init__(
# --- WEBHOOK SUBSCRIPTIONS ------------------------------------------ #

self.router.add_api_route(
"/",
"/subscriptions/",
self.create_subscription,
methods=["POST"],
operation_id="create_webhook_subscription",
Expand All @@ -59,7 +63,7 @@ def __init__(
status_code=status.HTTP_200_OK,
)
self.router.add_api_route(
"/{subscription_id}",
"/subscriptions/{subscription_id}",
self.fetch_subscription,
methods=["GET"],
operation_id="fetch_webhook_subscription",
Expand All @@ -68,7 +72,7 @@ def __init__(
status_code=status.HTTP_200_OK,
)
self.router.add_api_route(
"/{subscription_id}",
"/subscriptions/{subscription_id}",
self.edit_subscription,
methods=["PUT"],
operation_id="edit_webhook_subscription",
Expand All @@ -77,14 +81,14 @@ def __init__(
status_code=status.HTTP_200_OK,
)
self.router.add_api_route(
"/{subscription_id}",
"/subscriptions/{subscription_id}",
self.delete_subscription,
methods=["DELETE"],
operation_id="delete_webhook_subscription",
status_code=status.HTTP_204_NO_CONTENT,
)
self.router.add_api_route(
"/query",
"/subscriptions/query",
self.query_subscriptions,
methods=["POST"],
operation_id="query_webhook_subscriptions",
Expand All @@ -93,6 +97,16 @@ def __init__(
status_code=status.HTTP_200_OK,
)

self.router.add_api_route(
Comment thread
mmabrouk marked this conversation as resolved.
Outdated
"/subscriptions/{subscription_id}/test",
self.test_webhook,
methods=["POST"],
operation_id="test_webhook",
response_model=WebhookDeliveryResponse,
response_model_exclude_none=True,
status_code=status.HTTP_200_OK,
)

# --- WEBHOOK DELIVERIES --------------------------------------------- #

self.router.add_api_route(
Expand Down Expand Up @@ -123,18 +137,6 @@ def __init__(
status_code=status.HTTP_200_OK,
)

# --- WEBHOOK TEST --------------------------------------------------- #

self.router.add_api_route(
"/test/{subscription_id}",
self.test_webhook,
methods=["POST"],
operation_id="test_webhook",
response_model=WebhookDeliveryResponse,
response_model_exclude_none=True,
status_code=status.HTTP_200_OK,
)

# --- WEBHOOK SUBSCRIPTIONS ---------------------------------------------- #

@intercept_exceptions()
Expand Down Expand Up @@ -483,22 +485,51 @@ async def test_webhook(
if not has_permission:
raise FORBIDDEN_EXCEPTION # type: ignore

project_id = UUID(request.state.project_id)
user_id = str(request.state.user_id)

log.info(
"[WEBHOOKS API] Test webhook requested",
project_id=str(project_id),
subscription_id=str(subscription_id),
user_id=user_id,
)

try:
delivery = await self.webhooks_service.test_webhook(
project_id=UUID(request.state.project_id),
project_id=project_id,
#
subscription_id=subscription_id,
)

status_message = delivery.status.message if delivery.status else None
status_code = delivery.status.code if delivery.status else None

log.info(
"[WEBHOOKS API] Test webhook completed",
project_id=str(project_id),
subscription_id=str(subscription_id),
delivery_id=str(delivery.id),
event_id=str(delivery.event_id),
status_message=status_message,
status_code=status_code,
)

if delivery.status and delivery.status.message == "success":
log.info(
"[WEBHOOKS API] Invalidating webhook caches after successful test",
project_id=str(project_id),
subscription_id=str(subscription_id),
delivery_id=str(delivery.id),
)
await invalidate_cache(
namespace="webhooks",
project_id=str(request.state.project_id),
project_id=str(project_id),
key=f"subscription:{subscription_id}",
)
await invalidate_cache(
namespace="webhooks",
project_id=str(request.state.project_id),
project_id=str(project_id),
key="subscriptions",
)

Expand All @@ -507,11 +538,23 @@ async def test_webhook(
delivery=delivery,
)
except WebhookSubscriptionNotFoundError as e:
log.warning(
"[WEBHOOKS API] Test webhook failed: subscription not found",
project_id=str(project_id),
subscription_id=str(subscription_id),
)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
except WebhookTestEventPublishFailedError as e:
log.error(
"[WEBHOOKS API] Test webhook failed while publishing event",
project_id=str(project_id),
subscription_id=e.subscription_id,
event_id=e.event_id,
message=e.message,
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={
Expand All @@ -522,6 +565,14 @@ async def test_webhook(
},
) from e
except WebhookTestDeliveryTimeoutError as e:
log.error(
"[WEBHOOKS API] Test webhook timed out waiting for delivery",
project_id=str(project_id),
subscription_id=e.subscription_id,
event_id=e.event_id,
attempts=e.attempts,
message=e.message,
)
raise HTTPException(
status_code=status.HTTP_504_GATEWAY_TIMEOUT,
detail={
Expand Down
2 changes: 2 additions & 0 deletions api/oss/src/core/webhooks/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ async def edit_subscription(
user_id: UUID,
#
subscription: WebhookSubscriptionEdit,
#
secret_id: Optional[UUID] = None,
) -> Optional[WebhookSubscription]:
raise NotImplementedError

Expand Down
Loading
Loading