feat(connectors): add 9 knowledge base connectors - #6699
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryHigh Risk Overview SFTP gains optional SHA-256 host key pinning, idle socket timeouts, and stricter fingerprint validation in shared UI: API-key connectors can declare New implementations follow existing patterns: deferred listing stubs, Reviewed by Cursor Bugbot for commit 26103b2. Configure here. |
Greptile SummaryThe PR adds nine knowledge-base connectors and strengthens connector synchronization, reconciliation, and external-service validation. It also restricts Dataverse tool URLs to Microsoft-owned domains, although the accepted review finding identifies incomplete redirect-boundary protection.
Confidence Score: 3/5The PR is not yet safe to merge because Dataverse OAuth bearer tokens can still cross origins when an allowed endpoint redirects. The initial Dataverse URL is now restricted to Microsoft-owned domains, but existing tool requests leave stripAuthOnRedirect unset while the shared fetch implementation follows redirects and preserves Authorization by default. Files Needing Attention: apps/sim/tools/microsoft_dataverse/utils.ts and the Dataverse tool request configurations
|
| Filename | Overview |
|---|---|
| apps/sim/tools/microsoft_dataverse/utils.ts | Adds robust parsing and a Microsoft-domain allowlist for initial Dataverse destinations, but does not complete the required cross-origin redirect protection. |
| apps/sim/lib/core/security/input-validation.server.ts | Existing shared fetch behavior follows redirects and conditionally strips Authorization, exposing the consequence of Dataverse callers leaving the option unset. |
| apps/sim/connectors/registry.server.ts | Registers the new connector runtimes with the server-side connector registry. |
| apps/sim/lib/knowledge/connectors/sync-engine.ts | Adds reconciliation safeguards for empty or collapsed connector listings. |
| apps/sim/app/api/tools/sftp/utils.ts | Adds optional SHA-256 host-key pinning and explicit idle-timeout handling for SFTP connections. |
Sequence Diagram
sequenceDiagram
participant Tool as Dataverse Tool
participant Guard as getDataverseBaseUrl
participant Fetch as secureFetchWithPinnedIP
participant DV as Allowed Dataverse Origin
participant Other as Redirect Origin
Tool->>Guard: Validate environmentUrl
Guard-->>Tool: Microsoft-owned origin
Tool->>Fetch: GET with OAuth bearer token
Fetch->>DV: Initial pinned request
DV-->>Fetch: 3xx Location to another origin
Note over Fetch: stripAuthOnRedirect is unset
Fetch->>Other: Follow redirect with bearer token
Reviews (3): Last reviewed commit: "feat(connectors): add 9 knowledge base c..." | Re-trigger Greptile
17c5922 to
96519cf
Compare
|
@cursor review |
|
|
||
| const data = (await response.json()) as WorksheetListResponse | ||
| return data.value ?? [] | ||
| } |
There was a problem hiding this comment.
Excel worksheets ignore Graph pagination
Medium Severity
fetchWorksheets reads only the first Graph page and never follows @odata.nextLink. Workbooks with more sheets than Graph returns in one response silently omit the rest, and listingCapped is not set, so those worksheets are never indexed.
Reviewed by Cursor Bugbot for commit 96519cf. Configure here.
| owners: file.owners?.map((o) => o.displayName || o.emailAddress).filter(Boolean), | ||
| }, | ||
| } | ||
| } |
There was a problem hiding this comment.
Slides hash ignores speaker-notes setting
Medium Severity
The listing contentHash is only id plus modifiedTime and does not include includeSpeakerNotes. Toggling speaker notes leaves hashes unchanged, so already-indexed decks are not re-hydrated and keep the old extracted text.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 96519cf. Configure here.
Box, Zoho Desk, PagerDuty, Trello, Microsoft Excel, Google Slides, Google Vault, Mintlify, and SFTP. Selected by intersecting the published connector catalogs of Glean, Onyx, Dust, Vectara, Writer, Guru, Elastic, Microsoft 365 Copilot, Notion AI, Unstructured, and Airbyte against services that already ship a Sim block, so OAuth providers, credentials, and icons are reused. Box was the largest gap, appearing in 7-8 of ~10 catalogs. Every connector was validated against live provider documentation twice, the second pass treating the first pass's conclusions as unproven. Notable correctness work that came out of that: Listing truncation. The sync engine hard-deletes documents past a cap that is not flagged with `listingCapped`, and five connectors had a path there — an empty Mintlify discovery, Zoho Desk's exact-multiple default caps, Trello's archived lists and 1000-card ceiling, a Google Vault cursor bailout, and a PagerDuty stalled page. The engine also gained a backstop: an empty or collapsed listing blocks deletion reconciliation until the same observation repeats on a consecutive sync, reconstructed from existing sync-log counters so no migration is needed. API alignment. `desk.zoho.ca` does not resolve (Canada is `desk.zohocloud.ca`, and Singapore and UAE were missing); `modifiedTime` is absent from Zoho's ticket list projection, so every ticket re-embedded on every sync; Trello's `dateLastActivity` is documented to miss some edits; PagerDuty's 10,000-record ceiling bounds `offset + limit`, not offset; Excel indexed dates as raw serial numbers while Google Sheets renders them; Google Vault truncated at roughly 249 matters. Security. SFTP followed symlinks in `getDocument` and composed unchecked server-supplied filenames into paths; it now also supports optional host-key fingerprint verification, which runs during key exchange before any password is sent. Trello interpolated user-supplied board ids into URL paths. Google Vault is narrowed to `ediscovery.readonly`. `getDataverseBaseUrl` accepted any host while attaching a bearer token, and is pinned to Microsoft's Dataverse domains — pre-existing shipped code, fixed here. Also adds `ConnectorAuthConfig.optional` so a public source can be configured without inventing an API key, and teaches the scope check that a granted read-write scope satisfies a required `.readonly` sibling. Microsoft Dataverse was built and then removed: its OAuth cannot complete consent. Dataverse requires a per-environment resource URI, the provider declares a static `https://dynamics.microsoft.com/user_impersonation` that is not an Entra Application ID URI, and the environment URL is only collected after the credential exists. That predates this change and also affects the 12 shipped Dataverse tools.
96519cf to
26103b2
Compare
|
@cursor review |
| ) | ||
| } | ||
|
|
||
| return parsed.origin |
There was a problem hiding this comment.
Bearer token survives redirects
If an allowed Dataverse endpoint redirects to another origin, the shared fetch path follows the redirect while preserving Authorization because the Dataverse tools leave stripAuthOnRedirect unset, causing the redirect target to receive the user's reusable OAuth bearer token.
How this was verified: The shared redirect handler removes Authorization only when stripAuthOnRedirect is true, and no Dataverse request enables that option.
Knowledge Base Used: Blocks Module
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 26103b2. Configure here.
|
|
||
| const filtered = pathPrefix | ||
| ? discovered.filter((page) => page.path.startsWith(pathPrefix)) | ||
| : discovered |
There was a problem hiding this comment.
Mintlify prefix matches sibling paths
Medium Severity
pathPrefix is applied with raw startsWith, unlike withinBasePath, which requires an exact path or a / boundary. A prefix such as /guides also matches /guides-old and /guides2, so those pages are indexed and later prefix edits can reconcile the wrong set.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 26103b2. Configure here.


What
Adds 9 knowledge base connectors, closing the highest-frequency gaps in our catalog. Every service already shipped a block, so OAuth providers, credentials, and icons were reused — no new auth plumbing.
boxzoho-desktrellomicrosoft-excelgoogle-drivegoogle-vaultllms.txtSelected by surveying the published connector catalogs of Glean, Onyx, Dust, Vectara, Writer, Guru, Elastic, Microsoft 365 Copilot, Notion AI, Unstructured, and Airbyte, then intersecting the gaps with services that already have a Sim block. Box was the single biggest gap — 7-8 of ~10 catalogs, and the default content store in financial services, life sciences, and government.
Validation
Every connector was validated against live provider documentation twice, independently. The second pass was told to treat the first pass's conclusions as unproven — which mattered, because it found defects in the first pass's own fixes.
Data-loss class
The sync engine hard-deletes documents past a cap not flagged with
listingCapped. Paths found and fixed across both passes:llms.txtandsitemap.xml404, or an HTTP-200 HTML interstitial, whichdocs.cursor.comreally serves) reconciled the whole KB away. A sitemap-index child that 404s was silently skipped despite a comment claiming failure was fatal. The origin-level index returned early with 13 of 306 pages for a sub-path site.listingCappedlatched permanently on any list of 1000+ cards; then the fix for that stopped flagging multi-page lists while resting on an ordering guarantee Trello does not document.from <= 4999ceiling and 422'd the whole listing at the documented 5000 maximum.more: truewith zero incidents ended the listing unflagged.Because five of ten audited connectors had some path here, the engine also gained a backstop: an empty or collapsed listing now blocks deletion reconciliation until the same observation repeats on a consecutive sync. No migration — the previous run is reconstructed from existing sync-log counters. Corroboration is only trusted from a run that could not have been incremental, otherwise a bad listing confirms itself.
Correctness
desk.zoho.cadoes not resolve. Canada isdesk.zohocloud.ca. All 11 data centers were then re-verified by DNS and an authenticated probe returning401 UNAUTHORIZED, which proves the host serves the Desk v1 API. Singapore and UAE were missing entirely.modifiedTimeis absent fromGET /tickets, so the stub and hydrated hashes never matched and every ticket re-embedded on every sync, forever.dateLastActivitywithout creating an action, and never published which. The hash now folds inbadgescounters, which arrive with the listing at no extra cost.42019, not1/15/2015), unlike Google Sheets. Graph documents thatRange.textis independent of cell width, so the#######objection does not apply. A content-format token forces one re-index, since the metadata-only hash would otherwise keep stale content.offset + limit, so the guard admitted a request that 400s after any short page. The incremental window was also only half pinned.extracted_textgave up before polling when a representation was not yet generated..mdroute 404s hydrated every page to nothing whilevalidateConfigpassed. The HTML fallback then indexed<script>contents: 294KB of RSC payload per page, 98% noise.Security
getDocumentusedstat, which follows symlinks. Filenames fromreaddirwere composed into paths unchecked. Host-key verification was absent entirely; an optional fingerprint now verifies during key exchange, before any password is sent. It is opt-in and blank by default, so an unconfigured source retains the original MITM exposure — IP pinning does not mitigate this, since the pin derives from the same DNS answer an attacker would poison.ediscovery(which grants delete on matters and holds) toediscovery.readonly.getDataverseBaseUrlaccepted any host while every request attaches a bearer token. Pinned to Microsoft's Dataverse domains. This is pre-existing shipped code, fixed here.Removed: Microsoft Dataverse
Built, then cut. Its OAuth cannot complete consent, and never could. Dataverse requires a per-environment resource (
<environment-url>/user_impersonation); the provider declares a statichttps://dynamics.microsoft.com/user_impersonation, which is not an Entra Application ID URI. The scope is fixed at Better Auth config time with no per-connection override, and the environment URL is only collected after the credential exists — so nothing can supply it at authorize time. Entra rejects at/authorizewithAADSTS500011.This predates the PR and affects the 12 shipped
tools/microsoft_dataverse/*tools. Added in a bulk tool-authoring PR (#3257) with zero tests; the later "align with live API docs" PR (#5481) touched no OAuth file. A real fix needs a contract, route, and UI change plus an Entra app-registration permission, so it belongs in its own change. One-minute confirmation: open the authorize URL in a browser signed into any work tenant.Also cut earlier: Google Groups (no public API returns conversations — the Migration API is insert-only) and Workday (native file APIs need OAuth we haven't wired; only custom-report rows were reachable).
Claims corrected during validation
Stated in an earlier revision of this description and since disproven:
GET /status_pages/{id}/posts/{post_id}/postmortem. ButStatusPagePost.linked_resource.typeis an untyped string with no documented incident join, so it belongs in a separate status-pages connector, not the incident walk..well-known/llms.txtis not a real Mintlify location — 404s on every site checked.sourceConfigonce before the pagination loop, so enabled kinds cannot change mid-sync. The defensive branch is gone.beforepagination is not a reliable completeness guarantee, only a usable dedup bound.Known gaps
created_at:ascplus the 10k ceiling leaves a permanent hole on large accounts.ascis correct for offset-pagination integrity, so the fix is time-window chunking, not flipping todesc.[markdown]representation would preserve table structure that flatextracted_textdestroys.docs.anthropic.com→platform.claude.com); needsurlonSecureFetchResponse.addis invisible in sync counters. Shared with google-docs; belongs in a follow-up covering both.Still missing from the catalog
A generic web crawler (6/10 catalogs, backstops every source not in the catalog), Bitbucket, Guru, Coda, and a database/warehouse source. None have blocks today.
Testing
bun run type-checkcleanbiome checkclean across 229 filesbun run check:api-validationpassesNot exercised against live tenants. Validation was documentation-based, with live DNS and HTTP probes where a host or response shape could be checked without credentials.