diff --git a/doc/plans/2026-10-13-connection-api-parity.md b/doc/plans/2026-10-13-connection-api-parity.md index 5ec454c4620..692458bdd41 100644 --- a/doc/plans/2026-10-13-connection-api-parity.md +++ b/doc/plans/2026-10-13-connection-api-parity.md @@ -123,3 +123,6 @@ The implementation was rebased onto `a1f77821b9cd5c9c846fdf7a0fa5cc620ad2b6bb`. - A subsequent route review found a board-only owner helper left behind in the sandbox device-login path. It now uses the shared connection authority while keeping the responsible user as immutable session owner. A focused assembled-server case passed for actual key/JWT reads, cancellation, strict start validation, and another-owner denial. This fixture does not launch a sandbox/provider process; existing login service fixtures cover that contract. - Map review also corrected unsupported MCP GET handlers (405, POST required), restored private voice/phone consent boundaries and existing chat provenance notes, and distinguished saved device-session HTTP evidence from provider authentication. + +- Final assembled-server acceptance after the device-login fix: **32 scenarios passed** in a fresh PostgreSQL database. +- Review found that the top-level Apps connect route rejected an `aiLogin`-only handoff before rendering its saved login panel. The new route-policy test failed before the fix; the route now admits a non-empty saved-login ID, leaving owner/session validation to the existing server and panel. Empty IDs remain rejected. The prior component-only tests did not cover this entry gate. diff --git a/ui/src/pages/apps/app-connect-policy.test.ts b/ui/src/pages/apps/app-connect-policy.test.ts index 89d00279801..7baa492a09d 100644 --- a/ui/src/pages/apps/app-connect-policy.test.ts +++ b/ui/src/pages/apps/app-connect-policy.test.ts @@ -11,6 +11,12 @@ import { } from "./app-connect-policy"; describe("app connect policy", () => { + it("admits a saved AI login handoff without a catalog source", () => { + expect(canEnterAppsConnect(new URLSearchParams("aiLogin=saved-login"))).toBe(true); + expect(canEnterAppsConnect(new URLSearchParams("aiLogin="))).toBe(false); + expect(canEnterAppsConnect(new URLSearchParams("aiLogin=%20"))).toBe(false); + }); + it("derives automatic OAuth entry points from app capabilities", () => { expect(MCP_DIRECT_OAUTH_CONNECT_SLUGS).toEqual(expect.arrayContaining(["jira", "notion", "sentry"])); expect(isMcpDirectOAuthConnectSlug("notion")).toBe(true); diff --git a/ui/src/pages/apps/app-connect-policy.ts b/ui/src/pages/apps/app-connect-policy.ts index 20f147da509..ba96b4ab09b 100644 --- a/ui/src/pages/apps/app-connect-policy.ts +++ b/ui/src/pages/apps/app-connect-policy.ts @@ -57,6 +57,7 @@ export function canEnterAppsConnect( searchParams: URLSearchParams, { chatConnectorsEnabled = false, githubReviewBotsEnabled = false }: { chatConnectorsEnabled?: boolean; githubReviewBotsEnabled?: boolean } = {}, ): boolean { + if (searchParams.get("aiLogin")?.trim()) return true; if (searchParams.get("byo") === "1") { // The old BYO discovery page has moved to the Connectors list. Keep only // exact custom-connection reconnects using this legacy query contract.