fix(webhook): restore provider contracts and readiness - #90479
aviyashchin wants to merge 2 commits into
Conversation
Reviewed the diff. Three solid restorations in one: (1) the payload-ID dedup fallback is carefully bounded — route-scoped via JSON array encoding, scalar-only with bool/empty rejection, and strictly below trusted delivery headers, with tests proving both single-invocation retries and header-priority preservation plus an explicit no-secret/no-payload-leak assertion; (2) provider signature support (Linear/Attio/`X-Signature`) keeps the commit-to-V2 semantics intact — malformed V2 still never downgrades to body-only V1 — and `removeprefix("sha256=")` normalization matches what most emit; any attacker-supplied extra header can only cause additional strict comparisons, so mixed-header games fail closed; (3) the GET readiness endpoint deliberately touches none of the POST pipeline (no auth/rate/dedup/agent), verified by state-preservation assertions. One design point to make explicit:
Nit: the V2 comment block lost some of its original rationale (the mixed-header downgrade attack walkthrough) in this refactor — that reasoning is exactly what stops a future cleanup from re-nesting the V2 check inside `if generic_sig:`; worth preserving somewhere. No blocking issues found. |
What
Why
Generic HMAC-only handling rejects valid provider callbacks whose documented signature formats differ, while missing readiness and payload-level deduplication make production subscriptions hard to verify and allow provider retries to enqueue the same event twice.
Validation
scripts/run_tests.sh tests/gateway/test_webhook_adapter.py tests/gateway/test_webhook_session_close.py tests/gateway/test_webhook_route_toolsets.py tests/gateway/test_webhook_deliver_only.py tests/gateway/test_webhook_signature_rate_limit.py tests/gateway/test_webhook_integration.py tests/gateway/test_webhook_dynamic_routes.py