MT-22022: Add webhook signature verification helper#67
Conversation
📝 WalkthroughWalkthroughThis PR adds webhook signature verification to the Mailtrap Python SDK using HMAC-SHA256 constant-time comparison. The implementation includes core validation logic, module exports, comprehensive tests with shared fixture constants, and user-facing documentation with examples. ChangesWebhook signature verification
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add `mailtrap.webhooks.verify_signature` (re-exported as `mt.verify_signature`) to verify Mailtrap webhook signatures using HMAC-SHA256 over the raw request body with constant-time hex comparison via `hmac.compare_digest`. Returns False (no raise) for missing/empty/malformed/wrong-length signatures so a single guard at the request handler covers every bad-input case. Accepts both `str` and `bytes` payloads; signed input must be the raw body bytes (the helper docstring and example warn against re-serializing parsed JSON). Includes the shared cross-SDK test fixture (payload + secret + expected signature) that all six Mailtrap SDKs use to stay byte-for-byte compatible, plus a Flask receiver example and README subsection. See https://railsware.atlassian.net/browse/MT-22022
35b2788 to
129bc81
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
README.md (1)
249-274: 💤 Low valueClear and accurate webhook signature documentation.
The explanation of HMAC-SHA256 verification is well-written, and the important warning about using raw request body bytes (not re-serialized JSON) is prominently placed.
Consider adding a brief note about framework-specific approaches for obtaining the raw request body, e.g.:
**Framework examples:** - Flask: `raw_body = request.get_data()` - FastAPI: `raw_body = await request.body()` - Django: `raw_body = request.body`This would help users who are unfamiliar with accessing raw request bodies in their chosen framework, though the current framework-agnostic approach is also valid.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 249 - 274, Add a short framework-specific note under the "Verifying webhook signatures" section to show how to obtain the raw request body for common Python frameworks (e.g., Flask, FastAPI, Django) so users can correctly pass raw_body to mt.verify_signature; reference the Mailtrap-Signature header and the signing_secret usage, and keep the note concise and clearly labeled (e.g., "Framework examples") to avoid changing the existing verification guidance.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@README.md`:
- Around line 249-274: Add a short framework-specific note under the "Verifying
webhook signatures" section to show how to obtain the raw request body for
common Python frameworks (e.g., Flask, FastAPI, Django) so users can correctly
pass raw_body to mt.verify_signature; reference the Mailtrap-Signature header
and the signing_secret usage, and keep the note concise and clearly labeled
(e.g., "Framework examples") to avoid changing the existing verification
guidance.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 99d05986-8255-4a01-bbc5-c16791711838
📒 Files selected for processing (5)
README.mdexamples/webhooks/verify_signature.pymailtrap/__init__.pymailtrap/webhooks.pytests/unit/test_webhook_signature.py
Motivation
Expose a helper so Python users don't have to re-implement Mailtrap's HMAC-SHA256 webhook signature check on every receiver.
Changes
mailtrap.webhooks.verify_signature(payload, signature, signing_secret)→True/False. Re-exported asmailtrap.verify_signatureformt.verify_signature(...)usage. HMAC-SHA256 over the raw body, constant-time compare viahmac.compare_digest. Acceptspayloadasstr(UTF-8) orbytes. ReturnsFalse(never raises) on empty / wrong-length / non-hex / wrong-type inputs.tests/unit/test_webhook_signature.pypins the cross-SDK fixture (payload + signing_secret + expected digest) shared verbatim across all six official Mailtrap SDKs to guarantee byte-for-byte parity.examples/webhooks/verify_signature.py— runnable usage snippet.How to test
pytest tests/unit/test_webhook_signature.py -v— 10 examples, 0 failurespytest— full suite, 461 passedpre-commit run --all-files— all checks passmypy ./mailtrap— Success: no issues found in 63 source filespython examples/webhooks/verify_signature.py— exits 0Companion PRs
Coordinated rollout across all six official SDKs (same algorithm, same shared fixture):