Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(elation): add rate limiting to webhooks #579

Merged

Conversation

bejoinka
Copy link
Contributor

@bejoinka bejoinka commented Feb 6, 2025

No description provided.

Copy link

github-actions bot commented Feb 6, 2025

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Rate Limiting Logic

The newly added rate limiting logic should be reviewed to ensure it correctly handles edge cases, such as different rateLimitDuration values and unique hash generation for webhook payloads.

onEvent: async ({
  payload: { payload, settings },
  onSuccess,
  onError,
  helpers,
}) => {
  const { action, resource, data } = payload
  const { rateLimitDuration } = settings
  const { id: appointmentId, patient: patientId } = data

  // skip non 'saved'  actions for that webhook
  if (action !== 'saved') {
    return
  }

  if (rateLimitDuration) {
    const rateLimiter = helpers.rateLimit(1, rateLimitDuration as Duration)
    const strAppt = JSON.stringify(data)
    const uniqueHash = createHash('sha256').update(strAppt).digest('hex')
    const { success } = await rateLimiter.limit(uniqueHash)
    if (!success) {
      console.log(`ELATION: Rate limited for appointment_id=${appointmentId}`)
      // we're sending a 200 response to elation to avoid them retrying the request
      await onError({
        response: {
          statusCode: 200,
          message: 'Rate limit exceeded',
        },
      })
      return
    }
  }
Rate Limiting Implementation

The rate limiting implementation for patient webhooks should be validated to ensure it functions as intended and does not inadvertently block valid requests.

onEvent: async ({
  payload: { payload, settings },
  onSuccess,
  onError,
  helpers,
}) => {
  const { data, resource, action } = payload
  const { rateLimitDuration } = settings
  const { id: patientId } = data

  // skip non 'saved' actions for that webhook
  if (action !== 'saved') {
    return
  }

  if (rateLimitDuration) {
    const rateLimiter = helpers.rateLimit(1, rateLimitDuration as Duration)
    const strPatient = JSON.stringify(data)
    const uniqueHash = createHash('sha256').update(strPatient).digest('hex')
    const { success } = await rateLimiter.limit(uniqueHash)
    if (!success) {
      console.log(`ELATION: Rate limited for patient_id=${patientId}`)
      // we're sending a 200 response to elation to avoid them retrying the request
      await onError({
        response: {
          statusCode: 200,
          message: 'Rate limit exceeded',
        },
      })
      return
    }
  }

Copy link

github-actions bot commented Feb 6, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Validate rateLimitDuration input format

Ensure that the rateLimitDuration value is validated before being passed to the
helpers.rateLimit function to prevent runtime errors caused by invalid or malformed
input.

extensions/elation/webhooks/appointmentCreatedOrUpdated.ts [42-43]

-const rateLimiter = helpers.rateLimit(1, rateLimitDuration as Duration)
+if (typeof rateLimitDuration === 'string' && /^[0-9]+[smhd]$/.test(rateLimitDuration)) {
+  const rateLimiter = helpers.rateLimit(1, rateLimitDuration as Duration)
+} else {
+  await onError({
+    response: {
+      statusCode: 400,
+      message: 'Invalid rateLimitDuration format',
+    },
+  })
+  return
+}
Suggestion importance[1-10]: 9

__

Why: This suggestion ensures that the rateLimitDuration value is validated before being passed to the helpers.rateLimit function, preventing potential runtime errors due to invalid or malformed input. It directly addresses a critical issue that could lead to unexpected behavior or crashes.

High
General
Improve logging for rate limit events

Log errors using a more robust logging mechanism instead of console.log to ensure
better traceability and monitoring in production environments.

extensions/elation/webhooks/appointmentCreatedOrUpdated.ts [47-48]

-console.log(`ELATION: Rate limited for appointment_id=${appointmentId}`)
+helpers.logger.warn(`ELATION: Rate limited for appointment_id=${appointmentId}`)
Suggestion importance[1-10]: 7

__

Why: Replacing console.log with a structured logging mechanism improves traceability and monitoring in production environments. This enhances observability and aligns with best practices for error logging.

Medium
Enhance logging for rate limit events

Replace console.log with a structured logging mechanism to provide better
observability and debugging capabilities in production.

extensions/elation/webhooks/patientCreatedOrUpdated.ts [47-48]

-console.log(`ELATION: Rate limited for patient_id=${patientId}`)
+helpers.logger.warn(`ELATION: Rate limited for patient_id=${patientId}`)
Suggestion importance[1-10]: 7

__

Why: Using a structured logging mechanism instead of console.log provides better observability and debugging capabilities in production. This is a valuable improvement for monitoring and maintaining the system.

Medium

@bejoinka bejoinka force-pushed the et-904-prevent-multiple-care-flows-triggered-by-elation-webhook branch from 0b743ec to c75c581 Compare February 6, 2025 04:03
@bejoinka bejoinka merged commit b3523f0 into main Feb 6, 2025
2 checks passed
@bejoinka bejoinka deleted the et-904-prevent-multiple-care-flows-triggered-by-elation-webhook branch February 6, 2025 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant