Skip to content

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

Merged
waleedlatif1 merged 5 commits into
stagingfrom
worktree-kb-connector-gaps
Aug 14, 2026
Merged

feat(connectors): add 9 knowledge base connectors#6699
waleedlatif1 merged 5 commits 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.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 14, 2026 8:36pm

Request Review

@cursor

cursor Bot commented Aug 14, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Large expansion of external sync surface (user-supplied hosts, SFTP credentials, and doc-site crawling) with complex listing-cap logic; mis-flagging listingCapped or discovery failures could still affect KB document reconciliation despite guards.

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

Each connector implements listing, deferred content fetch, config validation, and tag mapping with provider-specific pagination, caps, and listingCapped signaling so partial listings do not trigger wrongful deletions. Mintlify discovers pages via llms.txt / sitemap with SSRF-safe fetching; SFTP walks remote trees with depth/file limits, optional SHA-256 host key pinning, symlink-safe reads, and session timeouts.

UI: the add-connector modal allows optional API keys when connector meta sets auth.optional (e.g. public Mintlify sites).

Security fixes: Microsoft Dataverse file upload outbound calls use stripAuthOnRedirect so OAuth tokens are not sent to signed storage redirects; SFTP connection helper adds fingerprint verification, idle timeout handling, and clearer host-key errors.

Reviewed by Cursor Bugbot for commit eb1e556. 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 safeguards, while also hardening the existing Microsoft Dataverse tools against credential disclosure.

  • Registers Box, Zoho Desk, PagerDuty, Trello, Microsoft Excel, Google Slides, Google Vault, Mintlify, and SFTP connectors.
  • Adds safer listing reconciliation and connector-specific pagination, hydration, and content-processing behavior.
  • Restricts Dataverse environment hosts and strips bearer authorization across redirects, including the upload route’s outbound request.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains from the previous review threads.

The arbitrary-host and redirect-based Dataverse bearer-token disclosures are addressed in current HEAD, including the upload route’s separate outbound fetch.

Important Files Changed

Filename Overview
apps/sim/tools/microsoft_dataverse/utils.ts Normalizes environment URLs and restricts bearer-authenticated Dataverse requests to HTTPS origins under Microsoft’s supported Dataverse domains.
apps/sim/app/api/tools/microsoft-dataverse/upload-file/route.ts Prevents the outbound upload PATCH from forwarding its OAuth bearer token to signed-storage redirect targets.
apps/sim/tools/microsoft_dataverse/upload_file.ts Keeps the user-entered environment URL user-only and delegates the external upload to the independently hardened internal route.
apps/sim/lib/knowledge/connectors/sync-engine.ts Adds reconciliation safeguards for suspiciously empty or collapsed connector listings.
apps/sim/connectors/registry.server.ts Registers the new connector runtimes for server-side synchronization.

Sequence Diagram

sequenceDiagram
  participant Tool as Dataverse Tool
  participant Route as Internal Upload Route
  participant DV as Dataverse API
  participant Storage as Signed Storage Host
  Tool->>Route: Same-origin upload request
  Route->>DV: PATCH file with OAuth bearer token
  DV-->>Route: Redirect to signed storage URL
  Route->>Storage: PATCH file body without Authorization
  Storage-->>Route: Upload response
  Route-->>Tool: Upload result
Loading

Reviews (6): Last reviewed commit: "fix(dataverse): strip the bearer token o..." | 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

Comment thread apps/sim/connectors/microsoft-excel/microsoft-excel.ts
Comment thread apps/sim/connectors/google-slides/google-slides.ts
@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

Comment thread apps/sim/tools/microsoft_dataverse/utils.ts
Comment thread apps/sim/connectors/mintlify/mintlify.ts
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.
The host allowlist added alongside the connector work only constrains the
initial destination. `secureFetchWithPinnedIP` follows redirects and keeps the
`Authorization` header unless a tool opts out, so a redirect away from an
allowed Dataverse origin would forward the caller's OAuth token to whatever
host answers. Dataverse redirects in normal operation — file downloads hand
back a signed storage URL, and environment hosts move between regional
origins — so this is reachable without a compromised environment URL.

Sets `stripAuthOnRedirect` on all 18 Dataverse tools, matching the existing
GitHub job-logs and Windchill precedent.
@waleedlatif1
waleedlatif1 force-pushed the worktree-kb-connector-gaps branch from 26103b2 to 903c94e Compare August 14, 2026 19:59
- microsoft-excel: `fetchWorksheets` read only the first Graph page and never
  followed `@odata.nextLink`. A workbook with more sheets than fit in one page
  dropped the remainder from the listing without setting `listingCapped`, so
  the sync engine reconciled those documents away as deleted. The walk now
  pages, bounded by MAX_WORKSHEETS, and only follows a nextLink that stays on
  the Graph origin, since the link is server-supplied and carries the token.

- google-slides: the listing `contentHash` covered only the file id and
  modified time, so toggling the speaker-notes option left every stored hash
  matching and no presentation was ever re-hydrated with the new scope. The
  setting is now part of the hash, in the single shared stub builder so the
  list and hydrate paths stay identical.

- mintlify: `pathPrefix` filtered with a bare `startsWith`, so a prefix of
  `/guides` also matched a sibling like `/guides-archive`. It now shares the
  `/`-boundary rule `withinBasePath` already used, extracted as `isUnderPath`.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/connectors/zoho-desk/zoho-desk.ts Outdated
Comment thread apps/sim/connectors/mintlify/mintlify.ts
…ash prefix

- zoho-desk: `sortBy: 'createdTime'` is ascending — Zoho denotes descending
  with a `-` prefix — so the default 500-record caps kept the oldest tickets
  and articles and recent ones were never listed. Because the cap sets
  listingCapped, that stale tail could not reconcile away either. Now sorts
  `-createdTime`. Still ordering on createdTime rather than modifiedTime, so
  rows do not reshuffle mid-walk.

- mintlify: `resolvePathPrefix` kept a trailing slash while `isUnderPath`
  accepts an exact match or `prefix + '/'`, so `/guides/` matched neither
  `/guides` nor `/guides/intro` and the source synced nothing. A regression
  from the previous round, which replaced a bare `startsWith`. The prefix is
  now normalized before comparison.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

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

✅ 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 74cda71. Configure here.

Comment thread apps/sim/tools/microsoft_dataverse/upload_file.ts
…rect

`upload_file` posts to an internal route rather than calling Dataverse
directly, so the tool-level `stripAuthOnRedirect` added in 903c94e only
covers the same-origin hop into that route. The route's own outbound PATCH
carries the caller's OAuth token and left redirect stripping at its default,
so a redirect to a signed storage host — which is exactly how Dataverse
serves file operations — would have handed that host a reusable credential.

The other 17 tools build the Dataverse URL directly, so the tool-level flag
already covers them.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

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

✅ 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 eb1e556. Configure here.

@waleedlatif1
waleedlatif1 merged commit 5bb59f0 into staging Aug 14, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the worktree-kb-connector-gaps branch August 14, 2026 21:14
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