Repository navigation
fix(cli): route the copilot device flow through the github backend key and the real poll route (#14298) - #14300
Conversation
…y and the real poll route
|
Excellent repro-driven fix — the fake-server test proving the old code would 404-loop even after a successful user authorization is exactly the right way to nail this down. Since issue #14298 also covers the Gemini/codex/kiro and Windows-baseline findings that this PR doesn't touch, I'll link it with |
|
I will take findings 4 and 5 as the follow-up against release/v3.8.51. For finding 5, the plan is: give codex a callback-server PKCE path in the CLI (GET start-callback-server, then poll POST poll-callback, the same routes the dashboard uses) instead of the device label that 404s, and fix kiro social to GET social-authorize and then poll POST social-exchange with deviceCode + provider, replacing the POST/GET pair that gets 405 today. A fake-server test that only mounts the real routes will pin both, and it fails on the current code. For finding 4 (gemini), the CLI entry cannot work until either the server registers a gemini provider or the entry is dropped from the list. Tell me which direction you prefer and I will fold it into the same PR, or leave it out if you want to decide later. Findings 6 and 7 are upstream/entitlement as you triaged, so I will not touch them. |
|
Thanks @xiechimon — merging via the release merge-train. Validated in local merge-train (mt-train10c) on the devbox @ train tip 4d841aa1c740bbaa03868dc0a403c62099a99a42 with the 72 sibling PRs of this batch: typecheck:core, file-size, complexity, cognitive-complexity, changelog-integrity green; changed-area node:test 831/831 (0 failing) and vitest 480/482 — the two reds are |
844e35c
into
diegosouzapw:release/v3.8.51
…kiro social routes
- codex is authorization_code_pkce on the server, so the device-code
action rejects it (404). Drive it through start-callback-server +
poll-callback like the dashboard does, with a manual browser-PKCE
fallback when the callback server is unavailable.
- kiro social-authorize is GET-only and social-exchange is POST-only;
the CLI had both methods inverted and polled by a state the response
never carries. Use GET social-authorize (provider query) and POST
social-exchange {deviceCode, provider} with slow_down backoff,
mirroring KiroSocialOAuthModal.
Refs diegosouzapw#14298 findings 4-5 (gemini registry entry left for a maintainer
call, see PR discussion on diegosouzapw#14300).
What
Fixes the broken CLI device-flow onboarding for GitHub Copilot (issue #14298, findings 1-3).
Three changes in
bin/cli/commands/oauth.mjs, all inside the CLI device-flow path:Add the
copilot->githubentry toBACKEND_OAUTH_KEY. The server registers the GitHub device flow under the keygithub(src/lib/oauth/providers/index.ts), sooauth start --provider copilotused to post/api/oauth/copilot/device-codeand fail with an unknown-provider error. Same class of mismap as theclaude-code->claudealias fixed in Claude Code OAuth device flow (oauth start --provider claude-code) fails with 401 — internally mapped to unrelatedcommand-codeprovider instead of Anthropic #9474.Poll the route that actually exists.
runDeviceFlowused to pollGET /api/providers/{key}/auth/status?state=...and thenPOST /api/providers/{key}/auth/apply. Neither route exists on the server, so the CLI looped until its timeout even after the user had authorized (GitHub already showed the device as connected). It now pollsPOST /api/oauth/{key}/pollwith{ deviceCode }, which is the same route the dashboard uses (src/shared/components/OAuthModal.tsx::pollDeviceCodeOnce). That route persists the connection server-side on success, so the separate apply step is not needed.codeVerifieris forwarded when the device-code response carries one, matching the server'soauthPollSchema.Stop keying the poll on
start.state.GET /api/oauth/{key}/device-codenever returns astatefield, so the old?state=query could never match a pending flow. The poll now uses the device code from the response (deviceCode/device_code), and exits with a clear message if the server returned none.Also mirrors the dashboard's handling of poll results:
slow_downbacks the interval off by 5s per the device-flow spec, and a non-pending error reportserrorDescriptionand exits 1 instead of looping silently until timeout.Why
Without this,
omniroute oauth start --provider copilotcould not complete at all from the CLI on any platform (the reporter hit it on Windows; the mismap and the dead poll route are platform-independent). The direct API sequence the reporter found (GET /api/oauth/github/device-code-> authorize ->POST /api/oauth/github/poll) is exactly what the CLI now does.How tested
New regression test
tests/unit/14298-cli-copilot-device-flow.test.tsdrivesrunOAuthStartagainst a fake HTTP server that only mounts the routes the real server exposes:githubkey, no request targets/copilot/or/api/providers/, poll carriesdeviceCode+codeVerifier;Red/green verified: with the base
oauth.mjsrestored, both tests fail (Failed to start device flow: 404/ timeout loop); with the fix, both pass.Adjacent regression:
cli-oauth-commands,9474-claude-code-oauth-mismap,probe-12413-antigravity-oauth-redirect-hint,grok-cli-oauth,grok-cli-device-route,oauth-device-code-endpointsall pass (42 tests, 0 failures).prettier --checkclean on both files,eslintclean,typecheck:coreexit 0.Scope note
#14298 lists seven findings. This PR covers 1-3 (the CLI device-flow path). Findings 4-7 (gemini registry entry, codex/kiro flows, github/* catalog mapping, baseline binary) touch different code paths and are left to separate changes.
Fixes #14298 (findings 1-3)