fix: cap rendered webhook prompts

maintainer edit: prevent custom webhook templates from enqueueing the full request body into the agent/session path. Reuses the existing prompt cap and adds regression coverage for {{ body }}.
This commit is contained in:
chengyongru 2026-06-25 10:00:59 +08:00
parent 8943f87818
commit 7283556048
2 changed files with 32 additions and 1 deletions

View File

@ -363,7 +363,7 @@ def _render_prompt(route: WebhookRouteConfig, context: dict[str, Any]) -> str:
raise WebhookError(400, f"webhook prompt template failed: {exc}") from exc
if not rendered.strip():
raise WebhookError(400, "webhook prompt template rendered empty content")
return rendered
return truncate_text(rendered, _DEFAULT_PROMPT_MAX_CHARS)
def _render_thread(route: WebhookRouteConfig, context: dict[str, Any]) -> str:

View File

@ -117,6 +117,37 @@ async def test_generic_webhook_accepts_hmac_signature() -> None:
assert "untrusted external data" in msg.content
@pytest.mark.asyncio
async def test_custom_prompt_is_truncated_after_rendering() -> None:
bus = MessageBus()
router = WebhookRouter(
WebhooksConfig(
routes={
"big": WebhookRouteConfig(
auth="none",
to="websocket:ops",
prompt="{{ body }}",
)
}
),
bus,
)
body = b"a" * 1_048_576
response = await router.handle(
method="POST",
path="/webhooks/big",
headers={},
body=body,
)
assert response is not None
assert response.status == 202
msg = await bus.consume_inbound()
assert len(msg.content) < len(body)
assert msg.content.endswith("\n... (truncated)")
@pytest.mark.asyncio
async def test_webhook_without_delivery_id_is_not_deduped() -> None:
bus = MessageBus()