Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions apps/desktop/renderer-architecture.json
Original file line number Diff line number Diff line change
Expand Up @@ -3676,9 +3676,7 @@
"window.maka.githubCopilotSubscription.logout": 1,
"window.maka.githubCopilotSubscription.refreshTokens": 1,
"window.maka.openAiCodex": 1,
"window.maka.openAiCodex.getAccountState": 1,
"window.maka.xaiOAuth": 1,
"window.maka.xaiOAuth.getAccountState": 1
"window.maka.xaiOAuth": 1
},
"environmentCapabilities": {},
"hookCalls": {
Expand Down Expand Up @@ -3985,9 +3983,7 @@
"window.maka.connections.test": 1,
"window.maka.connections.update": 1
},
"environmentCapabilities": {
"window": 2
},
"environmentCapabilities": {},
"hookCalls": {},
"lifecycleMethods": {},
"unresolvedDependencies": 0,
Expand Down
11 changes: 6 additions & 5 deletions apps/desktop/src/main/__tests__/provider-add-submission.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
PROVIDER_DEFAULTS,
providerSupportsModelDiscovery,
type CreateConnectionInput,
type LlmConnection,
type IdentifiedLlmConnection,
type ProviderType,
} from '@maka/core/llm-connections';

Expand All @@ -53,21 +53,22 @@ function draft(over: Partial<AddProviderDraft> = {}): AddProviderDraft {
};
}

function connection(slug: string): LlmConnection {
function connection(slug: string): IdentifiedLlmConnection {
return {
connectionId: `connection-${slug}`,
slug,
name: slug,
providerType: 'openai-compatible',
defaultModel: '',
enabled: true,
createdAt: 0,
updatedAt: 0,
} as LlmConnection;
} as IdentifiedLlmConnection;
}

function bridge(over: {
create?: (input: CreateConnectionInput) => Promise<LlmConnection>;
fetchModels?: (slug: string) => Promise<unknown>;
create?: (input: CreateConnectionInput) => Promise<IdentifiedLlmConnection>;
fetchModels?: (connection: { readonly connectionId: string; readonly slug: string }) => Promise<unknown>;
}) {
return {
create: over.create ?? (async (input) => connection(input.slug)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ test('retries connection delete after a stale revision instead of failing perman
emitConnectionListChanged() {},
});

await handlers.get('connections:delete')?.({}, 'openrouter');
await handlers.get('connections:delete')?.({}, connectionIdentity());
assert.equal(removals, 2);
});

Expand Down Expand Up @@ -123,12 +123,41 @@ test('treats a missing connection as a successful delete without calling remove'
},
});

await handlers.get('connections:delete')?.({}, 'already-gone');
await handlers.get('connections:delete')?.({}, {
connectionId: 'already-gone',
slug: 'already-gone',
});
assert.equal(removals, 0);
assert.equal(listChanged, 1);
});

test('rejects invalid connection slug input instead of treating it as already deleted', async () => {
test('does not delete a replacement Connection that reused the stale detail slug', async () => {
const handlers = new Map<string, (...args: unknown[]) => unknown>();
let removals = 0;
registerRuntimeHostConnectionsIpc({
ipcMain: {
handle: (channel, handler) => {
handlers.set(channel, handler as (...args: unknown[]) => unknown);
},
},
client: {
loadConnectionCatalog: async (): Promise<ConnectionCatalogSnapshot> => ({
...catalog(),
connections: [{ ...catalog().connections[0]!, connectionId: 'connection-2' }],
}),
removeConnection: async () => {
removals += 1;
return { kind: 'committed', catalogRevision: 8 };
},
} as never,
emitConnectionListChanged() {},
});

await handlers.get('connections:delete')?.({}, connectionIdentity());
assert.equal(removals, 0);
});

test('rejects invalid connection identity input instead of treating it as already deleted', async () => {
const handlers = new Map<string, (...args: unknown[]) => unknown>();
registerRuntimeHostConnectionsIpc({
ipcMain: {
Expand All @@ -149,7 +178,7 @@ test('rejects invalid connection slug input instead of treating it as already de

await assert.rejects(
async () => handlers.get('connections:delete')?.({}, 42),
/Invalid connection slug|connection slug/i,
/Invalid Connection identity/i,
);
});

Expand All @@ -176,7 +205,7 @@ test('reports an existing but unconfigured credential as missing', async () => {
});

assert.equal(
await handlers.get('connections:hasSecret')?.({}, 'openrouter'),
await handlers.get('connections:hasSecret')?.({}, connectionIdentity()),
false,
);
});
Expand Down Expand Up @@ -205,16 +234,16 @@ test('keeps saved custom header values out of the renderer and preserves them by
});

assert.deepEqual(
await handlers.get('connections:getRequestHeaders')?.({}, 'openrouter'),
await handlers.get('connections:getRequestHeaders')?.({}, connectionIdentity()),
{ names: ['HTTP-Referer'] },
);
assert.equal(
JSON.stringify(await handlers.get('connections:getRequestHeaders')?.({}, 'openrouter')).includes('private.example'),
JSON.stringify(await handlers.get('connections:getRequestHeaders')?.({}, connectionIdentity())).includes('private.example'),
false,
);

assert.deepEqual(
await handlers.get('connections:setRequestHeaders')?.({}, 'openrouter', [
await handlers.get('connections:setRequestHeaders')?.({}, connectionIdentity(), [
{ name: 'HTTP-Referer' },
{ name: 'X-Title', value: 'Maka' },
]),
Expand Down Expand Up @@ -371,3 +400,7 @@ function catalog(): ConnectionCatalogSnapshot {
],
};
}

function connectionIdentity() {
return { connectionId: 'connection-1', slug: 'openrouter' } as const;
}
99 changes: 74 additions & 25 deletions apps/desktop/src/main/__tests__/runtime-host-oauth-ipc-main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,18 @@ test('adapts every Host OAuth provider through one Desktop flow', async () => {
const authorization = await invoke(
handlers,
'openai-codex:get-auth-url',
catalog.connections[0]?.connectionId,
{ kind: 'existing', connectionId: catalog.connections[0]?.connectionId },
);
assert.deepEqual(authorization, { authRequestId: attemptId, stateHint: 'STATE-HINT' });
const expectedConnection = {
connectionId: catalog.connections[0]?.connectionId,
slug: 'openai-codex',
providerType: provider,
};
assert.deepEqual(authorization, {
authRequestId: attemptId,
stateHint: 'STATE-HINT',
connection: expectedConnection,
});
assert.deepEqual(opened, ['https://codex.example/authorize']);
assert.deepEqual(
await invoke(
Expand All @@ -178,7 +187,7 @@ test('adapts every Host OAuth provider through one Desktop flow', async () => {
attemptId,
'authorization-code#state',
),
{ ok: true },
{ ok: true, connection: expectedConnection },
);
assert.equal(changed, 1);
assert.deepEqual(catalog.defaultTarget, {
Expand All @@ -187,7 +196,11 @@ test('adapts every Host OAuth provider through one Desktop flow', async () => {
});
// No quota: reporting it required the retired provider's own client identity,
// so the account state carries the runtime state alone.
assert.deepEqual(await invoke(handlers, 'openai-codex:get-account-state'), {
assert.deepEqual(await invoke(
handlers,
'openai-codex:get-account-state',
catalog.connections[0]?.connectionId,
), {
provider,
runtimeState: 'authenticated',
});
Expand Down Expand Up @@ -231,7 +244,10 @@ test('provider-scoped OAuth IPC rejects a Connection ID owned by another provide
});

assert.deepEqual(
await invoke(handlers, 'openai-codex:get-auth-url', xaiConnection.connectionId),
await invoke(handlers, 'openai-codex:get-auth-url', {
kind: 'existing',
connectionId: xaiConnection.connectionId,
}),
{
ok: false,
reason: 'unknown',
Expand All @@ -240,14 +256,18 @@ test('provider-scoped OAuth IPC rejects a Connection ID owned by another provide
);
assert.deepEqual(
await invoke(handlers, 'openai-codex:get-account-state', xaiConnection.connectionId),
{ provider: 'openai-codex', runtimeState: 'not_logged_in' },
{
ok: false,
reason: 'unknown',
message: 'OAuth account does not match this provider',
},
);
assert.deepEqual(
await invoke(handlers, 'openai-codex:refresh-tokens', xaiConnection.connectionId),
{
ok: false,
reason: 'refresh_failed',
message: 'OAuth account is not connected',
message: 'OAuth account does not match this provider',
},
);
assert.deepEqual(await invoke(handlers, 'openai-codex:logout', xaiConnection.connectionId), {
Expand All @@ -271,7 +291,13 @@ test('malformed OAuth Connection IDs fail closed before catalog or credential ac
isProviderEnabled: () => true,
});

for (const malformed of [null, 7, {}]) {
for (const malformed of [
null,
7,
{},
{ kind: 'create', connectionId: '00000000-0000-4000-8000-000000000001' },
{ kind: 'existing', connectionId: '00000000-0000-4000-8000-000000000001', extra: true },
]) {
assert.deepEqual(await invoke(handlers, 'openai-codex:get-auth-url', malformed), {
ok: false,
reason: 'unknown',
Expand Down Expand Up @@ -395,9 +421,9 @@ test('a second OAuth start cannot replace or cancel a pending active attempt', a
isProviderEnabled: () => true,
});

const firstAuthorization = invoke(handlers, 'openai-codex:get-auth-url');
const firstAuthorization = invoke(handlers, 'openai-codex:get-auth-url', { kind: 'create' });
await firstPresentationPoll;
assert.deepEqual(await invoke(handlers, 'openai-codex:get-auth-url'), {
assert.deepEqual(await invoke(handlers, 'openai-codex:get-auth-url', { kind: 'create' }), {
ok: false,
reason: 'unknown',
message: 'Another OAuth login is already in progress',
Expand All @@ -413,6 +439,11 @@ test('a second OAuth start cannot replace or cancel a pending active attempt', a
assert.deepEqual(await firstAuthorization, {
authRequestId: firstAttemptId,
stateHint: 'FIRST',
connection: {
connectionId,
slug: 'openai-codex',
providerType: provider,
},
});
assert.deepEqual(
await invoke(handlers, 'openai-codex:logout', foreignConnection.connectionId),
Expand All @@ -425,7 +456,7 @@ test('a second OAuth start cannot replace or cancel a pending active attempt', a
assert.deepEqual(await invoke(handlers, 'openai-codex:logout'), {
ok: false,
reason: 'unknown',
message: 'Select a specific OAuth account to log out',
message: 'Invalid OAuth Connection identity',
});
assert.equal(cancels, 0);
assert.deepEqual(
Expand All @@ -435,7 +466,14 @@ test('a second OAuth start cannot replace or cancel a pending active attempt', a
assert.equal(cancels, 0);
assert.deepEqual(
await invoke(handlers, 'openai-codex:complete-authorization', firstAttemptId),
{ ok: true },
{
ok: true,
connection: {
connectionId,
slug: 'openai-codex',
providerType: provider,
},
},
);
assert.equal(cancels, 0);
assertNoUnexpectedClientCalls();
Expand Down Expand Up @@ -475,7 +513,7 @@ test('completion rejects a terminal projection that changes Connection identity'
isProviderEnabled: () => true,
});

await invoke(handlers, 'openai-codex:get-auth-url');
await invoke(handlers, 'openai-codex:get-auth-url', { kind: 'create' });
assert.deepEqual(await invoke(handlers, 'openai-codex:complete-authorization', attemptId), {
ok: false,
reason: 'unknown',
Expand All @@ -486,7 +524,7 @@ test('completion rejects a terminal projection that changes Connection identity'
assertNoUnexpectedClientCalls();
});

test('keeps a committed OAuth login successful when model discovery fails', async () => {
test('keeps a committed OAuth login successful when model discovery fails without replacing the existing default', async () => {
const provider = 'openai-codex' as const;
const modelId = PROVIDER_DEFAULTS[provider].fallbackModels[0];
assert.ok(modelId);
Expand All @@ -507,7 +545,7 @@ test('keeps a committed OAuth login successful when model discovery fails', asyn
};
let catalog: ConnectionCatalogSnapshot = {
revision: 1,
defaultTarget: null,
defaultTarget: { connectionId: existing.connectionId, modelId },
connections: [existing],
};
const presentation = new RuntimeHostOAuthPresentation(async () => undefined);
Expand Down Expand Up @@ -550,11 +588,6 @@ test('keeps a committed OAuth login successful when model discovery fails', asyn
fetchedConnectionIds.push(connectionId);
throw new Error('provider temporarily unavailable');
},
setDefaultConnectionTarget: async (expectedCatalogRevision, target) => {
assert.equal(expectedCatalogRevision, catalog.revision);
catalog = { ...catalog, revision: catalog.revision + 1, defaultTarget: target };
return { kind: 'committed' as const, catalogRevision: catalog.revision };
},
queryCredential: async (locator) =>
locator.scope === 'connection' && locator.connectionId === created.connectionId
? {
Expand All @@ -575,18 +608,34 @@ test('keeps a committed OAuth login successful when model discovery fails', asyn
isProviderEnabled: () => true,
});

assert.deepEqual(await invoke(handlers, 'openai-codex:get-auth-url'), {
assert.deepEqual(await invoke(handlers, 'openai-codex:get-auth-url', { kind: 'create' }), {
authRequestId: attemptId,
stateHint: 'DEVICE-CODE',
connection: {
connectionId: created.connectionId,
slug: created.slug,
providerType: provider,
},
});
assert.deepEqual(
await invoke(handlers, 'openai-codex:complete-authorization', attemptId, undefined),
{ ok: true },
{
ok: true,
connection: {
connectionId: created.connectionId,
slug: created.slug,
providerType: provider,
},
},
);
assert.equal(changed, 1);
assert.deepEqual(fetchedConnectionIds, [created.connectionId]);
assert.deepEqual(catalog.defaultTarget, { connectionId: created.connectionId, modelId });
assert.deepEqual(await invoke(handlers, 'openai-codex:get-account-state'), {
assert.deepEqual(catalog.defaultTarget, { connectionId: existing.connectionId, modelId });
assert.deepEqual(await invoke(
handlers,
'openai-codex:get-account-state',
created.connectionId,
), {
provider,
runtimeState: 'authenticated',
});
Expand Down Expand Up @@ -655,7 +704,7 @@ function oauthProjection(
attemptId,
connection: {
connectionId,
slug: 'codex-subscription',
slug: 'openai-codex',
providerType: 'openai-codex' as const,
},
phase,
Expand Down
Loading