Repository navigation
fix(webhooks): read the signature header ClickUp and Linear actually send - #1645
Merged
Merged
Conversation
…send `ClickUpProvider` looked for `X-Clickup-Signature` and `LinearProvider` for `X-Linear-Signature`. Neither product sends those. ClickUp signs with `X-Signature` and Linear with `Linear-Signature`, so `verify` found no header, returned False, and `WebhookAppEnvironment` raised 401 before `parse` ever ran. With `require_signature=True` — the default — both integrations rejected every genuine delivery. The test suite could not see it. Each plugin's `SAMPLE_DELIVERY` signs with the same wrong header its `verify` reads, so the conformance round trip verified against itself and passed. The per-plugin `_parse` helpers also built signature headers that `parse` ignores entirely, which spread the wrong name without testing anything. So each provider now gets a test asserting the literal wire header, which is the one thing the self-consistent round trip cannot check, and `_parse` no longer fabricates headers it does not use. `_CREDENTIAL_HEADERS` in the shared conformance helper needed the new names too. That set gates the hostile-credential check by header name and `continue`s on anything unlisted, so a rename silently turned the check off for that provider rather than failing — the same way the round trip hid the bug itself. It now asserts that it matched a header. GitHub (`X-Hub-Signature-256`) and Slack (`X-Slack-Signature`) were verified correct against their docs and are untouched. Jira's `X-Webhook-Token` is the plugin's own shared-token stand-in, since Jira Cloud does not sign webhooks. Refs: https://developer.clickup.com/docs/webhooksignature Refs: https://linear.app/developers/webhooks Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Oct 2, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while triaging GitHub Copilot's review of unionai/unionai-docs#1673, which flagged the ClickUp header as its three high-severity findings. They're one bug, and it belongs here rather than in the docs. Linear has the same bug; Copilot did not catch that one.
The bug
ClickUpProviderlooked forX-Clickup-Signature; ClickUp signs withX-Signature.LinearProviderlooked forX-Linear-Signature; Linear signs withLinear-Signature.Neither header is present on a real delivery, so
verifyhit itsif not signatureguard, returnedFalse, and_app.pyraised 401 beforeparseever ran. Withrequire_signature=True— the default — both integrations rejected every genuine webhook. Not a degraded path: nothing got through.Verified against the vendor docs (ClickUp, Linear). I checked the other three providers too: GitHub
X-Hub-Signature-256and SlackX-Slack-Signatureare correct and untouched, and Jira'sX-Webhook-Tokenis the plugin's own shared-token stand-in because Jira Cloud doesn't sign webhooks at all.Why CI was green
Each plugin's
SAMPLE_DELIVERYsigns with the same wrong header its ownverifyreads, soassert_provider_conformsverified the sample against itself and passed. The round trip is self-consistent no matter what the header is called — it can never catch this class of bug.The per-plugin
_parsehelpers also built signature headers thatparseignores entirely. They tested nothing and propagated the wrong name into two more files.Changes
clickup/_provider.py,linear/_provider.py)._sample_headersemits the real header, soSAMPLE_DELIVERYnow mirrors an actual delivery._parsehelpers — stop fabricating headersparsedoesn't read._CREDENTIAL_HEADERSgates the hostile-credential check by header name andcontinues on anything unlisted, so renaming a header silently switched that check off instead of failing. Updated the names and made a no-match assert, so it can't degrade to a no-op the same way again.plugins/clickup/README.md,plugins/linear/README.md,plugins/README-saas-integrations.md.Verification
tests/flyte/extras/webhooks,tests/flyte/app/extras/test_webhook_app.py)._CREDENTIAL_HEADERSguard. Two independent nets now catch it.ruff check,ruff format --check, and the pre-commitfmt/mypy/tyhooks pass. No dependency orpyproject.tomlchanges, so theuv.lockgate is untouched.Docs follow-up
unionai/unionai-docs#1673 should regenerate the
content/api-reference/.../clickup/pages after this merges (they render the docstrings above) and hand-editcontent/integrations/saas-integrations/clickup.md. The Linear pages in that PR need the same correction, which the review didn't flag. The remaining low-severity comments there are docs-wording only and imply no further SDK change.🤖 Generated with Claude Code