Skip to content

feat(emailbison): block, tools#4470

Open
icecrasher321 wants to merge 3 commits intostagingfrom
feat/emailbison
Open

feat(emailbison): block, tools#4470
icecrasher321 wants to merge 3 commits intostagingfrom
feat/emailbison

Conversation

@icecrasher321
Copy link
Copy Markdown
Collaborator

Summary

Email Bison tools (https://emailbison.com/)

Type of Change

  • New feature

Testing

WIP

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel Bot commented May 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment May 6, 2026 6:23am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 6, 2026

PR Summary

Medium Risk
Adds a new external API integration with multiple read/write operations and parameter parsing, which could affect runtime behavior and error handling when calling Email Bison endpoints. Changes are largely additive and isolated but touch shared registries and generated icon mappings.

Overview
Adds a new Email Bison integration end-to-end: a new block (EmailBisonBlock) with UI configuration for 13 operations (leads, campaigns, replies, tags) and wiring into the block/tool registries so it’s available in the product.

Introduces a new apps/sim/tools/emailbison toolset (request builders, response mappers/types, and shared utils) that calls Email Bison’s API using bearer-token auth, plus landing-page integration metadata and a new EmailBisonIcon registered in both docs and sim icon maps.

Documentation is extended with a new emailbison.mdx tools page and the tools index is updated to include emailbison; additionally, PostHog docs rename personalApiKey to apiKey in several tool parameter tables.

Reviewed by Cursor Bugbot for commit b3f6a09. Configure here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b3f6a09. Configure here.

},
},
request: {
url: (params) => emailBisonUrl(`/api/campaigns/${params.campaignId}/update`),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Campaign updates hit wrong endpoint

Medium Severity

The emailbison_update_campaign tool sends campaign update requests to /api/campaigns/{id}/update. The Email Bison API, however, expects these updates at /api/campaigns/{id}, causing all campaign setting updates to fail.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b3f6a09. Configure here.

},
request: {
url: (params) => emailBisonUrl(`/api/campaigns/${params.campaignId}/${params.action}`),
method: 'PATCH',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Status updates use wrong method

Medium Severity

emailbison_update_campaign_status sends status actions with PATCH, while Email Bison’s campaign action endpoint uses POST. The default pause action fails before users can manage campaign state.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b3f6a09. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 6, 2026

Greptile Summary

This PR adds full Email Bison integration to Sim — a block definition, 13 tool implementations (leads, campaigns, replies, tags), icon, docs, and registry entries. The architecture follows established patterns well, with a clean shared utilities layer and proper TypeScript types throughout.

  • utils.ts / all tools: emailBisonData calls response.json() without checking response.ok, so any 4xx/5xx from the Email Bison API silently becomes a generic "response did not include a valid X" error, hiding the actual API error message (e.g., "Unauthorized", "Not found").
  • update_campaign_status.ts: params.action is interpolated directly into the URL path without encodeURIComponent, creating a potential path traversal vector for callers who bypass the block UI; additionally, the tool declares campaignOutputs as its response shape but status-action endpoints likely return a lightweight success/message body rather than a full campaign object.

Confidence Score: 3/5

The integration is structurally sound but has two runtime issues that affect all 13 tools and the campaign status action endpoint before merging.

The HTTP error masking in emailBisonData affects every single tool — any API error gives users an opaque internal error instead of the actual reason. The update_campaign_status URL construction passes params.action unencoded into the path, and its response mapping assumes a full campaign object from endpoints that likely return a lightweight action result.

apps/sim/tools/emailbison/utils.ts (impacts all 13 tools) and apps/sim/tools/emailbison/update_campaign_status.ts need attention before merge.

Security Review

  • Path traversal via unencoded action in URL (apps/sim/tools/emailbison/update_campaign_status.ts, line 43): params.action is interpolated directly into the URL path without encodeURIComponent. Since new URL() does not re-encode path segments, a caller supplying "pause/../../target" as action would navigate to an unintended path on the API domain.
  • No HTTP error status check before parsing (apps/sim/tools/emailbison/utils.ts, emailBisonData): Authentication errors and API failures are silently swallowed and replaced with generic messages, which may mask credential exposure indicators in error responses.

Important Files Changed

Filename Overview
apps/sim/tools/emailbison/utils.ts Shared utilities for Email Bison tools; HTTP responses are parsed without checking response.ok, causing API errors (401, 404, 500) to surface as misleading generic messages instead of the actual API error.
apps/sim/tools/emailbison/update_campaign_status.ts Pause/resume/archive campaign tool; params.action is interpolated into the URL path without encodeURIComponent, and the declared output shape (full campaign) may not match what action endpoints actually return.
apps/sim/blocks/blocks/emailbison.ts Block definition wiring 13 operations; parameter transformation logic is correct but the name mapping ternary is convoluted.
apps/sim/tools/emailbison/types.ts Type definitions for all Email Bison params and responses; well-structured with nullable fields and proper union types for response variants.
apps/sim/tools/emailbison/attach_leads_to_campaign.ts Attach leads to campaign tool; correctly uses actionOutputs shape and actionOutput mapper, consistent with what the action endpoint likely returns.
apps/sim/tools/registry.ts Registers all 13 Email Bison tools in the global tool registry with correct IDs matching the block's tools.access list.

Sequence Diagram

sequenceDiagram
    participant UI as Block UI
    participant Block as EmailBisonBlock
    participant Tool as Tool (e.g. list_leads)
    participant Utils as utils.ts
    participant API as Email Bison API

    UI->>Block: User selects operation + fills inputs
    Block->>Block: tools.config.params() transforms inputs
    Block->>Tool: Dispatches to emailbison_{operation}
    Tool->>Utils: emailBisonUrl() builds URL
    Tool->>Utils: emailBisonHeaders() adds Bearer token
    Tool->>API: fetch(url, { method, headers, body })
    API-->>Tool: Response (2xx or 4xx/5xx)
    Tool->>Utils: emailBisonData() or emailBisonArrayData()
    Note over Utils: response.ok NOT checked
    Utils->>Utils: response.json() expects {data: ...}
    Utils-->>Tool: mapped data or throws generic error
    Tool-->>Block: { success: true, output: ... }
    Block-->>UI: Rendered output
Loading

Comments Outside Diff (1)

  1. apps/sim/blocks/blocks/emailbison.ts, line 1130-1136 (link)

    P2 name mapping ternary is convoluted

    The ternary for name falls through to emptyToUndefined(params.campaignName) for update_campaign. This is correct, but the logic is hard to follow and error-prone if new operations are added. The nested ternary could be simplified into a plain switch or early-return helper to make the mapping intent explicit.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "typecheck issue" | Re-trigger Greptile

Comment on lines +52 to +55
export async function emailBisonData<T>(response: Response): Promise<T | null> {
const payload = (await response.json()) as EmailBisonEnvelope<T>
return payload.data ?? null
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 HTTP error responses silently produce misleading errors

response.json() is called unconditionally without checking response.ok. When Email Bison returns a 4xx/5xx (e.g., {"error": "Unauthorized"}), payload.data is undefined, so emailBisonData returns null. Callers then throw the generic "Email Bison response did not include a valid X" message, completely hiding the actual API error. Users see no actionable reason for the failure (wrong API key, resource not found, etc.).

Suggested change
export async function emailBisonData<T>(response: Response): Promise<T | null> {
const payload = (await response.json()) as EmailBisonEnvelope<T>
return payload.data ?? null
}
export async function emailBisonData<T>(response: Response): Promise<T | null> {
const payload = (await response.json()) as EmailBisonEnvelope<T> & { error?: string; message?: string }
if (!response.ok) {
const reason = payload.error ?? payload.message ?? `HTTP ${response.status}`
throw new Error(`Email Bison API error: ${reason}`)
}
return payload.data ?? null
}

},
},
request: {
url: (params) => emailBisonUrl(`/api/campaigns/${params.campaignId}/${params.action}`),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 security Unvalidated string in URL path construction

params.action is a raw string interpolated directly into the URL path without encodeURIComponent. The emailBisonUrl helper passes the path string to new URL(path, base), which does NOT percent-encode path segments already in the string. If action is "pause/../../admin", the resulting URL normalizes to the base domain's /admin path. TypeScript's union type and the block dropdown prevent this in normal UI flow, but the tool can also be invoked directly via the tool API without those guards.

Comment on lines +47 to +55
transformResponse: async (response) => {
const data = await emailBisonRecordData(response, 'campaign')

return {
success: true,
output: mapCampaign(data),
}
},
outputs: campaignOutputs,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Response shape mismatch for status-action endpoints

The tool declares campaignOutputs as its output schema and calls mapCampaign(data), expecting a full campaign object. However, action endpoints like /pause, /resume, and /archive typically return a lightweight success/status response rather than the complete campaign record. If the API returns {"data": {"success": true, "message": "Campaign paused"}}, mapCampaign will silently produce a campaign object full of null values, discarding the success/message fields. Consider whether actionOutputs / actionOutput (as used in attach_leads_to_campaign.ts) is the correct shape here.

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.

1 participant