@codex review
Final piece of MCPG-193. Depends on #516 AND #517 landing first — this branch is based on #517 so it typechecks against
main. Once #517 merges, the diff againstmainwill naturally shrink to just this script.
After #517 ships, newly-provisioned tenants automatically get their lambdaConfiguration.scimGroupRequestConverterId pointing at the Composio-managed lambda. Existing tenants still point at FusionAuth's default request converter, which does not stamp group.data.source = 'scim' — so their Okta-pushed group webhooks get silently dropped at the source-scope gate in apps/admin/server/scim/source-scope.ts.
This script repoints each existing SCIM-enabled tenant.
apps/admin/scripts-tmp/backfill-scim-group-request-lambda.ts. Mirrors the dry-run / per-org / sweep flag pattern from MCPG-209's PR #512 backfill.ensureComposioScimGroupLambda() once at startup to confirm the managed lambda exists in FA before any tenant is touched. The lambda has a deterministic UUID and idempotent upsert, so re-runs are safe.lambdaConfiguration.scimGroupRequestConverterId (FA tenant PATCH deep-merges, so every other setting is preserved).--dry-run, --org-slug <slug>, --all. Defends against fat-fingered sweeps.{ "summary": true, ... } line. Exits non-zero if any per-tenant PATCH failed.main (the #517 commit will be absorbed). Diff naturally shrinks to just this script file.bun run apps/admin/scripts-tmp/backfill-scim-group-request-lambda.ts --dry-run
bun run apps/admin/scripts-tmp/backfill-scim-group-request-lambda.ts --org-slug planktoncomposio
curl -sS "$FUSIONAUTH_URL/api/tenant/$TENANT_ID" -H "Authorization: $FUSIONAUTH_API_KEY" | jq '.tenant.lambdaConfiguration.scimGroupRequestConverterId'.bun run apps/admin/scripts-tmp/backfill-scim-group-request-lambda.ts --all.bunx turbo check-types --filter=@repo/admin — greenbunx turbo lint --filter=@repo/admin — green--all sweep across remaining SCIM-enabled orgsa00a6486-958f-4d7e-bf1b-36c34842068c). It becomes orphaned but harmless once the tenant gets repointed to the managed id. Can be swept manually in a later cleanup pass.@codex review
@codex review
@codex review
@codex review
Codex Review: Didn't find any major issues. Breezy!
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Pushing a group from Okta lands the group in FusionAuth correctly, but the resulting group.create / group.update webhook delivered to the Composio admin throws inside the team auto-create pipeline and returns HTTP 500 group_update_processing_failed. The SCIM-managed team never gets created, and Okta-originated groups never appear in Composio.
Tested live against planktoncomposio (FA tenant 1ea93b19-2f09-4b28-a71e-470f3e25a2e9, prod admin at https://egateway.composio.dev) on 2026-05-15.
| Layer | Status |
|---|---|
| Okta → FusionAuth SCIM POST | ✅ groups land (e.g. plank444 id=43ca9bc3-a75e-41ee-8725-2b6d6f513cbb) |
| FA SCIM Group Request Converter Lambda | ✅ writes data.source = "scim" onto the group (verified — see "Test setup" below) |
| FA webhook config | ✅ scoped to tenant 1ea93b19-…, URL https://egateway.composio.dev/api/fusionauth/webhooks/group-updated, all group.* events enabled, shared-secret auth |
| Composio webhook auth | ✅ secret matches (probe returns 500, not 401) |
| Composio webhook schema validation | ✅ passes (probe returns 500, not 400 invalid_payload) |
| Composio org-context resolution | ✅ passes — Organization for planktoncomposio has fusionauthTenantId = 1ea93b19-… and scimEnabled = true (probe would otherwise short-circuit to 200 silently) |
| Composio team auto-create pipeline | ❌ throws → caught by webhook route, returns 500 |
The 500 originates in the catch block at apps/admin/app/api/fusionauth/webhooks/group-updated/route.ts:207-218, which calls — the actual stack trace lives in Sentry.
Sentry.captureException(error, ...)Call path that throws:
ensureScimManagedTeamForWebhookGroup(...) is invoked because shouldCreateSourceScopedGroup = true (the source marker data.source: "scim" is present in the payload)ensureScimManagedTeamForWebhookGroup runs upsertNormalizedScimGroup then createScimManagedTeamcreateScimManagedTeam runs withRepairRollback({ work: ... }) which calls updateTeamScimBinding then applyScimProjectionPlanForRepairapplyScimProjectionPlan(orgId) — heaviest operation, hits Postgres, FA APIs, and the projection engineWhen work throws, withRepairRollback deletes the just-created Team row, so nothing remains in the DB to debug from the outside.
applyScimProjectionPlan requires settings.fusionauth.applications.admin.id and settings.fusionauth.applications.mcp.id on the Organization (project.ts:1428-1430). If those aren't configured on planktoncomposio's Org settings, downstream syncProjectedTeamMemberships / role-assignment code will throw.syncProjectedTeamMemberships calls FA group/membership APIs that may fail when the team has zero members or when the FA admin/mcp application/role config is incomplete.createScimManagedTeamWithAutoSlug — less likely since both my real-id probe and synthetic-id probe failed with identical error.We can't pick between these without the actual stack trace.
Two probes against the prod admin on 2026-05-15, both returned HTTP 500 {"error":"group_update_processing_failed"}:
data.source: "scim", externalId: "okta-diag-probe":
x-flow-id: ae065023-ccab-4874-9767-07f8f3bfda25x-request-id: req_5cfae86c-403a-4c49-8a43-5f43e1ae580143ca9bc3-a75e-41ee-8725-2b6d6f513cbb), data.source: "scim":
x-flow-id: 76bf0ab1-3355-418b-bd7b-5bbedd8a65f0x-request-id: req_b8a7c688-dc04-44da-92ce-5a667c2776fcThese should map to captured Sentry exceptions for component: "fusionauth-group-updated-webhook" with the full stack.
A. New SCIM Group Request Converter Lambda created in FusionAuth
a00a6486-958f-4d7e-bf1b-36c34842068cComposio planktoncomposio SCIM Group Request Converter (externalId)SCIMServerGroupRequestConverter// planktoncomposio-only — copies SCIM externalId into FA group.data so the Composio webhook source-scope check passes
function convert(group, members, options, scimGroup) {
group.data = group.data || {};
group.data.source = 'scim';
if (scimGroup.externalId) {
group.data.externalId = scimGroup.externalId;
}
group.name = scimGroup.displayName;
if (scimGroup.members) {
for (var i = 0; i < scimGroup.members.length; i++) {
members.push({
userId: scimGroup.members[i].value,
data: { $ref: scimGroup.members[i]['$ref'] }
});
}
}
}
B. Tenant patched to reference the new lambda
1ea93b19-2f09-4b28-a71e-470f3e25a2e9 (planktoncomposio)lambdaConfiguration.scimGroupRequestConverterId changed from fda7bc79-74a4-48c8-8681-039aceb822dd (shared FA default) to a00a6486-… (new lambda above)Revert command if we want to back out:
PATCH /api/tenant/1ea93b19-2f09-4b28-a71e-470f3e25a2e9
{ "tenant": { "lambdaConfiguration": { "scimGroupRequestConverterId": "fda7bc79-74a4-48c8-8681-039aceb822dd" } } }
Independent of the auto-create bug, the default FA SCIM Group Request Converter never copies SCIM externalId into group.data, so even before reaching the auto-create code path, the source-scope marker check at apps/admin/server/scim/source-scope.ts:31-48 would reject every Okta-originated group webhook. The new lambda fixes that gate for planktoncomposio. The remaining 500 is a separate, downstream bug.
When fixing this properly, the lambda change should either be:
fda7bc79-… body, or set up a "Composio Standard" lambda used by all SCIM tenants), orapps/admin/server/routers/onboarding/configure-scim.ts or wherever the FA tenant SCIM setup runs).1ea93b19-… from test pushes: plank444, plank222, Plank123, composio123, composio123-admins, neto123, neto123-admins, Teste, Team test, Testing, and okta-…-admins siblings.ScimGroup row from each probe (the rollback only deletes the Team row, not the upserted ScimGroup — see webhook-ingestion.ts:449-457 and withRepairRollback at repair.ts:611-628). Worth confirming and cleaning.error.message (and code) in the response body, deploy to prod, re-probe.applyScimProjectionPlan / syncProjectedTeamMemberships (or wherever the stack points).group.create auto-create path against the test DB so this can't regress silently.ScimGroup rows in prod DB.The latest updates on your projects. Learn more about Vercel for GitHub.
| Project | Deployment | Actions | Updated (UTC) |
|---|---|---|---|
| composio-enterprise-admin | Preview | May 21, 2026 4:27pm | |
| composio-enterprise-internal | May 21, 2026 4:27pm |