Skip to content

feat(connectors): add 9 knowledge base connectors - #6699

Open
waleedlatif1 wants to merge 1 commit into
stagingfrom
worktree-kb-connector-gaps
Open

feat(connectors): add 9 knowledge base connectors#6699
waleedlatif1 wants to merge 1 commit into
stagingfrom
worktree-kb-connector-gaps

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

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.

Connector Auth Syncs
Box OAuth box Files, recursive from a folder or the whole account
Zoho Desk OAuth zoho-desk Help Center articles + tickets with conversations
PagerDuty API key Incidents, notes, timeline log entries
Trello OAuth trello Cards with descriptions, checklists, comments, attachments
Microsoft Excel OAuth microsoft-excel Worksheet data
Google Slides OAuth google-drive Slide text + speaker notes
Google Vault OAuth google-vault Matters, holds, saved queries
Mintlify API key (optional) Documentation pages via llms.txt
SFTP API key Remote file trees

Selected 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:

  • Mintlify — three independent listing-collapse paths. An empty discovery (both llms.txt and sitemap.xml 404, or an HTTP-200 HTML interstitial, which docs.cursor.com really 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.
  • Trello — cards in archived lists vanished from an unflagged listing; listingCapped latched 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.
  • Zoho Desk — the flag never fired at the default caps (500/50 and 500/100 are exact multiples); then the fix's probe walked into Zoho's hard from <= 4999 ceiling and 422'd the whole listing at the documented 5000 maximum.
  • PagerDutymore: true with zero incidents ended the listing unflagged.
  • SFTP — depth-limit pruning set the flag on every sync of a deep tree, permanently suppressing legitimate deletions.

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

  • Zoho Deskdesk.zoho.ca does not resolve. Canada is desk.zohocloud.ca. All 11 data centers were then re-verified by DNS and an authenticated probe returning 401 UNAUTHORIZED, which proves the host serves the Desk v1 API. Singapore and UAE were missing entirely.
  • Zoho DeskmodifiedTime is absent from GET /tickets, so the stub and hydrated hashes never matched and every ticket re-embedded on every sync, forever.
  • Trello — Atlassian documents that some edits bump dateLastActivity without creating an action, and never published which. The hash now folds in badges counters, which arrive with the listing at no extra cost.
  • Microsoft Excel — dates and currency indexed as raw serial numbers (42019, not 1/15/2015), unlike Google Sheets. Graph documents that Range.text is 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.
  • PagerDuty — the 10,000-record ceiling bounds offset + limit, so the guard admitted a request that 400s after any short page. The incremental window was also only half pinned.
  • Google Vault — one call per matter per kind truncated at ~249 matters, silently never indexed on any run. Now ~3,500.
  • SFTP — the incremental cutoff compared against the remote clock, permanently skipping same-second writes.
  • Boxextracted_text gave up before polling when a representation was not yet generated.
  • Mintlify — a site whose .md route 404s hydrated every page to nothing while validateConfig passed. The HTML fallback then indexed <script> contents: 294KB of RSC payload per page, 98% noise.

Security

  • SFTPgetDocument used stat, which follows symlinks. Filenames from readdir were 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.
  • Trello — user-supplied board ids were interpolated into URL paths raw.
  • Google Vault — narrowed from read-write ediscovery (which grants delete on matters and holds) to ediscovery.readonly.
  • Dataverse toolsgetDataverseBaseUrl accepted 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 static https://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 /authorize with AADSTS500011.

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:

  • PagerDuty does have a postmortem APIGET /status_pages/{id}/posts/{post_id}/postmortem. But StatusPagePost.linked_resource.type is an untyped string with no documented incident join, so it belongs in a separate status-pages connector, not the incident walk.
  • .well-known/llms.txt is not a real Mintlify location — 404s on every site checked.
  • The Google Vault cursor bug was unreachable — the engine reads sourceConfig once before the pagination loop, so enabled kinds cannot change mid-sync. The defensive branch is gone.
  • Trello's before pagination is not a reliable completeness guarantee, only a usable dedup bound.

Known gaps

  • SFTP host verification is opt-in. Consider requiring it, or TOFU-pinning the first-seen key.
  • PagerDuty created_at:asc plus the 10k ceiling leaves a permanent hole on large accounts. asc is correct for offset-pagination integrity, so the fix is time-window chunking, not flipping to desc.
  • Excel indexes hidden sheets, and issues one request for up to 200,000 cells against Microsoft's explicit large-range guidance.
  • Box [markdown] representation would preserve table structure that flat extracted_text destroys.
  • Mintlify cannot configure a docs site that redirects cross-host (docs.anthropic.complatform.claude.com); needs url on SecureFetchResponse.
  • Google Slides / Docs — a fetch failure on an add is invisible in sync counters. Shared with google-docs; belongs in a follow-up covering both.
  • No connector has tests.

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-check clean
  • biome check clean across 229 files
  • bun run check:api-validation passes
  • 245 tests pass, including 13 new sync-engine guard tests verified to fail when the guard is reverted

Not 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.

@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 14, 2026 7:17pm

Request Review

@cursor

cursor Bot commented Aug 14, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Large surface area: remote file/SFTP and user-supplied URLs (Mintlify), optional SFTP host verification by default, and sync listing logic where mis-flagged caps can block or allow wrongful deletions. OAuth/API credentials touch compliance and incident data (Vault, PagerDuty).

Overview
Adds nine knowledge base connectors (Box, Zoho Desk, PagerDuty, Trello, Microsoft Excel, Google Slides, Google Vault, Mintlify, SFTP) and registers them in client/server connector registries. Docs now list 61 built-in sources and document setup for PagerDuty, SFTP, and optional Mintlify keys.

SFTP gains optional SHA-256 host key pinning, idle socket timeouts, and stricter fingerprint validation in shared createSftpConnection; the SFTP connector walks remote trees with caps, incremental mtime filtering, and symlink-safe reads.

UI: API-key connectors can declare auth.optional (Mintlify public sites); the add-connector modal skips requiring a key and omits empty secrets on create.

New implementations follow existing patterns: deferred listing stubs, listingCapped when pagination or caps truncate, and provider-specific extraction (e.g. Box representations, Slides text, Vault matter/hold/query rendering, Excel Graph text values, Mintlify llms.txt/sitemap + SSRF-safe fetch, PagerDuty full incident history with date_range=all).

Reviewed by Cursor Bugbot for commit 26103b2. Configure here.

Comment thread apps/sim/connectors/zoho-desk/zoho-desk.ts
Comment thread apps/sim/connectors/microsoft-dataverse/microsoft-dataverse.ts Outdated
Comment thread apps/sim/connectors/pagerduty/pagerduty.ts Outdated
Comment thread apps/sim/connectors/trello/trello.ts Outdated
@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The 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.

  • Registers Box, Zoho Desk, PagerDuty, Trello, Microsoft Excel, Google Slides, Google Vault, Mintlify, and SFTP connectors.
  • Adds collapsed-listing reconciliation safeguards and connector-specific pagination, hydration, and deletion protections.
  • Adds optional SFTP host-key verification and Dataverse initial-origin validation.

Confidence Score: 3/5

The 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

Security Review

The Dataverse URL allowlist protects direct requests, but the tools do not enable cross-origin Authorization stripping. A redirect from an allowed Dataverse endpoint can therefore forward the OAuth bearer token to another origin. How this was verified: The shared redirect handler preserves Authorization unless stripAuthOnRedirect is true, and no Dataverse request enables that option.

Important Files Changed

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
Loading

Reviews (3): Last reviewed commit: "feat(connectors): add 9 knowledge base c..." | Re-trigger Greptile

Comment thread apps/sim/connectors/microsoft-dataverse/microsoft-dataverse.ts Outdated
@waleedlatif1 waleedlatif1 changed the title feat(connectors): add 10 knowledge base connectors feat(connectors): add 9 knowledge base connectors Aug 14, 2026
@waleedlatif1
waleedlatif1 force-pushed the worktree-kb-connector-gaps branch from 17c5922 to 96519cf Compare August 14, 2026 19:04
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review


const data = (await response.json()) as WorksheetListResponse
return data.value ?? []
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 96519cf. Configure here.

owners: file.owners?.map((o) => o.displayName || o.emailAddress).filter(Boolean),
},
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

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.
@waleedlatif1
waleedlatif1 force-pushed the worktree-kb-connector-gaps branch from 96519cf to 26103b2 Compare August 14, 2026 19:10
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

)
}

return parsed.origin

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 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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 using high effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

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 26103b2. Configure here.


const filtered = pathPrefix
? discovered.filter((page) => page.path.startsWith(pathPrefix))
: discovered

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 26103b2. Configure 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