Skip to content

feat(console): ask for the installer's OAuth client on Connect for a clientSource installer connector - #29496

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-80b6qg
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-80b6qg

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Part of #28869

Clause-②: yes
Metadata-protocol: none

PR 1 of 2 on the card, per the seat's claim amendment (6581522588, option B): items 1, 3, 4 and 5. Item 2, the redirect URI with a copy button, is PR 2 on this card once the server half #29463 lands, because no answer the Console reads carries the redirect URI today (stop report 6581473243).

维护者速读

新增语言键(connectorConnections 下 12 个,十种语言全部补齐):clientKeptWithSecret、clientKept、clientTitle、clientIntro、clientStored、clientStoredSecret、clientStoredNoSecret、clientResend、clientId、clientSecret、clientSecretHint、clientContinue。

What changes

  • connectorConnections.ts: readConnectableInstances marks an instance whose declaration (GET /meta/connector) says auth.clientSource: 'installer'. beginConnection(name, client?) sends { clientId, clientSecret? } as a JSON body for such an instance and no body otherwise, exactly as before.
  • ConnectorConnectionsPage.tsx: Connect / Reconnect on an installer-client instance opens a form (client ID; masked client secret with autocomplete=new-password) before any window opens or anything is sent. Continue opens the sign-in window on that click and begins with the client. The secret is cleared from the form state before the begin is awaited; a refused begin keeps the form open with the server's words and an empty secret. A connected row shows the kept client from client { clientId, hasSecret } on the status. Reconnect shows the stored client ID and whether a secret is kept, prefills the ID, leaves the secret empty and sends the client again: today's server refuses a client-less begin of such an instance on every begin, reconnect included (installerClientOfBegin). The client-less reconnect that reuses the stored client is ask 2 of connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463; PR 2 switches to it. Every other instance (a declared client, an MCP dynamically registered client) connects at once with no form and no body.
  • No redirect URI is shown, guessed or parsed from prose. The form says the Connectors documentation describes the redirect URI to register.
  • @object-ui/i18n: the twelve keys above in all ten locales (the all-locales parity suite requires every pack, so the card's four became ten).
  • Changeset .changeset/28869-installer-oauth-client-form.md (@object-ui/app-shell, @object-ui/i18n: patch).

Tests

New describe('an installer-supplied OAuth client') in ConnectorConnectionsPage.test.tsx, six cases: the form appears before any window or POST and the begin carries { clientId, clientSecret } (id trimmed); a public client sends only { clientId }; a refused begin keeps the form with the server's words and an empty secret; a reconnect shows the stored client, prefills the id, starts with an empty secret and sends the client again (today's server behaviour, pinned); Cancel sends nothing and the next opening has an empty secret; no other instance shows the form and its begin has no body. Every case that types the secret asserts it is absent from document.body.innerHTML afterwards.

Acceptance notes

Verification

Page suite, ablations (head bc8ea24, re-run on merge 4a4fe17)
  • pnpm exec vitest run packages/app-shell/src/views/setup/ConnectorConnectionsPage.test.tsx (from ui/, under os-verify-lock): 17 passed (11 existing + 6 new). On merge head 4a4fe17 with packages/i18n/: Test Files 96 passed, Tests 1460 passed, 13 skipped.
  • Ablation A1 (via scripts/ablation-replace.mjs, restored blob == HEAD, git diff HEAD empty): the installer gate in startConnect dropped, so every instance gets the form: 6 failed / 11 passed, the "no other instance shows the form" pin among them.
  • Ablation A2: readConnectableInstances never marks clientSource: 'installer': 5 failed / 12 passed (every installer case).
  • Ablation A3: the secret not cleared when the begin is sent: 1 failed / 16 passed ("a refused begin keeps the form open ..., and the secret is gone from it").
  • ui vitest aliases @object-ui/* to source, so no rebuild leg was owed.
Packages and gates (head bc8ea24)
  • pnpm exec vitest run packages/i18n/ (under the lock): Test Files 95 passed, Tests 1443 passed, 13 skipped.
  • turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n: 66 tasks successful, VERDICT command-exit 0.
  • pnpm --dir ui exec vitest run scripts/: Test Files 169 passed, 2 skipped; Tests 4921 passed.
  • node scripts/check-sdui-manifest.mjs: exit 0 (no registry change).
  • dispatch-gates --commands: 34 families, every one exit 0; --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN.
Live run (app-crm, Vite source Console)

objectstack dev --seed-admin --fresh on app-crm with OS_BASE_URL set to the Console origin, the Vite Console proxying to it, a local stub for the vendor's authorize/token endpoints, and an installer connector saved through PUT /meta/connector/vendor_docs (clientSource: 'installer', the dogfood fixture's shape). In Playwright: Connect opened the client form; Continue sent POST .../vendor_docs/connection with body keys clientId, clientSecret; the stub saw the authorize request with that client id and the token request authenticated as that client; the page showed Connected and "OAuth client live-installer-client, secret stored"; the status read answered client: { source: 'installer', clientId: 'live-installer-client', hasSecret: true }. Reconnect opened the form with the id prefilled and the secret empty. The typed secret was absent from the page's HTML after the connect and in the reconnect form. Screenshots of the Connect step, the connected row and the Reconnect step were handed to the seat.


Generated by Claude Code

An oauth2 connector instance declaring clientSource: 'installer' now opens a
client form on Connect / Reconnect: client id and a masked, write-only client
secret. The begin POST carries { clientId, clientSecret }; a reconnect shows
the stored client id and whether a secret is kept, prefills the id and sends
the client again. Every other instance connects with no form, as before.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jQhfprmgNtfhzNURJ6
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tooling labels Nov 2, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

席位核对 · ACCEPT · 2026-11-02T16:49Z

Head-sha: 4a4fe1747e7c4e1d668d97eaa7485fc2c99b5bb3

  • Shape: draft → main, PR 1 of 2 on console: the connector connection form asks the administrator for the OAuth client (client id + secret) when the instance takes an installer-supplied client (#28702 B, ui slice) #28869: Part of #28869 in the body, no closing keyword, so the card stays open for PR 2. 14 files, +503 / −16 (519 lines ≤ 3000). No governed path: check-governed-merges --pr 29496 reports NOT governed. Clause-②: yes and Metadata-protocol: none are line-initial in the body and the changeset, as claimed (6581428199, amended 6581522588). The changeset is patch for @object-ui/app-shell and @object-ui/i18n.
  • Contract review (seat's own, Clause-②: yes): PASS. The public widening is twelve new connectorConnections.* locale keys (listed in 维护者速读), in all ten locales for the parity suite. ConnectableInstance.installerClient and InstallerClientInput are types of the private app-shell. No metadata key: the form follows the declaration's existing auth.clientSource, so Metadata-protocol: none holds. The begin body matches PR feat(automation): an oauth2 connector with clientSource: 'installer' connects with the administrator's OAuth client #29097's { clientId, clientSecret? }.
  • File surface: inside the claim: ConnectorConnectionsPage.tsx, connectorConnections.ts, the page test, the ten locales, the changeset.
  • Read in the diff: readConnectableInstances marks an oauth2 authorization_code instance installerClient only when auth.clientSource === 'installer'; every other instance connects as before with no form. For an installer instance Connect / Reconnect opens a dialog (client id, masked secret with autocomplete=new-password). Submit trims the id, clears the secret from state before anything is awaited, and connect still opens the sign-in window synchronously inside the submit gesture; a refusal closes the window and shows the server's words in the dialog (rendered, not parsed). A reconnect pre-fills the stored client.clientId, says whether a secret is kept (hasSecret), starts with an empty secret and re-sends the client (today's server refuses a client-less begin; ask 2 of connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463 adds reuse). The row shows the kept client id and whether a secret is stored, never a secret. No redirect URI is shown or guessed; the intro points to the Connectors docs (item 2 waits on connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463, option C refused).
  • Tests (dev): page suite 17 / 17 (6 new); i18n 95 files; ui scripts/ 169 files; type-check 66 tasks. Ablations A1 (gate dropped: 6 red incl. the no-form pin), A2 (reader never marks installer: 5 red), A3 (secret not cleared: 1 red), each restored to HEAD. Derived gates 34 of 34, --ran reconciled; body gates exit 0.
  • Measured (dev): live on app-crm + Vite Console + a vendor stub: a full installer-client connect (POST body carried clientId + clientSecret, the token leg authenticated as that client, the row showed the kept client), and a Reconnect with the id pre-filled and the secret empty. Shots: /mnt/project-files/issue-28869/live-*.png.
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending. mergeable_state is clean.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. The card stays open (pm:dispatched, this seat) for PR 2: the redirect URI with a copy button and "keep the stored client unless replaced", Blocked-by connector connection state: answer the derived OAuth redirect URI so the Console can show it before an installer registers a client #29463.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 16:50
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit c88467d Nov 2, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-80b6qg branch November 2, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant