Skip to content

Offer the first app for the workspace picked on the server picker - #1449

Merged
helpcodeai merged 3 commits into
mainfrom
fix/post-approve-picker-workspace
Nov 2, 2026
Merged

helpcodeai merged 3 commits into
mainfrom
fix/post-approve-picker-workspace

Conversation

@helpcodeai

Copy link
Copy Markdown
Contributor

What and why

Two problems seen in an end-to-end test on Cloud after #1440 and #1441.

1. Post-approve page after "Choose what to connect"

A user in several workspaces gets the "Choose what to connect" picker. If they picked an empty workspace where they are ADMIN or EDITOR, they went straight back to the client and never saw the first-connector page. There were two reasons:

  • POST /auth/select-servers always redirected to /callback. Only the no-picker path called maybeOfferFirstConnector.
  • maybeOfferFirstConnector counted connectors and checked the role in users.organizationId (the primary workspace), not in the workspace granted to this client.

Changes in packages/backend/src/auth/login.controller.ts:

  • New grantedWorkspace(clientId, userId, fallback). It resolves the one workspace this connection reaches, the same way the shared endpoint does:
    • an organization grant gives that organization;
    • a servers grant gives the servers' organization when they are all in one workspace;
    • no grant (connections from before grants existed) gives users.organizationId;
    • none, or servers spread over several workspaces, gives null. With no single workspace, nothing is offered.
  • maybeOfferFirstConnector uses that workspace for the connector count, the role check, the trial lookup and the product event.
  • handleServerSelection calls maybeOfferFirstConnector after a valid selection. It falls back to the old redirect when there is nothing to offer. The CSRF check and the signed pending_grant identity check stay in front of it, unchanged.
  • The social provider used to sign in (continueWith= dashboard links) is kept across the picker. It travels in a signed, httpOnly pending_grant_social cookie and is checked against the enabled providers when read.
  • POST /auth/first-app resolves the org through the same helper, so the app is installed into the workspace the page was offered for. The connector still lands on the granted servers of that workspace. Its CSRF cookie check, the signed login_user check, the pending-authorization check and the role/plan checks (canSetUp) are unchanged. One behaviour change: a grant whose servers span two workspaces now answers 403 ("page expired") instead of installing into the first server's workspace. The page is never offered for such a grant.

Single-workspace behaviour does not change. The picker is not shown there, the silent grant points at the user's own workspace, and the helper resolves to that workspace as before.

Cloud / self-hosted: the first-connector page and /auth/first-app stay Cloud-only (isCloud() guards, unchanged). On self-hosted, the picker submission still redirects straight to /callback. A spec covers this.

2. Etsy "app pending" panel

Etsy returns the same 403 for an app that is still Pending and for an active app with a wrong shared secret. The panel's headline said " has not approved your app yet", which is wrong in the second case. The headline is now neutral and the body covers both cases:

  • en: " does not accept these keys yet." / "If your app is new, reviews it, usually within a few days: we'll e-mail you when it's approved, nothing else to do. If your app is already active, copy the shared secret again from your app page. Your keys are saved."
  • de and it: translated to match.

The backend appPending flag and the Etsy verifyHints["403"] already name both cases, so no logic changes. Only the comments on checkAppKeys and on the appPending type in api.ts now say the flag means "maybe pending". The Playwright test in connector-guided-setup.spec.ts asserts the new text.

Not changed: the guided setup's "Wait for Etsy's approval" step (connectorGuide, "Etsy has not approved your app yet"). It already has its own "Already approved, but this still waits" path back to the keys.

Cloud cherry-pick note: the Cloud branch has no i18n, and its page.tsx still has the old English strings inline. A cherry-pick of this PR there must put the new English title and body inline in packages/frontend/src/app/connectors/setup/[slug]/page.tsx instead of the message files.

Tests

New specs in packages/backend/src/auth/login.controller.spec.ts:

  • Multi-workspace user picks an empty workspace (whole workspace, or servers in it): the first-connector page is shown for that workspace, and the event is recorded with that organizationId.
  • Picks a workspace that has connectors, or one where they are VIEWER, or servers in two workspaces: straight to /callback.
  • Self-hosted: straight to /callback.
  • Sign-in path: the granted workspace is counted, not the primary one.
  • The social provider is carried across the picker. An unknown provider in the cookie is ignored.
  • first-app installs into the granted workspace, not the primary one. It falls back to the user's own workspace when there is no grant. It refuses a none grant and a grant spanning two workspaces.

Commands run

Directory Command Result
packages/backend npx jest --maxWorkers=2 src/auth/login.controller src/auth/server-picker 3 suites, 104 tests passed
packages/backend npx eslint src/auth/login.controller.ts src/auth/login.controller.spec.ts src/adapters/adapters.service.ts clean
packages/backend npx tsc --noEmit -p tsconfig.json no errors in touched files; 13 baseline errors, all missing modules (basic-ftp, ssh2, @aws-sdk/client-s3, picomatch types) from a stale local node_modules, not from this change
packages/backend npx jest src/adapters/adapters.service.spec not runnable locally, same stale-node_modules picomatch typing error (only a comment changed in that file); left to CI
packages/frontend npx tsc --noEmit -p tsconfig.json passed
packages/frontend npx eslint src/lib/api.ts tests/e2e/connector-guided-setup.spec.ts clean
packages/frontend npx playwright test tests/e2e/connector-guided-setup.spec.ts not run locally: next dev did not start in this worktree (missing .next build manifest); left to CI
root node scripts/validate-adapters.mjs exit 0 (existing non-blocking warnings only)
root node --test scripts/validate-adapters.test.mjs scripts/adapter-new.test.mjs scripts/generate-llms-txt.test.mjs passed
root node --test scripts/satellites/satellites.test.mjs passed
root node scripts/adapter-count.mjs --check OK
root node scripts/generate-llms-txt.mjs --check passed
root node scripts/regenerate-catalog.mjs no diff

No ee/ change.

A user in several workspaces who picks an empty one on "Choose what to
connect" now gets the first-connector page for that workspace, and the
page (and POST /auth/first-app) use the workspace granted to the client
instead of the user's primary organization. The Etsy app-pending panel
no longer claims the app is unapproved: Etsy answers the same 403 for a
wrong shared secret of an active app.
@helpcodeai
helpcodeai enabled auto-merge (squash) November 2, 2026 12:51
@helpcodeai
helpcodeai merged commit 0229e46 into main Nov 2, 2026
14 checks passed
@helpcodeai
helpcodeai deleted the fix/post-approve-picker-workspace branch November 2, 2026 13:10
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant