Skip to content

#425 Add DELETE /api/webhooks/:id route with confirmation token and cascading delivery cleanup FIXED - #1139

Closed
veloura-dev wants to merge 1 commit into
CalloraOrg:mainfrom
veloura-dev:#425-Add-DELETE-/api/webhooks/-id-route-with-confirmation-token-and-cascading-delivery-cleanup-FIX
Closed

#425 Add DELETE /api/webhooks/:id route with confirmation token and cascading delivery cleanup FIXED#1139
veloura-dev wants to merge 1 commit into
CalloraOrg:mainfrom
veloura-dev:#425-Add-DELETE-/api/webhooks/-id-route-with-confirmation-token-and-cascading-delivery-cleanup-FIX

Conversation

@veloura-dev

Copy link
Copy Markdown

CLOSE #425

**1. Findings

  1. Existing Single-Step Deletion Risk:
    • Previously, DELETE /api/webhooks/:developerId across both routing layers (src/webhooks/webhook.routes.ts and src/routes/webhooks.ts) executed an immediate, single-step deletion (WebhookStore.delete(developerId)).
    • There was no confirmation token mechanism to protect against accidental removal of production webhook subscriptions.
  2. Missing Delivery Attempt Cleanup & Tracking:
    • When a webhook subscription was deleted, existing operational logs (failedDeliveryLog and Dead-Letter Queue entries in deadLetterStore) were left behind in memory without cleanup.
    • While dispatchWebhook (src/webhooks/webhook.dispatcher.ts) logged delivery attempts to logger, it did not record individual delivery attempt records in a dedicated store (webhook_delivery_attempts) that could be inspected or pruned upon subscription deletion.
  3. Dual Webhook Routing Layers:
    • The repository maintains two webhook routing modules (src/webhooks/webhook.routes.ts and src/routes/webhooks.ts). To ensure consistent behavior regardless of which router is mounted or tested, both needed to support two-step delete, token verification, delivery attempt pruning, and database audit row persistence (appendAuditRow / auditStateChange).
  4. Pre-Existing Build & Test Instabilities:
    • src/index.ts had duplicate import statements and variable declarations (proxyDrainTracker) resulting from a stale merge conflict on main.
    • Test suites that mocked logger.js without exporting PINO_REDACT_PATHS caused Pino initialization to crash (pino – redact must contain an array of strings) whenever src/middleware/logging.ts was loaded.
    • An obsolete April 2026 test file (src/webhooks/webhook.integration.test.ts) tested a non-existent demo endpoint (POST /api/webhooks expecting x-webhook-signature), which conflicted with the real POST /api/webhooks registration endpoint.

2. Fix Features Implemented

  1. Two-Step Deletion Protocol (POST /api/webhooks/:developerId/delete-token & DELETE /api/webhooks/:developerId)

    • Step 1 — Issue Confirmation Token (POST /api/webhooks/:developerId/delete-token):
      • Issues a secure 32-byte cryptographic hex token (64 characters) with a 5-minute TTL (300,000 ms).
      • Returns a structured JSON payload:
        {
          "message": "Webhook deletion confirmation token issued.",
          "developerId": "dev-123",
          "token": "d9f8e7a6...",
          "expires_at": "2026-08-01T12:25:00.000Z",
          "expiresInMs": 300000
        }
      • Emits WEBHOOK_DELETE_TOKEN_ISSUED audit logs (logger.audit) and persistent database audit rows (appendAuditRow).
    • Step 2 — Enforced Deletion with Token (DELETE /api/webhooks/:developerId):
      • Accepts the confirmation token via query parameter (?token=...), HTTP header (x-confirm-token, x-callora-delete-token, x-confirmation-token), or JSON request body ({ "token": "..." }).
      • Token Enforcement: Calling DELETE without a valid token is blocked with structured HTTP 400 error envelopes:
        • MISSING_TOKEN — No token provided.
        • INVALID_TOKEN — Token does not match the stored token for this developer subscription.
        • EXPIRED_TOKEN — Token has exceeded its 5-minute TTL.
      • 404 Handling: Rejects requests for non-existent developer subscriptions with HTTP 404 (WEBHOOK_NOT_FOUND).
  2. Single Transaction Subscription + Delivery Cleanup (WebhookStore.deleteSubscriptionWithCleanup)

    • Implemented WebhookStore.deleteSubscriptionWithCleanup(developerId, token) in src/webhooks/webhook.store.ts.
    • Because synchronous operations on JavaScript Maps and Arrays execute atomically on the single thread, this method executes a single atomic transaction that:
      1. Deletes the webhook subscription (WebhookConfig).
      2. Deletes the used confirmation token and any other pending deletion tokens for developerId.
      3. Prunes all delivery attempt records for developerId:
        • Prunes all entries in deliveryAttempts (webhook_delivery_attempts).
        • Prunes all entries in failedDeliveryLog.
        • Prunes all Dead-Letter Queue entries in deadLetterStore.
    • Returns an operational result envelope:
      {
        "message": "Webhook removed.",
        "developerId": "dev-123",
        "prunedDeliveryAttempts": 5
      }
  3. Delivery Attempt Tracking (webhook_delivery_attempts)

    • Implemented WebhookDeliveryAttempt record tracking in WebhookStore (src/webhooks/webhook.store.ts) with methods recordDeliveryAttempt, getDeliveryAttempts(developerId), and clearDeliveryAttempts().
    • Wired WebhookStore.recordDeliveryAttempt(...) into dispatchWebhook (src/webhooks/webhook.dispatcher.ts) so every delivery attempt—whether successful, non-2xx HTTP response, or network/timeout failure—is recorded in deliveryAttempts.
  4. Comprehensive Audit Event Logging

    • Both POST /delete-token and DELETE /:developerId emit:
      • Structured application access logs via logger.info.
      • Structured audit trail events via logger.audit (WEBHOOK_DELETE_TOKEN_ISSUED and WEBHOOK_DELETED).
      • Persistent database audit rows via appendAuditRow / auditStateChange, capturing the before subscription state and after: null on deletion.
  5. OpenAPI Specification & Contract Documentation

    • Updated src/openapi.yaml to document /api/webhooks/{developerId}/delete-token (POST) and /api/webhooks/{developerId} (DELETE) with complete request parameters, request bodies, and response schemas (WebhookDeleteTokenResponse, WebhookDeleteResponse, and StandardErrorEnvelope examples for 400 and 404 errors).
  6. High Code Coverage & Dedicated Tests

    • Created src/webhooks/webhook.store.test.ts to test all unit methods on WebhookStore, achieving 100% statement, line, and function coverage.
    • Added describe('DELETE /api/webhooks/:developerId - Two-Step Delete & Authorization') to tests/integration/webhooks.test.ts, covering token issuance, valid two-step deletion, token expiry, invalid token rejection, missing token rejection, and delivery attempt pruning.
    • Updated src/routes/webhooks.test.ts to assert that database audit rows (WEBHOOK_DELETE_TOKEN_ISSUED and WEBHOOK_DELETED) are written during the two-step delete flow.

@drips-wave

drips-wave Bot commented Aug 1, 2026

Copy link
Copy Markdown

@veloura-dev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@veloura-dev veloura-dev closed this by deleting the head repository Aug 1, 2026
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.

Add DELETE /api/webhooks/:id route with confirmation token and cascading delivery cleanup

2 participants