fix: route Cursor auth through browser polling

Closes #1194
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-05-07 11:25:17 -04:00
1 parent a95266e4cc
commit 8b681df455
12 files changed
+152 -25

No files matched your search

+7
View File
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'bun:test';
import {
getDeviceCodeProviderInstruction,
getProviderDisplayName,
isDeviceCodeProvider,
} from '../../../ui/src/lib/provider-config';
describe('provider-config fallbacks', () => {
@@ -15,4 +16,10 @@ describe('provider-config fallbacks', () => {
'Complete the authorization in your browser.'
);
});
it('does not classify Cursor browser URL auth as a verification-code device flow', () => {
expect(isDeviceCodeProvider('cursor')).toBe(false);
expect(isDeviceCodeProvider('ghcp')).toBe(true);
expect(isDeviceCodeProvider('qwen')).toBe(true);
});
});
@@ -11,7 +11,7 @@ import {
getCachedQuota,
setCachedQuota,
} from '../../../src/cliproxy/quota/quota-response-cache';
import { restoreFetch, mockFetch } from '../../mocks';
import { restoreFetch, mockFetch, getCapturedFetchRequests } from '../../mocks';
describe('cliproxy-auth-routes manual callback nickname persistence', () => {
let server: Server;
@@ -179,6 +179,34 @@ describe('cliproxy-auth-routes manual callback nickname persistence', () => {
expect(registry.providers.kiro.accounts['github-ABC123']?.nickname).toBe('work');
});
it('starts Cursor auth through the browser URL management endpoint', async () => {
mockFetch([
{
url: /\/v0\/management\/cursor-auth-url\?is_webui=true$/,
response: {
url: 'https://cursor.com/loginDeepControl?state=cursor-state',
state: 'cursor-state',
},
},
]);
const startResponse = await postJson('/api/cliproxy/auth/cursor/start-url', {
nickname: 'work',
});
expect(startResponse.status).toBe(200);
expect(startResponse.body).toEqual({
success: true,
authUrl: 'https://cursor.com/loginDeepControl?state=cursor-state',
state: 'cursor-state',
method: null,
});
const requests = getCapturedFetchRequests();
expect(requests).toHaveLength(1);
expect(requests[0]?.url).toContain('/v0/management/cursor-auth-url?is_webui=true');
});
it('returns wait after callback submission when the local token is not yet available', async () => {
mockFetch([
{
@@ -13,15 +13,14 @@ describe('cliproxy-auth-routes start-url guard', () => {
);
expect(getStartUrlUnsupportedReason('ghcp')).toContain("Provider 'ghcp' uses Device Code flow");
expect(getStartUrlUnsupportedReason('qwen')).toContain("Provider 'qwen' uses Device Code flow");
expect(getStartUrlUnsupportedReason('cursor')).toContain(
"Provider 'cursor' uses Device Code flow"
);
expect(getStartUrlUnsupportedReason('codebuddy')).toContain(
"Provider 'codebuddy' uses Device Code flow"
);
expect(getStartUrlUnsupportedReason('kilo')).toContain(
"Provider 'kilo' uses Device Code flow"
);
expect(getStartUrlUnsupportedReason('kilo')).toContain("Provider 'kilo' uses Device Code flow");
});
it('allows Cursor browser URL auth on start-url', () => {
expect(getStartUrlUnsupportedReason('cursor')).toBeNull();
});
it('allows Kiro social methods on start-url', () => {
@@ -138,6 +137,8 @@ describe('cliproxy-auth-routes nickname validation', () => {
];
expect(getStartAuthNicknameError('kiro', 'work', existingAccounts, 'github-ABC123')).toBeNull();
expect(getStartAuthNicknameError('kiro', 'github-ABC123', existingAccounts, 'github-ABC123')).toBeNull();
expect(
getStartAuthNicknameError('kiro', 'github-ABC123', existingAccounts, 'github-ABC123')
).toBeNull();
});
});