Skip to content

feat(webhook): add JIRA webhook HMAC-SHA256 signature verification#978

Merged
aaight merged 1 commit intodevfrom
feature/jira-webhook-signature-verification
Mar 22, 2026
Merged

feat(webhook): add JIRA webhook HMAC-SHA256 signature verification#978
aaight merged 1 commit intodevfrom
feature/jira-webhook-signature-verification

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 22, 2026

Summary

  • Adds verifyJiraSignature() to src/webhook/signatureVerification.ts using HMAC-SHA256 with timing-safe comparison, following the exact same pattern as verifyGitHubSignature()
  • Adds verifyJiraWebhookSignature() to src/router/webhookVerification.ts as a verifySignature callback that resolves the project from the JIRA project key in the payload, looks up the webhook secret, and verifies the X-Hub-Signature header
  • Wires verifyJiraWebhookSignature into the JIRA createWebhookHandler() call in src/router/index.ts (previously missing — unlike GitHub and Trello which both had verification)
  • Extends resolveWebhookSecret() in credentials.ts to accept 'jira' as a provider (resolves webhook_secret from the PM integration)
  • Adds webhook_secret (optional) to JIRA credential roles in integrationRoles.ts
  • When no JIRA webhook secret is configured, verification is skipped (backwards compatible)
  • When a secret is configured, requests with missing or invalid signatures return 401

Test plan

  • verifyJiraSignature() unit tests: valid signature, invalid signature, missing/bad prefix, tampered body, empty body, garbage input, timing-safe length mismatch
  • verifyJiraWebhookSignature() unit tests: valid sig, wrong sig, missing header (with secret), no secret (skip), project not found (skip), missing project key (skip)
  • End-to-end Hono app tests: 200 on valid sig, 401 on wrong sig, 401 on missing header with secret, 200 on no secret, 200 on missing project, webhook_log entries on 401
  • extractJiraProjectKey() unit tests: extracts key, handles missing fields, handles invalid JSON
  • All 6279 unit tests passing
  • Zero lint errors (biome)
  • Zero TypeScript errors

Trello card: https://trello.com/c/4X6eqQSR/499-as-a-developer-i-want-jira-webhook-signature-verification-so-that-spoofed-jira-webhooks-are-rejected

🤖 Generated with Claude Code

🕵️ claude-code · claude-sonnet-4-6 · run details

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 22, 2026

Codecov Report

❌ Patch coverage is 90.90909% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/router/platformClients/credentials.ts 0.00% 4 Missing ⚠️
src/router/index.ts 0.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

LGTM — Clean, well-structured implementation that correctly mirrors the existing GitHub and Trello webhook signature verification patterns.

What I verified:

  • verifyJiraSignature() correctly uses HMAC-SHA256 with timingSafeEqual and a length guard before comparison — identical approach to verifyGitHubSignature().
  • verifyJiraWebhookSignature() follows the exact same callback pattern as the GitHub/Trello equivalents: extract identifier from payload → find project → resolve secret → verify (or skip when no secret/project).
  • extractJiraProjectKey() uses the same issue.fields.project.key path as JiraRouterAdapter.parseWebhook(), so verification and routing share the same assumptions about payload structure.
  • resolveWebhookSecret() extends cleanly with the 'jira' provider, resolving from pm category (consistent with JIRA being a PM integration).
  • The webhook_secret credential role is correctly marked optional: true for backwards compatibility.
  • The null return (skip verification) when no project key is found, no project matches, or no secret is configured is the correct backwards-compatible behavior.
  • Test coverage is thorough: low-level signature verification, callback-level verification, and end-to-end Hono app tests all covering valid, invalid, and skip scenarios.
  • All 7 CI checks pass.

Minor observation (not blocking): For comment_created/comment_updated JIRA events that may lack issue.fields.project.key, signature verification is silently skipped. This is consistent with how JiraRouterAdapter.parseWebhook() also returns null for these payloads (so they wouldn't be processed anyway), making it a non-issue in practice.

🕵️ claude-code · claude-opus-4-6 · run details

@aaight aaight merged commit 75d4595 into dev Mar 22, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants