Skip to content

feat(Composio): add Composio plugin - #344

Open
adiafk wants to merge 53 commits into
corsairdev:mainfrom
adiafk:feat/composio-plugin
Open

adiafk wants to merge 53 commits into
corsairdev:mainfrom
adiafk:feat/composio-plugin

Conversation

@adiafk

@adiafk adiafk commented Jul 4, 2026 •

Copy link
Copy Markdown

Description

Adds the Composio plugin (@corsair-dev/composio) on Composio REST v3.1 (https://backend.composio.dev/api/v3.1).

It covers the 19 operations of the composio toolkit listed on corsair.dev/oss/composio that Composio still serves. It also adds the REST calls needed to use them: create a session, list/get/execute tools, list toolkits, and manage connected accounts.

Composio runs its meta tools on two routes:

  • Catalog tools run through POST /tools/execute/{slug}.
  • Session-only tools run through POST /tool_router/session/{session_id}/execute_meta with { slug, arguments }. Composio rejects these outside a session. Call sessions.create first to get a session_id.

Operations

corsair.dev op Endpoint HTTP
COMPOSIO_CHECK_ACTIVE_CONNECTION meta.checkActiveConnection POST /tools/execute/COMPOSIO_CHECK_ACTIVE_CONNECTION
COMPOSIO_CHECK_ACTIVE_CONNECTIONS meta.checkActiveConnections POST /tools/execute/COMPOSIO_CHECK_ACTIVE_CONNECTIONS
COMPOSIO_CREATE_PLAN meta.createPlan POST /tools/execute/COMPOSIO_CREATE_PLAN
COMPOSIO_ENABLE_TRIGGER meta.enableTrigger POST /tools/execute/COMPOSIO_ENABLE_TRIGGER
COMPOSIO_EXECUTE_TOOL meta.executeTool POST /tools/execute/COMPOSIO_EXECUTE_TOOL
COMPOSIO_GET_DEPENDENCY_GRAPH meta.getDependencyGraph POST /tools/execute/COMPOSIO_GET_DEPENDENCY_GRAPH
COMPOSIO_GET_REQUIRED_PARAMETERS meta.getRequiredParameters POST /tools/execute/COMPOSIO_GET_REQUIRED_PARAMETERS
COMPOSIO_GET_RESPONSE_SCHEMA meta.getResponseSchema POST /tools/execute/COMPOSIO_GET_RESPONSE_SCHEMA
COMPOSIO_INITIATE_CONNECTION meta.initiateConnection POST /tools/execute/COMPOSIO_INITIATE_CONNECTION
COMPOSIO_LIST_TOOLKITS meta.listToolkits POST /tools/execute/COMPOSIO_LIST_TOOLKITS
COMPOSIO_LIST_TRIGGERS meta.listTriggers POST /tools/execute/COMPOSIO_LIST_TRIGGERS
COMPOSIO_WAIT_FOR_CONNECTION meta.waitForConnection POST /tools/execute/COMPOSIO_WAIT_FOR_CONNECTION
COMPOSIO_GET_TOOL_SCHEMAS meta.getToolSchemas POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_MANAGE_CONNECTIONS meta.manageConnections POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_MULTI_EXECUTE_TOOL meta.multiExecuteTool POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_REMOTE_BASH_TOOL meta.remoteBashTool POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_REMOTE_WORKBENCH meta.remoteWorkbench POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_SEARCH_TOOLS meta.searchTools POST /tool_router/session/{session_id}/execute_meta
COMPOSIO_WAIT_FOR_CONNECTIONS meta.waitForConnections POST /tool_router/session/{session_id}/execute_meta
(support) sessions.create POST /tool_router/session
(support) tools.list GET /tools
(support) tools.get GET /tools/{tool_slug}
(support) tools.execute POST /tools/execute/{tool_slug}
(support) toolkits.list GET /toolkits
(support) connections.list GET /connected_accounts
(support) connections.create POST /connected_accounts/link
(support) connections.delete DELETE /connected_accounts/{id}

Argument shapes follow the Composio toolkit reference. Routes and response shapes follow the v3.1 OpenAPI spec.

Not implemented

Six ops listed on corsair.dev are no longer served by Composio:

  • COMPOSIO_UPSERT_RECIPE and COMPOSIO_GET_RECIPE were session meta tools. Composio removed them from the execute_meta slug enum, and the Composio CLI changelog records the removal (entry 5f004ff: "These slugs were removed from @composio/client").
  • COMPOSIO_CREATE_UPDATE_RECIPE, COMPOSIO_EXECUTE_RECIPE, COMPOSIO_GET_RECIPE_DETAILS and COMPOSIO_DOWNLOAD_S3_FILE are not in the current composio toolkit (version 20260917_00, 19 tools), and v3.1 has no recipe or S3 download endpoint.

Database entities

Entities mirror the v3.1 response objects (tools, toolkits, connected accounts, tool router session) and are written with upsertByEntityId. A failed write logs a warning and never fails the API call.

Entity Entity id Written by
tools tool slug tools.list, tools.get
toolkits toolkit slug toolkits.list
connectedAccounts connected account id connections.list (row removed by connections.delete)
sessions session_id sessions.create

connectedAccounts leaves out the API's state and data fields because they hold OAuth tokens and API keys.

Auth

Project API key, sent as the x-api-key header. Configure it with composio({ key }) or the api_key auth type.

Webhooks

None. corsair.dev lists no triggers for this integration, so the plugin defines no webhooks.

Tests

api.test.ts stubs fetch with real Response objects. For every endpoint it asserts the exact method, URL, query, body and API key header, and it compares the parsed result against a literal value. It also checks that:

  • an input_required session result parses,
  • a 401 becomes ComposioAPIError and is not retried,
  • a 429 passes Retry-After through to the rate-limit handler with no extra transport retry,
  • a response with the wrong shape is rejected,
  • each entity is written under its id, connected accounts are saved without credential state, connections.delete drops the row, and a failing write does not fail the call.

error-handlers.test.ts covers the retry handlers.

Live test

The project key available for this run is rejected by Composio, so no authenticated call could run. Every request still reached backend.composio.dev and returned the documented 401 error body (APIKey_InvalidAPIKey), which confirms the host and each path below:

Request Result
GET /api/v3.1/tools, /toolkits 401 documented error
GET /api/v3.1/tools/COMPOSIO_SEARCH_TOOLS and the six unlisted recipe/S3 slugs 401 documented error (auth runs before slug lookup, so availability is shown by the v3.1 OpenAPI spec and toolkit docs above, not by this call)

Checklist

Before submitting your PR, please verify the following:

  • I have run pnpm lint and all checks pass
  • I have run pnpm typecheck and there are no TypeScript errors
  • I have run pnpm build and all packages build successfully
  • I have run pnpm test and all tests pass
  • I have added or updated tests where applicable
  • I have added or updated necessary documentation

Screenshots / Demos (if applicable)

Screenshot 2026-08-04 at 1 43 34 PM

Additional Notes

Auth uses the project API key via x-api-key, not Connect MCP ck_ consumer keys.

adiafk added 4 commits July 4, 2026 23:49
- Add @corsair-dev/composio package with build config
- Register composio in core constants (BaseProviders, AllProviders)
- Implement REST client for backend.composio.dev/api
- Add rate limit and auth error handlers
- Define entity schemas for tools, connections, actions
- Tools: list and get tools/integrations
- Actions: list, get, and execute actions on connected apps
- Connections: list, create, and delete authenticated connections
- Apps: list available apps
- Implement trigger.fired, connection.status, action.completed webhooks
- Wire up composio() factory function with key builder, endpoint meta, and webhook matcher
- Export all endpoint and webhook types
@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

@adityalowanshi is attempting to deploy a commit to the corsair Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added the core Changes in packages/corsair label Jul 4, 2026
@greptile-apps

greptile-apps Bot commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium impact] The latest changes appear safe to merge; no new blocking issue was found.

Summary

Adds the Composio plugin with 27 operations, project API-key auth, four synced entities, and endpoint tests.

  • Corsair now offers a typed Composio plugin for REST v3.1.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Caller[Caller] --> Binder[Corsair endpoint binder]
  Binder --> Input[Validate input with Zod]
  Input --> API[Composio v3.1 API]
  API --> Output[Validate response with Zod]
  Output --> Store[Save supported entities]
  Store --> Result[Return result]
  Input --> Errors[Plugin error handlers]
  API --> Errors
Loading

Reviews (15) · Last reviewed commit: "fix(composio): validate endpoint inputs" · Reviewed by Greptile

adiafk added 5 commits July 4, 2026 23:58
- Add @corsair-dev/composio package with build config
- Register composio in core constants (BaseProviders, AllProviders)
- Implement REST client for backend.composio.dev/api
- Add rate limit and auth error handlers
- Define entity schemas for tools, connections, actions
- Tools: list and get tools/integrations
- Actions: list, get, and execute actions on connected apps
- Connections: list, create, and delete authenticated connections
- Apps: list available apps
- Implement trigger.fired, connection.status, action.completed webhooks
- Wire up composio() factory function with key builder, endpoint meta, and webhook matcher
- Export all endpoint and webhook types
- Implement real HMAC signature verification in verifyComposioWebhookSignature using verifyHmacSignature from corsair/http
- Guard JSON.parse in parseBody with try/catch to prevent crash on malformed webhook bodies
- Add explanatory comments to type assertions in all endpoint files
@adiafk
adiafk force-pushed the feat/composio-plugin branch from e508a33 to 0febbd2 Compare July 4, 2026 18:28
@adiafk adiafk changed the title feat: add Composio plugin feat( Composeio ): add Composio plugin Jul 4, 2026
@adiafk adiafk changed the title feat( Composeio ): add Composio plugin feat(Composeio): add Composio plugin Jul 4, 2026
@coderabbitai

coderabbitai Bot commented Aug 4, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 91939151-58fc-4642-9fae-b24a5c725cff

📥 Commits

Reviewing files that changed from the base of the PR and between a4d9463 and 17603de.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • packages/composio/api.test.ts
  • packages/composio/client.ts
  • packages/composio/endpoints/actions.ts
  • packages/composio/endpoints/apps.ts
  • packages/composio/endpoints/connections.ts
  • packages/composio/endpoints/index.ts
  • packages/composio/endpoints/tools.ts
  • packages/composio/endpoints/types.ts
  • packages/composio/error-handlers.ts
  • packages/composio/index.ts
  • packages/composio/jest.config.cjs
  • packages/composio/package.json
  • packages/composio/schema/database.ts
  • packages/composio/schema/index.ts
  • packages/composio/tsconfig.json
  • packages/composio/tsup.config.ts
  • packages/composio/webhooks.test.ts
  • packages/composio/webhooks/index.ts
  • packages/composio/webhooks/triggers.ts
  • packages/composio/webhooks/types.ts
  • packages/corsair/core/constants.ts
🚧 Files skipped from review as they are similar to previous changes (19)
  • packages/composio/tsup.config.ts
  • packages/composio/tsconfig.json
  • packages/composio/package.json
  • packages/composio/webhooks/index.ts
  • packages/composio/error-handlers.ts
  • packages/composio/schema/index.ts
  • packages/composio/jest.config.cjs
  • packages/corsair/core/constants.ts
  • packages/composio/client.ts
  • packages/composio/endpoints/tools.ts
  • packages/composio/endpoints/connections.ts
  • packages/composio/endpoints/apps.ts
  • packages/composio/api.test.ts
  • packages/composio/schema/database.ts
  • packages/composio/endpoints/actions.ts
  • packages/composio/endpoints/types.ts
  • packages/composio/webhooks/triggers.ts
  • packages/composio/endpoints/index.ts
  • packages/composio/webhooks/types.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Walkthrough

Added the @corsair-dev/composio package with Composio v3 API endpoints, typed schemas, API-key authentication, Standard Webhooks verification, event triggers, retry handlers, tests, and Corsair provider registration.

Changes

Composio provider integration

Layer / File(s) Summary
Data contracts and package foundation
packages/composio/endpoints/types.ts, packages/composio/schema/*, packages/composio/package.json, packages/composio/*config*
Added Zod schemas, endpoint types, database entity schemas, package metadata, and build/test configuration.
API client and endpoint implementations
packages/composio/client.ts, packages/composio/endpoints/*, packages/composio/api.test.ts
Added authenticated Composio v3 requests for tools, actions, connected accounts, and toolkits. Tests validate v3 paths and reject v1 paths.
Webhook signature verification and handlers
packages/composio/webhooks/*, packages/composio/webhooks.test.ts
Added Standard Webhooks verification, event matching, message and project-event handlers, and signature validation tests.
Plugin assembly and provider registration
packages/composio/index.ts, packages/composio/error-handlers.ts, packages/corsair/core/constants.ts
Added plugin contracts, endpoint and webhook wiring, API-key configuration, retry handling, metadata, factory construction, and Composio provider registration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • corsairdev/corsair#353: Both PRs add provider plugins with API clients, typed endpoints, schemas, error handlers, package configuration, and provider registration.
  • corsairdev/corsair#610: Both PRs add webhook signature verification that returns HTTP 401 for invalid requests.
  • corsairdev/corsair#647: Both PRs register a provider in the shared provider constants.

Suggested labels: plugin

Suggested reviewers: mayank-saraswal

Merge Risk: ⚪ Minimal · up to 17603

The Composio integration and webhook handling introduce no actionable merge-blocking risk in the supplied evidence, so the PR is merge-ready after normal checks and review.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed The changes implement Composio v3 endpoints, API-key authentication, typed validation, error handling, retries, webhook verification, tests, and provider registration required by issue #344.
Out of Scope Changes check Passed The reviewed changes are directly related to the Composio plugin, its endpoints, webhooks, validation, tests, packaging, and provider registration.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely identifies the main change: adding the Composio plugin. It matches the pull request objectives and changeset.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator

@greptile review

Comment thread packages/composio/webhooks/types.ts Outdated
Comment thread packages/composio/webhooks/types.ts Outdated

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (7)
packages/composio/webhooks.test.ts (1)

14-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the whsec_ key path.

Line 15 uses a bare secret. This test does not exercise the Standard Webhooks decoding branch in packages/composio/webhooks/types.ts Lines 85-94. Add a valid whsec_<base64> fixture and sign with the decoded raw key.

Proposed test
@@
 	it('accepts a valid Standard Webhooks signature', () => {
 		const signature = sign(secret, id, ts, body);
@@
 		expect(result.valid).toBe(true);
 	});
+
+	it('accepts a valid `whsec_` secret', () => {
+		const result = verifyComposioWebhookSignature(
+			{
+				rawBody: body,
+				headers: {
+					'webhook-id': id,
+					'webhook-timestamp': ts,
+					'webhook-signature': sign(secret, id, ts, body),
+				},
+				payload: JSON.parse(body),
+			} as never,
+			`whsec_${Buffer.from(secret, 'utf8').toString('base64')}`,
+		);
+
+		expect(result.valid).toBe(true);
+	});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/webhooks.test.ts` around lines 14 - 39, Update the “accepts
a valid Standard Webhooks signature” test and its secret fixture to use a valid
whsec_<base64> key, and generate the signature with the decoded raw key so
verifyComposioWebhookSignature exercises the Standard Webhooks decoding branch.
packages/composio/tsconfig.json (1)

17-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Exclude test files from declaration emit.

include matches **/*.test.ts, so the composite build emits declaration files for tests into dist. Add the test pattern to exclude to keep the published declaration surface limited to the plugin API.

♻️ Proposed change
-  "exclude": ["dist", "node_modules"],
+  "exclude": ["dist", "node_modules", "**/*.test.ts"],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/tsconfig.json` around lines 17 - 19, Update the tsconfig
include/exclude configuration by adding a pattern that excludes test files such
as *.test.ts from declaration emit, while preserving the existing dist and
node_modules exclusions and the plugin source inclusion.
packages/composio/endpoints/actions.ts (2)

39-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Throw ComposioAPIError for input validation failures.

These guards throw a plain Error. The package already defines ComposioAPIError in packages/composio/client.ts, and transport failures use it. Callers that branch on the error type will not recognize these validation failures. Use ComposioAPIError with a 400 status for consistency.

♻️ Proposed change
-import { makeComposioRequest } from '../client';
+import { ComposioAPIError, makeComposioRequest } from '../client';
 	const toolSlug = input.tool_slug ?? input.actionId;
 	if (!toolSlug) {
-		throw new Error('tool_slug is required');
+		throw new ComposioAPIError('tool_slug is required', 400);
 	}

Also applies to: 64-67

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/endpoints/actions.ts` around lines 39 - 42, Update the
validation guards in the actions endpoint, including the corresponding guard
around lines 64–67, to throw the existing ComposioAPIError from client.ts
instead of plain Error. Set the error status to 400 while preserving the current
validation messages and control flow.

6-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated omitUndefined helper into one module. The same 7-line helper is copied verbatim into three endpoint modules. Define it once inside the package, for example in packages/composio/endpoints/utils.ts, and import it. The helper stays inside packages/composio/, so the package remains self-contained.

  • packages/composio/endpoints/actions.ts#L6-L12: delete the local definition and import omitUndefined from the new packages/composio/endpoints/utils.ts.
  • packages/composio/endpoints/connections.ts#L6-L12: delete the local definition and import omitUndefined from the same module.
  • packages/composio/endpoints/apps.ts#L6-L12: delete the local definition and import omitUndefined from the same module.
♻️ Proposed extraction

New file packages/composio/endpoints/utils.ts:

export type QueryValue = string | number | boolean | undefined;

export function omitUndefined(
	query: Record<string, QueryValue>,
): Record<string, QueryValue> {
	return Object.fromEntries(
		Object.entries(query).filter(([, v]) => v !== undefined),
	);
}

Then in each endpoint module:

-function omitUndefined(
-	query: Record<string, string | number | boolean | undefined>,
-): Record<string, string | number | boolean | undefined> {
-	return Object.fromEntries(
-		Object.entries(query).filter(([, v]) => v !== undefined),
-	);
-}
+import { omitUndefined } from './utils';

As per coding guidelines, "Each plugin should remain self-contained within its own packages/<plugin>/ package" — the new helper module stays inside packages/composio/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/endpoints/actions.ts` around lines 6 - 12, Extract the
duplicated omitUndefined helper into packages/composio/endpoints/utils.ts,
preserving its current filtering behavior and shared QueryValue type. In
packages/composio/endpoints/actions.ts lines 6-12,
packages/composio/endpoints/connections.ts lines 6-12, and
packages/composio/endpoints/apps.ts lines 6-12, remove the local definitions and
import omitUndefined from the new module.

Source: Coding guidelines

packages/composio/client.ts (1)

50-60: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Preserve the upstream error body and rate-limit metadata.

ApiError carries body, retryAfter, rateLimitReset, rateLimitRemaining, and rateLimitLimit (see packages/corsair/async-core/ApiError.ts lines 4-43). ComposioAPIError keeps only message and status. After the shared executor exhausts its retries (packages/corsair/async-core/request.ts lines 332-438), callers lose both the Composio error code and the backoff hint, so they cannot schedule a retry or report the specific failure.

♻️ Proposed change to retain error detail
 export class ComposioAPIError extends Error {
 	constructor(
 		message: string,
 		public readonly status?: number,
+		public readonly body?: unknown,
+		public readonly retryAfter?: number,
 	) {
 		super(message);
 		this.name = 'ComposioAPIError';
 	}
 }
 		if (error instanceof ApiError) {
-			throw new ComposioAPIError(error.message, error.status);
+			throw new ComposioAPIError(
+				error.message,
+				error.status,
+				error.body,
+				error.retryAfter,
+			);
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/client.ts` around lines 50 - 60, Update the ApiError
handling in the request try/catch to preserve the upstream error body and
rate-limit metadata, including retryAfter, rateLimitReset, rateLimitRemaining,
rateLimitLimit, and the Composio error code. Extend or use the ComposioAPIError
construction path so callers retain these fields after request retries are
exhausted, while preserving existing handling for generic Error and unknown
failures.
packages/composio/endpoints/types.ts (2)

23-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer z.looseObject() over .passthrough() in Zod 4.

Zod 4 retains .passthrough() as a legacy API. Replace these loose object schemas with z.looseObject(). The package declares zod as ^4.1.13, and the lockfile resolves version 4.4.3.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/endpoints/types.ts` around lines 23 - 55, Replace the
legacy .passthrough() calls in ToolSchema and PaginatedToolsSchema with Zod 4’s
z.looseObject() construction, preserving each schema’s existing fields and
optionality while continuing to allow unknown properties.

179-186: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Open Redirect (CWE-601): URL Redirection to Untrusted Site ('Open Redirect')

Reachability: Internal · Exploitability: Moderate

Reachability path
● Entry
  packages/composio/endpoints/apps.ts:20
  omitUndefined
│
▼
● Hop
  packages/composio/endpoints/actions.ts
│
▼
● Sink
  packages/composio/endpoints/types.ts

Restrict redirect URLs to HTTP(S).

z.url() also accepts schemes such as mailto:. Use z.url({ protocol: /^https?$/ }).optional() for both callback_url and redirectUri before forwarding them as redirect targets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/composio/endpoints/types.ts` around lines 179 - 186, Update
ConnectionCreateInputSchema so both callback_url and the deprecated redirectUri
validate with z.url({ protocol: /^https?$/ }).optional(), restricting redirect
targets to HTTP and HTTPS while preserving their optional status.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/composio/endpoints/connections.ts`:
- Around line 34-39: Update the event payloads in connectionsList and
connectionCreate to exclude end-user identifiers before calling
logEventFromContext. Replace the connectionsList `{ ...input }` payload with
only non-sensitive fields, and remove user_id from the connectionCreate payload
while preserving the existing event names and statuses.

---

Nitpick comments:
In `@packages/composio/client.ts`:
- Around line 50-60: Update the ApiError handling in the request try/catch to
preserve the upstream error body and rate-limit metadata, including retryAfter,
rateLimitReset, rateLimitRemaining, rateLimitLimit, and the Composio error code.
Extend or use the ComposioAPIError construction path so callers retain these
fields after request retries are exhausted, while preserving existing handling
for generic Error and unknown failures.

In `@packages/composio/endpoints/actions.ts`:
- Around line 39-42: Update the validation guards in the actions endpoint,
including the corresponding guard around lines 64–67, to throw the existing
ComposioAPIError from client.ts instead of plain Error. Set the error status to
400 while preserving the current validation messages and control flow.
- Around line 6-12: Extract the duplicated omitUndefined helper into
packages/composio/endpoints/utils.ts, preserving its current filtering behavior
and shared QueryValue type. In packages/composio/endpoints/actions.ts lines
6-12, packages/composio/endpoints/connections.ts lines 6-12, and
packages/composio/endpoints/apps.ts lines 6-12, remove the local definitions and
import omitUndefined from the new module.

In `@packages/composio/endpoints/types.ts`:
- Around line 23-55: Replace the legacy .passthrough() calls in ToolSchema and
PaginatedToolsSchema with Zod 4’s z.looseObject() construction, preserving each
schema’s existing fields and optionality while continuing to allow unknown
properties.
- Around line 179-186: Update ConnectionCreateInputSchema so both callback_url
and the deprecated redirectUri validate with z.url({ protocol: /^https?$/
}).optional(), restricting redirect targets to HTTP and HTTPS while preserving
their optional status.

In `@packages/composio/tsconfig.json`:
- Around line 17-19: Update the tsconfig include/exclude configuration by adding
a pattern that excludes test files such as *.test.ts from declaration emit,
while preserving the existing dist and node_modules exclusions and the plugin
source inclusion.

In `@packages/composio/webhooks.test.ts`:
- Around line 14-39: Update the “accepts a valid Standard Webhooks signature”
test and its secret fixture to use a valid whsec_<base64> key, and generate the
signature with the decoded raw key so verifyComposioWebhookSignature exercises
the Standard Webhooks decoding branch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fb4b5fac-89c4-4410-9a08-7190e4dc9e20

📥 Commits

Reviewing files that changed from the base of the PR and between 839b807 and 5e74398.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • packages/composio/api.test.ts
  • packages/composio/client.ts
  • packages/composio/endpoints/actions.ts
  • packages/composio/endpoints/apps.ts
  • packages/composio/endpoints/connections.ts
  • packages/composio/endpoints/index.ts
  • packages/composio/endpoints/tools.ts
  • packages/composio/endpoints/types.ts
  • packages/composio/error-handlers.ts
  • packages/composio/index.ts
  • packages/composio/jest.config.cjs
  • packages/composio/package.json
  • packages/composio/schema/database.ts
  • packages/composio/schema/index.ts
  • packages/composio/tsconfig.json
  • packages/composio/tsup.config.ts
  • packages/composio/webhooks.test.ts
  • packages/composio/webhooks/index.ts
  • packages/composio/webhooks/triggers.ts
  • packages/composio/webhooks/types.ts
  • packages/corsair/core/constants.ts

Comment thread packages/composio/endpoints/connections.ts

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/composio/error-handlers.ts`:
- Around line 8-9: Update the rate-limit detection logic around the error
classification function to avoid substring checks on error.message. Prefer an
exact structured status or code field, or parse and match a complete rate-limit
token, so values such as 4290 and unrelated text containing rate_limited are not
classified as rate limits before selecting RATE_LIMIT_ERROR.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3be874d3-2fc0-4156-a999-5368f8b44316

📥 Commits

Reviewing files that changed from the base of the PR and between 839b807 and 5e74398.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • packages/composio/api.test.ts
  • packages/composio/client.ts
  • packages/composio/endpoints/actions.ts
  • packages/composio/endpoints/apps.ts
  • packages/composio/endpoints/connections.ts
  • packages/composio/endpoints/index.ts
  • packages/composio/endpoints/tools.ts
  • packages/composio/endpoints/types.ts
  • packages/composio/error-handlers.ts
  • packages/composio/index.ts
  • packages/composio/jest.config.cjs
  • packages/composio/package.json
  • packages/composio/schema/database.ts
  • packages/composio/schema/index.ts
  • packages/composio/tsconfig.json
  • packages/composio/tsup.config.ts
  • packages/composio/webhooks.test.ts
  • packages/composio/webhooks/index.ts
  • packages/composio/webhooks/triggers.ts
  • packages/composio/webhooks/types.ts
  • packages/corsair/core/constants.ts
🚧 Files skipped from review as they are similar to previous changes (20)
  • packages/composio/webhooks/index.ts
  • packages/composio/tsconfig.json
  • packages/composio/webhooks.test.ts
  • packages/composio/endpoints/apps.ts
  • packages/composio/endpoints/index.ts
  • packages/composio/tsup.config.ts
  • packages/composio/webhooks/triggers.ts
  • packages/composio/endpoints/tools.ts
  • packages/composio/schema/index.ts
  • packages/corsair/core/constants.ts
  • packages/composio/jest.config.cjs
  • packages/composio/package.json
  • packages/composio/api.test.ts
  • packages/composio/endpoints/actions.ts
  • packages/composio/endpoints/connections.ts
  • packages/composio/client.ts
  • packages/composio/webhooks/types.ts
  • packages/composio/index.ts
  • packages/composio/endpoints/types.ts
  • packages/composio/schema/database.ts

Comment thread packages/composio/error-handlers.ts Outdated
@Dhirenderchoudhary

Dhirenderchoudhary commented Aug 4, 2026 •

Copy link
Copy Markdown
Collaborator

@greptile review

@github-actions

github-actions Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Plugin PR scorecard — packages/composio

Check Status Notes
R1 — Scope: plugin files only ✅
R2 — Tests with assertions ✅
R3 — Description complete ✅
R3 — Linked issue / claim ✅
R4 — Demo video / recording ✅

Rules: PLUGIN_PR_RULES.md · re-runs on every push

@github-actions github-actions Bot added docs Docs / Mintlify / markdown changes plugin Changes inside a plugin package labels Sep 19, 2026
@greptile-apps

greptile-apps Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Comments Outside Diff

These findings could not be posted inline.

  • P1 Security Replay cache is process-scoped protection is absent across workers packages/composio/webhooks/types.ts:1951 ▶

    processedWebhookDeliveries is a module-level Map, so each OS process (or serverless worker) starts with an empty cache. In any multi-process or serverless deployment, a captured webhook can be POSTed to a different worker within the ±5-minute tolerance window; that worker's cache is cold, the HMAC is still valid, and isWebhookReplayed records and returns false - accepting the replay. This lets an attacker re-trigger every composio.trigger.message handler repeatedly for up to 5 minutes from a single captured delivery.

    The previous thread identified the missing deduplication; this implementation fixes the single-process case but not the distributed case. A shared store (Redis, Postgres, or the framework's Hub) is needed for distributed replay protection. If a distributed store isn't available in the short term, at minimum add a code comment warning callers that this protection is ineffective in multi-worker environments.

  • P1 Rate-limit instanceof ApiError check is dead code packages/composio/error-handlers.ts:881 ▶

    makeComposioRequest always catches ApiError and re-throws it as ComposioAPIError, so the error that reaches this handler is never an ApiError instance. Two concrete failures follow: (1) for a 429 whose message doesn't contain "rate limit" or "too many requests" (e.g. a generic 429 body), the matcher returns false, the error falls to DEFAULT, and { maxRetries: 0 } is returned - no retries attempted; (2) error.retryAfter in the handler branch is also dead code because ComposioAPIError never carries that field. The RATE_LIMIT_ERROR.match must check error instanceof ComposioAPIError && error.status === 429 instead, and ComposioAPIError needs a retryAfter field (populated from ApiError.retryAfter) for the headersRetryAfterMs path to work.

  • P1 JSON.parse body will throw a SyntaxError if the body string is malformed, crashing createComposioMatch which runs inside pluginWebhookMatcher and all three webhook match functions before any handler is reached. Wrapping in a try/catch lets the matcher fail gracefully. packages/composio/webhooks/types.ts:1119 ▶

    JSON.parse(body) will throw a SyntaxError if the body string is malformed, crashing createComposioMatch (which runs inside pluginWebhookMatcher and all three webhook match functions) before any handler is reached. Wrapping in a try/catch lets the matcher fail gracefully.

    function parseBody(body: unknown): Record<string, unknown> {
    	if (typeof body === 'string') {
    		try {
    			return JSON.parse(body) as Record<string, unknown>;
    		} catch {
    			return {};
    		}
    	}
    	// body may be pre-parsed by the framework; fall back to empty object for null/undefined
    	return (body ?? {}) as Record<string, unknown>;
    }
    
  • P1 Security Webhook signature never cryptographically verified packages/composio/webhooks/types.ts:1138 ▶

    verifyComposioWebhookSignature accepts a secret parameter but never uses it - it returns { valid: true } for any request that merely includes an x-composio-signature header, regardless of the header's value. An attacker who knows the plugin is Composio-backed can forge any webhook event (trigger.fired, connection.status, action.completed) by adding the header with an arbitrary value and bypass all three handlers' authentication checks.

  • P2 unknown parameter used without an explanatory comment packages/composio/webhooks/types.ts:1119 ▶

    parseBody accepts body: unknown - the team's rule requires every use of unknown to be accompanied by a comment explaining why stricter typing isn't feasible. Adding a brief comment (e.g. explaining that the framework may deliver the body as either a pre-parsed object or a raw string) satisfies the rule and aids future readers.

    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!

  • P2 Type assertions and unknown missing required justification comments packages/composio/endpoints/actions.ts:83 ▶

    Per the team's rules, type assertions in the plugins folder and any use of any/unknown must be accompanied by an explanatory comment. input as Record<string, string | number | boolean | undefined> appears without justification here, and the same pattern repeats in tools.ts, apps.ts, and connections.ts. Similarly, (body ?? {}) as Record<string, unknown> and JSON.parse(body) as Record<string, unknown> in webhooks/types.ts lack comments explaining why the casts are necessary over directly using the typed values.

    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!

@github-actions github-actions Bot added the gate:failed Plugin PR gate checks failing label Sep 19, 2026
Revert packages/agiled/readme.md to match main so R1 gate passes.
@github-actions github-actions Bot removed the gate:failed Plugin PR gate checks failing label Sep 19, 2026
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator

@greptileai review

@greptile-apps

greptile-apps Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator

@greptileai review

Comment thread packages/composio/endpoints/meta-tools.ts
Comment thread docs/plugins/composio/database.mdx
@Dhirenderchoudhary

Copy link
Copy Markdown
Collaborator

@greptileai review

@github-actions github-actions Bot removed the needs-maintainer Automated rounds exhausted - human review needed label Oct 12, 2026
@Dhirenderchoudhary

Dhirenderchoudhary commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Ran the tests locally on 4bad1f8ca.

Unit tests: 47/47 passing.

PR #344 test run

@Dhirenderchoudhary Dhirenderchoudhary left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM
THanks

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:round-1 Review bot posted consolidated findings bot:round-2 Review bot pushed an automated fix core Changes in packages/corsair docs Docs / Mintlify / markdown changes plugin Changes inside a plugin package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants