From 9ed28548d9b09921ddc840700ca77dd84b7b84b4 Mon Sep 17 00:00:00 2001 From: Guido Vizoso Date: Thu, 20 Aug 2026 15:19:23 -0300 Subject: [PATCH 01/34] Take out the Drive connector that answered as the deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The knowledge lane needs answers that come back as the person asking. What was in the tree did the opposite: `connectors.ts` configured Google Drive with a service account and a domain-impersonation subject, and the worker synced documents into a local pgvector index guarded by our own ACL rows. Every person got the same answer, computed from what one credential could see, and revoking somebody's access left a cached copy of their documents behind. Fixing it is not a change to that code, it is the other design, so this takes it out first rather than building the replacement beside it. Nothing imported any of it outside its own tests, so nothing observable goes with it except two admin screens that configured a sync that will not happen. Gone: the in-memory knowledge repository and its ACL check, the knowledge agent, the connector catalogue and admin service, the sync persistence and the worker's connector runner, the `/api/admin/connectors` routes and the two admin screens in front of them. Kept on purpose, both recorded where a reader will meet them: - `knowledge.yaml` is still parsed and still validated. It is part of the deployment-package contract and shipped packages carry it, so a malformed one should keep being refused. `knowledgeSources` is now read by nothing, and says so, so the next reader does not take it for something live. - Every table stays. Dropping `connector_instances`, `documents`, `chunks`, `document_acls` and the rest is an irreversible migration with none of this slice's purpose behind it, and the `chunks` embedding column may yet be wanted. They are unused tables until somebody decides otherwise. Two things worth knowing for the next change here. `createApp` lost a positional parameter, so the placeholder runs in the agent and channel route tests each drop one `undefined`; both tests assert through the store they pass, which is what catches a slot landing in the wrong position, since consecutive `undefined`s shift without a type error. And `routeTree.gen.ts` carries `@ts-nocheck`, so `bun run typecheck` stayed green while the route tree still imported both deleted screens — the build is what catches that, not the typechecker. The worker is now a stub that reports idle. Left in place; removing a workspace is a separate decision. --- app/src/components/admin/admin-sidebar.tsx | 10 +- app/src/lib/connectors/queries.ts | 28 ---- app/src/routeTree.gen.ts | 54 ------- app/src/routes/_authed/admin/connectors.tsx | 89 ----------- .../_authed/admin/connectors/google-drive.tsx | 143 ------------------ app/src/routes/_authed/admin/index.tsx | 7 - app/tests/connectors.test.ts | 6 - server/src/agents/knowledge-agent.ts | 22 --- server/src/app.ts | 59 -------- server/src/connectors.ts | 124 --------------- server/src/connectors/contract.ts | 27 ---- server/src/connectors/sync-persistence.ts | 107 ------------- server/src/index.ts | 10 -- server/src/knowledge/acl.ts | 22 --- server/src/knowledge/repository.ts | 57 ------- server/src/knowledge/types.ts | 9 -- server/src/tenant-package.ts | 10 ++ server/tests/agent-routes.test.ts | 5 +- server/tests/channel-routes.test.ts | 3 +- .../tests/connector-admin.integration.test.ts | 109 ------------- server/tests/connectors.test.ts | 135 ----------------- server/tests/knowledge-acl.test.ts | 30 ---- server/tests/knowledge-agent.test.ts | 37 ----- server/tests/knowledge-repository.test.ts | 51 ------- .../sync-persistence.integration.test.ts | 97 ------------ worker/src/connector-runner.ts | 45 ------ worker/tests/connector-runner.test.ts | 77 ---------- worker/tests/status.test.ts | 2 +- 28 files changed, 16 insertions(+), 1359 deletions(-) delete mode 100644 app/src/lib/connectors/queries.ts delete mode 100644 app/src/routes/_authed/admin/connectors.tsx delete mode 100644 app/src/routes/_authed/admin/connectors/google-drive.tsx delete mode 100644 app/tests/connectors.test.ts delete mode 100644 server/src/agents/knowledge-agent.ts delete mode 100644 server/src/connectors.ts delete mode 100644 server/src/connectors/contract.ts delete mode 100644 server/src/connectors/sync-persistence.ts delete mode 100644 server/src/knowledge/acl.ts delete mode 100644 server/src/knowledge/repository.ts delete mode 100644 server/src/knowledge/types.ts delete mode 100644 server/tests/connector-admin.integration.test.ts delete mode 100644 server/tests/connectors.test.ts delete mode 100644 server/tests/knowledge-acl.test.ts delete mode 100644 server/tests/knowledge-agent.test.ts delete mode 100644 server/tests/knowledge-repository.test.ts delete mode 100644 server/tests/sync-persistence.integration.test.ts delete mode 100644 worker/src/connector-runner.ts delete mode 100644 worker/tests/connector-runner.test.ts diff --git a/app/src/components/admin/admin-sidebar.tsx b/app/src/components/admin/admin-sidebar.tsx index 1a5559e9..a2813876 100644 --- a/app/src/components/admin/admin-sidebar.tsx +++ b/app/src/components/admin/admin-sidebar.tsx @@ -5,7 +5,6 @@ import { IconKey, IconLayoutGrid, IconListDetails, - IconPlugConnected, IconPuzzle, IconShieldCheck, } from "@tabler/icons-react"; @@ -29,9 +28,9 @@ const adminLinkOptions = { to: "/admin" } satisfies LinkOptions; /** * The same three groups, in the same order, as the admin index. * - * A rail that lists eight things flat asks somebody to know which of them is the one they want. The + * A rail that lists seven things flat asks somebody to know which of them is the one they want. The * grouping is the only navigation help this screen offers, so it has to agree with the page it - * navigates to — two different orderings of the same eight links is worse than either ordering. + * navigates to — two different orderings of the same seven links is worse than either ordering. */ const GROUPS: { label: string; @@ -44,11 +43,6 @@ const GROUPS: { { label: "What Bots can reach", items: [ - { - title: "Connectors", - icon: IconPlugConnected, - linkOptions: { to: "/admin/connectors" }, - }, { title: "Credentials", icon: IconKey, diff --git a/app/src/lib/connectors/queries.ts b/app/src/lib/connectors/queries.ts deleted file mode 100644 index ac0e08f3..00000000 --- a/app/src/lib/connectors/queries.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { queryOptions } from "@tanstack/react-query"; - -export type ConnectorStatus = { - id: string; - type: "google_drive" | "onedrive"; - name: string; - roots: string[]; - configured: boolean; -}; - -export const connectorKeys = { - all: ["connectors"] as const, - list: () => [...connectorKeys.all, "list"] as const, -}; - -export function connectorListQueryOptions() { - return queryOptions({ - queryKey: connectorKeys.list(), - queryFn: async (): Promise => { - const response = await fetch("/api/admin/connectors", { - credentials: "include", - }); - if (!response.ok) throw new Error("Could not load connectors"); - return ((await response.json()) as { connectors: ConnectorStatus[] }) - .connectors; - }, - }); -} diff --git a/app/src/routeTree.gen.ts b/app/src/routeTree.gen.ts index 3feb12cc..78ca426e 100644 --- a/app/src/routeTree.gen.ts +++ b/app/src/routeTree.gen.ts @@ -22,7 +22,6 @@ import { Route as AuthedAdminAuditRouteImport } from './routes/_authed/admin/aud import { Route as AuthedAdminBoundariesRouteImport } from './routes/_authed/admin/boundaries' import { Route as AuthedAdminComponentsRouteImport } from './routes/_authed/admin/components' import { Route as AuthedAdminComputersRouteImport } from './routes/_authed/admin/computers' -import { Route as AuthedAdminConnectorsRouteImport } from './routes/_authed/admin/connectors' import { Route as AuthedAdminCredentialsRouteImport } from './routes/_authed/admin/credentials' import { Route as AuthedAdminPlaygroundRouteImport } from './routes/_authed/admin/playground' import { Route as AuthedAdminPluginsRouteImport } from './routes/_authed/admin/plugins' @@ -30,7 +29,6 @@ import { Route as AuthedSettingsIndexRouteImport } from './routes/_authed/settin import { Route as AuthedAppAgentsIndexRouteImport } from './routes/_authed/_app/agents/index' import { Route as AuthedAppChannelChannelIdRouteImport } from './routes/_authed/_app/channel/$channelId' import { Route as AuthedAppChannelNewRouteImport } from './routes/_authed/_app/channel/new' -import { Route as AuthedAdminConnectorsGoogleDriveRouteImport } from './routes/_authed/admin/connectors/google-drive' const AuthedRoute = AuthedRouteImport.update({ id: '/_authed', @@ -95,11 +93,6 @@ const AuthedAdminComputersRoute = AuthedAdminComputersRouteImport.update({ path: '/computers', getParentRoute: () => AuthedAdminRouteRoute, } as any) -const AuthedAdminConnectorsRoute = AuthedAdminConnectorsRouteImport.update({ - id: '/connectors', - path: '/connectors', - getParentRoute: () => AuthedAdminRouteRoute, -} as any) const AuthedAdminCredentialsRoute = AuthedAdminCredentialsRouteImport.update({ id: '/credentials', path: '/credentials', @@ -136,12 +129,6 @@ const AuthedAppChannelNewRoute = AuthedAppChannelNewRouteImport.update({ path: '/channel/new', getParentRoute: () => AuthedAppRoute, } as any) -const AuthedAdminConnectorsGoogleDriveRoute = - AuthedAdminConnectorsGoogleDriveRouteImport.update({ - id: '/google-drive', - path: '/google-drive', - getParentRoute: () => AuthedAdminConnectorsRoute, - } as any) export interface FileRoutesByFullPath { '/': typeof AuthedAppIndexRoute @@ -154,7 +141,6 @@ export interface FileRoutesByFullPath { '/admin/boundaries': typeof AuthedAdminBoundariesRoute '/admin/components': typeof AuthedAdminComponentsRoute '/admin/computers': typeof AuthedAdminComputersRoute - '/admin/connectors': typeof AuthedAdminConnectorsRouteWithChildren '/admin/credentials': typeof AuthedAdminCredentialsRoute '/admin/playground': typeof AuthedAdminPlaygroundRoute '/admin/plugins': typeof AuthedAdminPluginsRoute @@ -162,7 +148,6 @@ export interface FileRoutesByFullPath { '/settings/': typeof AuthedSettingsIndexRoute '/channel/$channelId': typeof AuthedAppChannelChannelIdRoute '/channel/new': typeof AuthedAppChannelNewRoute - '/admin/connectors/google-drive': typeof AuthedAdminConnectorsGoogleDriveRoute '/agents/': typeof AuthedAppAgentsIndexRoute } export interface FileRoutesByTo { @@ -174,7 +159,6 @@ export interface FileRoutesByTo { '/admin/boundaries': typeof AuthedAdminBoundariesRoute '/admin/components': typeof AuthedAdminComponentsRoute '/admin/computers': typeof AuthedAdminComputersRoute - '/admin/connectors': typeof AuthedAdminConnectorsRouteWithChildren '/admin/credentials': typeof AuthedAdminCredentialsRoute '/admin/playground': typeof AuthedAdminPlaygroundRoute '/admin/plugins': typeof AuthedAdminPluginsRoute @@ -182,7 +166,6 @@ export interface FileRoutesByTo { '/settings': typeof AuthedSettingsIndexRoute '/channel/$channelId': typeof AuthedAppChannelChannelIdRoute '/channel/new': typeof AuthedAppChannelNewRoute - '/admin/connectors/google-drive': typeof AuthedAdminConnectorsGoogleDriveRoute '/agents': typeof AuthedAppAgentsIndexRoute } export interface FileRoutesById { @@ -198,7 +181,6 @@ export interface FileRoutesById { '/_authed/admin/boundaries': typeof AuthedAdminBoundariesRoute '/_authed/admin/components': typeof AuthedAdminComponentsRoute '/_authed/admin/computers': typeof AuthedAdminComputersRoute - '/_authed/admin/connectors': typeof AuthedAdminConnectorsRouteWithChildren '/_authed/admin/credentials': typeof AuthedAdminCredentialsRoute '/_authed/admin/playground': typeof AuthedAdminPlaygroundRoute '/_authed/admin/plugins': typeof AuthedAdminPluginsRoute @@ -207,7 +189,6 @@ export interface FileRoutesById { '/_authed/settings/': typeof AuthedSettingsIndexRoute '/_authed/_app/channel/$channelId': typeof AuthedAppChannelChannelIdRoute '/_authed/_app/channel/new': typeof AuthedAppChannelNewRoute - '/_authed/admin/connectors/google-drive': typeof AuthedAdminConnectorsGoogleDriveRoute '/_authed/_app/agents/': typeof AuthedAppAgentsIndexRoute } export interface FileRouteTypes { @@ -223,7 +204,6 @@ export interface FileRouteTypes { | '/admin/boundaries' | '/admin/components' | '/admin/computers' - | '/admin/connectors' | '/admin/credentials' | '/admin/playground' | '/admin/plugins' @@ -231,7 +211,6 @@ export interface FileRouteTypes { | '/settings/' | '/channel/$channelId' | '/channel/new' - | '/admin/connectors/google-drive' | '/agents/' fileRoutesByTo: FileRoutesByTo to: @@ -243,7 +222,6 @@ export interface FileRouteTypes { | '/admin/boundaries' | '/admin/components' | '/admin/computers' - | '/admin/connectors' | '/admin/credentials' | '/admin/playground' | '/admin/plugins' @@ -251,7 +229,6 @@ export interface FileRouteTypes { | '/settings' | '/channel/$channelId' | '/channel/new' - | '/admin/connectors/google-drive' | '/agents' id: | '__root__' @@ -266,7 +243,6 @@ export interface FileRouteTypes { | '/_authed/admin/boundaries' | '/_authed/admin/components' | '/_authed/admin/computers' - | '/_authed/admin/connectors' | '/_authed/admin/credentials' | '/_authed/admin/playground' | '/_authed/admin/plugins' @@ -275,7 +251,6 @@ export interface FileRouteTypes { | '/_authed/settings/' | '/_authed/_app/channel/$channelId' | '/_authed/_app/channel/new' - | '/_authed/admin/connectors/google-drive' | '/_authed/_app/agents/' fileRoutesById: FileRoutesById } @@ -377,13 +352,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthedAdminComputersRouteImport parentRoute: typeof AuthedAdminRouteRoute } - '/_authed/admin/connectors': { - id: '/_authed/admin/connectors' - path: '/connectors' - fullPath: '/admin/connectors' - preLoaderRoute: typeof AuthedAdminConnectorsRouteImport - parentRoute: typeof AuthedAdminRouteRoute - } '/_authed/admin/credentials': { id: '/_authed/admin/credentials' path: '/credentials' @@ -433,35 +401,14 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthedAppChannelNewRouteImport parentRoute: typeof AuthedAppRoute } - '/_authed/admin/connectors/google-drive': { - id: '/_authed/admin/connectors/google-drive' - path: '/google-drive' - fullPath: '/admin/connectors/google-drive' - preLoaderRoute: typeof AuthedAdminConnectorsGoogleDriveRouteImport - parentRoute: typeof AuthedAdminConnectorsRoute - } } } -interface AuthedAdminConnectorsRouteChildren { - AuthedAdminConnectorsGoogleDriveRoute: typeof AuthedAdminConnectorsGoogleDriveRoute -} - -const AuthedAdminConnectorsRouteChildren: AuthedAdminConnectorsRouteChildren = { - AuthedAdminConnectorsGoogleDriveRoute: AuthedAdminConnectorsGoogleDriveRoute, -} - -const AuthedAdminConnectorsRouteWithChildren = - AuthedAdminConnectorsRoute._addFileChildren( - AuthedAdminConnectorsRouteChildren, - ) - interface AuthedAdminRouteRouteChildren { AuthedAdminAuditRoute: typeof AuthedAdminAuditRoute AuthedAdminBoundariesRoute: typeof AuthedAdminBoundariesRoute AuthedAdminComponentsRoute: typeof AuthedAdminComponentsRoute AuthedAdminComputersRoute: typeof AuthedAdminComputersRoute - AuthedAdminConnectorsRoute: typeof AuthedAdminConnectorsRouteWithChildren AuthedAdminCredentialsRoute: typeof AuthedAdminCredentialsRoute AuthedAdminPlaygroundRoute: typeof AuthedAdminPlaygroundRoute AuthedAdminPluginsRoute: typeof AuthedAdminPluginsRoute @@ -473,7 +420,6 @@ const AuthedAdminRouteRouteChildren: AuthedAdminRouteRouteChildren = { AuthedAdminBoundariesRoute: AuthedAdminBoundariesRoute, AuthedAdminComponentsRoute: AuthedAdminComponentsRoute, AuthedAdminComputersRoute: AuthedAdminComputersRoute, - AuthedAdminConnectorsRoute: AuthedAdminConnectorsRouteWithChildren, AuthedAdminCredentialsRoute: AuthedAdminCredentialsRoute, AuthedAdminPlaygroundRoute: AuthedAdminPlaygroundRoute, AuthedAdminPluginsRoute: AuthedAdminPluginsRoute, diff --git a/app/src/routes/_authed/admin/connectors.tsx b/app/src/routes/_authed/admin/connectors.tsx deleted file mode 100644 index dd699db5..00000000 --- a/app/src/routes/_authed/admin/connectors.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { IconBrandGoogleDrive, IconCloud } from "@tabler/icons-react"; -import { useQuery } from "@tanstack/react-query"; -import { createFileRoute, Link } from "@tanstack/react-router"; -import { - PageEmpty, - PageRows, - PageSection, - PageShell, -} from "@/components/layout/page-shell"; -import { StaggerItem } from "@/components/layout/stagger"; -import { Button } from "@/components/ui/button"; -import { - Item, - ItemActions, - ItemContent, - ItemDescription, - ItemMedia, - ItemTitle, -} from "@/components/ui/item"; -import { Separator } from "@/components/ui/separator"; -import { connectorListQueryOptions } from "@/lib/connectors/queries"; - -export const Route = createFileRoute("/_authed/admin/connectors")({ - component: ConnectorsPage, -}); - -function ConnectorsPage() { - const connectors = useQuery(connectorListQueryOptions()); - return ( - - - {connectors.isPending ? ( - Loading connectors… - ) : connectors.error ? ( -

- Could not load connectors. -

- ) : connectors.data?.length === 0 ? ( - - No connectors. They come from this deployment's knowledge sources. - - ) : ( - - {connectors.data?.map((connector, index) => ( - - - - {connector.type === "google_drive" ? ( - - ) : ( - - )} - - - {connector.name} - - Roots: {connector.roots.join(", ")} ·{" "} - {connector.configured ? "Configured" : "Not configured"} - - - - {connector.type === "google_drive" ? ( - - ) : ( - // Said rather than left blank, which would read as a control yet to arrive. - - No setup screen yet - - )} - - - {index !== (connectors.data?.length ?? 0) - 1 && } - - ))} - - )} -
-
- ); -} diff --git a/app/src/routes/_authed/admin/connectors/google-drive.tsx b/app/src/routes/_authed/admin/connectors/google-drive.tsx deleted file mode 100644 index f2d79ebf..00000000 --- a/app/src/routes/_authed/admin/connectors/google-drive.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { useForm } from "@tanstack/react-form"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { createFileRoute } from "@tanstack/react-router"; -import { z } from "zod"; -import { PageShell } from "@/components/layout/page-shell"; -import { Button } from "@/components/ui/button"; -import { - Field, - FieldError, - FieldGroup, - FieldLabel, -} from "@/components/ui/field"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { connectorKeys } from "@/lib/connectors/queries"; - -export const Route = createFileRoute("/_authed/admin/connectors/google-drive")({ - component: GoogleDriveConnectorPage, -}); - -function GoogleDriveConnectorPage() { - const queryClient = useQueryClient(); - const setup = useMutation({ - mutationFn: async (value: { - serviceAccountJson: string; - impersonationSubject: string; - }) => { - const response = await fetch("/api/admin/connectors/google-drive/setup", { - method: "POST", - credentials: "include", - headers: { "content-type": "application/json" }, - body: JSON.stringify(value), - }); - if (!response.ok) throw new Error("Could not set up Google Drive"); - }, - onSuccess: () => - queryClient.invalidateQueries({ queryKey: connectorKeys.all }), - }); - const form = useForm({ - defaultValues: { serviceAccountJson: "", impersonationSubject: "" }, - validators: { - onSubmit: z.object({ - serviceAccountJson: z - .string() - .trim() - .refine((value) => { - try { - const parsed: unknown = JSON.parse(value); - return Boolean( - parsed && typeof parsed === "object" && !Array.isArray(parsed), - ); - } catch { - return false; - } - }, "Paste a valid service-account JSON object."), - impersonationSubject: z - .string() - .email("Enter the Workspace account to impersonate."), - }), - }, - onSubmit: async ({ value }) => { - await setup.mutateAsync(value); - form.reset(); - }, - }); - return ( - /* - * THE FORM STAYS ON THE PAGE HERE, unlike the rest of admin. This route exists only to hold it — - * there is no list behind it to interrupt — so putting it in a dialog would mean navigating to a - * page whose only content immediately covers itself up. - */ - -
{ - event.preventDefault(); - form.handleSubmit(); - }} - > - - - {(field) => ( - - - Service account JSON key - -