feat(sailpoint): add SailPoint (IGA) integration - #6092
Conversation
Add a SailPoint Identity Security Cloud integration with 27 tools spanning
identity-governance reads (search + count + aggregate, identities, accounts,
entitlements, roles, access profiles, sources, account activities, campaigns,
certifications, and entitlement expansion), the access-request write path
(request, cancel, status), and CSV account/entitlement aggregation.
Auth uses a service-identity Personal Access Token via the OAuth2
client-credentials grant against the per-tenant host
(https://{tenant}.api.identitynow.com), resolved server-side in two internal
routes (/api/tools/sailpoint/query and /load) with in-process token caching
and Retry-After 429 backoff. The block enumerates the exact PAT scopes and the
service-identity caveat. Access-request constraints (revoke one identity + one
item, grant 25-entitlement / 10-identity caps, comment-on-revoke) are enforced
pre-submission, and empty userAuth reads surface a permission-gap diagnostic.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview 27 tools proxy through two server routes ( A SailPoint workflow block, tool registry entries, Reviewed by Cursor Bugbot for commit 531ae54. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryPrior SailPoint review findings are addressed on HEAD; this follow-up found no incomplete or unsafe fixes and no new thread-eligible issues.
Confidence Score: 5/5Safe to merge; previously reported SailPoint SSRF, search-aggregate, and total-count issues are fixed and no remaining blocking failures were found on this follow-up. No blocking failure remains. Host resolution only targets allowed SailPoint hosts, aggregate requests require aggregations DSL, and the block can request X-Total-Count via count mapping.
|
| Filename | Overview |
|---|---|
| apps/sim/app/api/tools/sailpoint/client.ts | SSRF allowlist and bare-tenant validation are in place; regression coverage rejects non-SailPoint hosts and accepts full identitynow hosts. |
| apps/sim/lib/api/contracts/tools/sailpoint.ts | searchAggregateSchema requires a non-empty aggregationsDsl object so missing aggregations fail validation before the API call. |
| apps/sim/app/api/tools/sailpoint/query/route.ts | Aggregate path forwards aggregationsDsl with aggregationType DSL and preserves AggregationResult as item; count query param is still honored when provided. |
| apps/sim/blocks/blocks/sailpoint.ts | Include Total Count sub-block and applyPagination map count; Search Aggregate requires aggregationsDsl with JSON wand support. |
Reviews (5): Last reviewed commit: "fix(sailpoint): adaptive token TTL buffe..." | Re-trigger Greptile
…te, retry/count fixes - Restrict tenant host resolution to *.api.identitynow.com / *.api.identitynowgov.com (or a bare tenant subdomain) so the client-credentials request can never post the PAT secret to an attacker-controlled or internal host. Throws on any other host. - Make search_aggregate functional: add an aggregationsDsl input (tool/contract/route/block) and preserve the AggregationResult object instead of dropping it through the list handler. - Retry the token exchange on 429 with Retry-After backoff, matching sailpointFetch. - Rebuild the multipart FormData per attempt so 401/429 retries never reuse a consumed body. - Expose an "Include Total Count" toggle so totalCount is reachable from the block UI. - Regenerate docs. Add route tests for the SSRF guard and aggregate object preservation.
|
@cursor review |
…r, fix review-item filters - Require aggregationsDsl on search_aggregate (contract + tool) and send aggregationType: DSL so /search/aggregate always receives a valid aggregations definition. - Coerce searchAfter cursor elements to strings instead of dropping non-string values, and expose a searchAfter input on the block so deep pagination past 10k is reachable from the UI. - Correct the certification review-item filter fields (entitlements / access profiles / roles) to comma-separated ID filters instead of true/false placeholders.
|
@cursor review |
# Conflicts: # scripts/check-api-validation-contracts.ts
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 52d5372. Configure here.
Include a hash of client_secret in the token cache key so a caller with a matching tenant/clientId but the wrong secret cannot reuse another principal's cached bearer token - a mismatched secret now misses the cache and fails the token exchange. Regression test added.
|
@cursor review |
…missing header - Cap the token cache expiry buffer at the smaller of 60s and 10% of the lifetime so a short-lived token still caches instead of expiring immediately. - Return an error for search_count when SailPoint provides no X-Total-Count (and no numeric body) instead of reporting a misleading total of 0. Tests added for both count paths.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 531ae54. Configure here.
SailPoint (IGA) integration
Adds a SailPoint Identity Security Cloud integration for identity-governance workflows.
What's included
search/search_count/search_aggregate, list+get identities, accounts (+ account entitlements), entitlements, roles (+ role entitlements), access profiles (+ entitlements), sources, account activities, campaigns, certifications (+ review items).request_access,cancel_access_request,get_access_request_status.load_accounts/load_entitlements(CSV account/entitlement aggregation via multipart).blocks/blocks/sailpoint.ts(IntegrationType.Security,AuthMode.ApiKey) whoselongDescriptionenumerates the exact PAT scopes and the service-identity caveat./api/tools/sailpoint/query,/api/tools/sailpoint/load) that do the token exchange, per-tenant host + version resolution, and file forwarding server-side.Auth model
Client-credentials / Personal Access Token against the per-tenant host
https://{tenant}.api.identitynow.com, mirroring the in-repo CrowdStrike pattern. No OAuth redirect, nooauth.ts/auth.ts/env.tschanges.tenant:clientId:apiVersion, refreshed on 401.Retry-After(SailPoint's limit is 100 req / client_id / API version / 10s).v2025default,v2024,v3) — never a silent fallback.Correctness details (verified against the v2025 OpenAPI spec)
requestType=GRANT_ACCESS/REVOKE_ACCESS/MODIFY_ACCESS; itemtype=ACCESS_PROFILE/ROLE/ENTITLEMENT.superRefine: revoke = one identity + one item + comment; grant-with-entitlements caps at 25 items / 10 identities.limitcaps (search 10000, roles/role-entitlements 50, otherwise 250).userAuthreads (identities/entitlements/roles/search) returncomplete: false+ a permission-gapwarnings[]diagnostic — the service-identity/API-Management-client gotcha surfaced at runtime.Verification
bun run check:api-validation:strict✓,check:bare-icons✓, biome ✓, typecheck clean for the new files.superRefinerejection, 202 write, multipart aggregation, error propagation).scripts/generate-docs.ts.🤖 Generated with Claude Code