AI Agents SDE Task Viewer
      • Context
      • Plan
      • Prd
  1. Home
  2. AgentSDE
  3. agent-core
  4. gh-547
  5. plan
  6. plan.md
plan.md(4.0 KB)· Apr 23, 2026· 2 min read
  • Summary
  • Files
  • Steps
  • Verification
  • Risks
  • Open Questions

Plan — BJ-7: JiraAdapter + webhook route#

Summary#

Add a JiraAdapter that normalizes Jira webhooks into DispatchEvent, expose POST /webhooks/jira, and extract HMAC-SHA256 into a shared helper so both adapters share one crypto path. Targets rc/atlassian-integration (Wave 2).

Files#

PathActionNotes
src/webhook/crypto.tscreateverifyHmacSha256(rawBody, signatureHeader, secret, prefix) — timingSafeEqual, throws UnauthorizedException
src/webhook/adapters/github.adapter.tsmodifyReplace inline HMAC block (lines 30–45) with verifyHmacSha256(..., 'sha256=')
src/webhook/adapters/github.adapter.spec.tsmodifyKeep existing coverage; no behavioural change
src/webhook/adapters/jira.adapter.tscreateImplements PlatformAdapter (platform='jira'); switches on body.webhookEvent
src/webhook/adapters/jira.adapter.spec.tscreateCovers 5 event types + signature + unknown-event ignore
src/webhook/webhook.controller.tsmodifyAdd @Post('jira') handler mirroring handleGitHub shape, reads JIRA_WEBHOOK_SECRET, signature header x-hub-signature
src/webhook/webhook.controller.spec.tsmodifyAdd cases: 401 on bad signature, 200 + dispatch on valid payload, 200 + ignored on unknown event
src/webhook/webhook.module.tsmodifyProvide JiraAdapter; register in onModuleInit()
src/webhook/dto/dispatch-event.dto.tsmodifyAdd 'issue_updated' and 'link_created' to DispatchEventType; add 'jira' to platform union (coordinate with #540)
src/config/config.schema.tsmodifyJIRA_WEBHOOK_SECRET: Joi.string().optional()
.env.examplemodifyDocument JIRA_WEBHOOK_SECRET
CLAUDE.mdmodifyNote JIRA_WEBHOOK_SECRET in env-var table

Steps#

  1. Extract verifyHmacSha256 into src/webhook/crypto.ts and refactor GitHubAdapter.verifySignature to delegate.
  2. Extend DispatchEventType with issue_updated and link_created; add 'jira' to the platform union; update .env.example, config.schema.ts, and CLAUDE.md for JIRA_WEBHOOK_SECRET.
  3. Implement JiraAdapter with the 5 event mappings (jira:issue_created→intake, jira:issue_updated→issue_updated with changelog inspection, jira:issue_deleted→task_cancelled, comment_created|comment_updated→issue_comment, jira:issuelink_created→link_created); unknown event returns { event: null, reason }.
  4. Add POST /webhooks/jira to WebhookController: read raw body, call adapter.verifySignature with header x-hub-signature and JIRA_WEBHOOK_SECRET, persist WebhookDeliveryEntity with source='jira', resolve tenant via TenantResolverService.resolveFromWebhook('jira', ...), dispatch.
  5. Register JiraAdapter in WebhookModule providers and onModuleInit().
  6. Write jira.adapter.spec.ts (event mapping, signature, graceful unknown) and extend webhook.controller.spec.ts with jira-route coverage; run npm run test and npm run lint.

Verification#

  • npm run test passes; new specs cover all 5 event types plus bad/missing signature and unknown webhookEvent.
  • npm run lint passes with zero warnings; npm run build succeeds.
  • GitHubAdapter behaviour unchanged — its existing spec continues to pass after crypto extraction.

Risks#

  • #540 (BJ-0) not yet merged — it also adds 'jira' to platform unions. Mitigation: include the union extension here if rc/atlassian-integration still lacks it at implementation time; rebase drops the duplicate once #540 lands.
  • Tenant resolution for Jira — TenantResolverService.resolveFromWebhook may not yet support 'jira'. Mitigation: fall back to { org: <configured>, source: 'jira' } and open a follow-up if the resolver needs Jira-specific logic.

Open Questions#

  • Should jira:issue_updated without a changelog field emit an issue_updated dispatch, or be ignored? Plan assumes emit (carry commentBody=undefined, no label info) per the issue's "graceful" guidance.
ContextPrd