Strip whitespace (blank → None) and reject non-ASCII-token characters
to prevent impossible header lookups that would fail all signed requests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Not all webhook providers use X-Hub-Signature-256 or X-Webhook-Signature.
Add an optional signature_header field so users can specify which header
carries the HMAC signature. When set, that exact header is checked;
when unset, the existing auto-detect fallback is preserved. The custom
header is also excluded from stored/exposed payload headers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous field_validator approach passed `cls` as the first argument
to `_normalize_secret`, which only accepted `v`, causing a TypeError at
runtime. Switch to `Annotated[str | None, BeforeValidator(...)]` which
calls the function with just the value and also eliminates the repeated
validator assignment in both schema classes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move blank/whitespace-only secret normalization to a shared
field_validator on both BoardWebhookCreate and BoardWebhookUpdate.
This ensures consistent behavior across create and update paths
and removes the inline normalization from the endpoint handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Webhook ingest endpoint was completely unauthenticated. Add an optional
`secret` field to BoardWebhook. When configured, inbound requests must
include a valid HMAC-SHA256 signature in X-Hub-Signature-256 or
X-Webhook-Signature headers. Uses hmac.compare_digest for timing safety.
Includes migration to add the secret column.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>