fix: skip auth requirement for config-defined custom providers

Shows the auth panel only when provider credentials are actually required
Keeps custom providers defined in config from being treated as incomplete
Adds coverage for the new provider auth check
This commit is contained in:
Bohdan Triapitsyn
2026-08-19 10:24:35 +03:00
parent ef2afdc759
commit 13a45aa5a5
3 changed files with 24 additions and 5 deletions
@@ -1,5 +1,5 @@
import { describe, expect, test } from 'bun:test'; import { describe, expect, test } from 'bun:test';
import { shouldLoadAvailableProviders } from './providerAvailability'; import { requiresProviderAuth, shouldLoadAvailableProviders } from './providerAvailability';
import { import {
getOAuthAuthMethods, getOAuthAuthMethods,
normalizeAuthType, normalizeAuthType,
@@ -15,6 +15,14 @@ describe('ProvidersPage available provider loading', () => {
}); });
}); });
describe('ProvidersPage provider authentication', () => {
test('does not require credentials for a custom provider defined in config', () => {
expect(requiresProviderAuth(true, false, true)).toBe(false);
expect(requiresProviderAuth(true, false, false)).toBe(true);
expect(requiresProviderAuth(true, true, false)).toBe(false);
});
});
describe('provider auth method helpers', () => { describe('provider auth method helpers', () => {
test('normalizeAuthType recognizes oauth and api labels', () => { test('normalizeAuthType recognizes oauth and api labels', () => {
expect(normalizeAuthType({ type: 'oauth', label: 'Login with Cursor' })).toBe('oauth'); expect(normalizeAuthType({ type: 'oauth', label: 'Login with Cursor' })).toBe('oauth');
@@ -23,7 +23,7 @@ import type { ModelMetadata } from '@/types';
import { getCurrentIntlLocale, useI18n } from '@/lib/i18n'; import { getCurrentIntlLocale, useI18n } from '@/lib/i18n';
import { runtimeFetch } from '@/lib/runtime-fetch'; import { runtimeFetch } from '@/lib/runtime-fetch';
import { opencodeClient } from '@/lib/opencode/client'; import { opencodeClient } from '@/lib/opencode/client';
import { shouldLoadAvailableProviders } from './providerAvailability'; import { requiresProviderAuth, shouldLoadAvailableProviders } from './providerAvailability';
import { import {
getOAuthAuthMethods, getOAuthAuthMethods,
parseAuthPayload, parseAuthPayload,
@@ -324,7 +324,8 @@ export const ProvidersPage: React.FC = () => {
? provider.env.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0) ? provider.env.filter((entry): entry is string => typeof entry === 'string' && entry.trim().length > 0)
: []; : [];
const hasCreds = Boolean(sources.auth.exists) || envEntries.length > 0; const hasCreds = Boolean(sources.auth.exists) || envEntries.length > 0;
if (!hasCreds) { const isCustomProvider = Boolean(provider && isConfigDefinedCustomProvider(provider, sources));
if (requiresProviderAuth(true, hasCreds, isCustomProvider)) {
setShowAuthPanel(true); setShowAuthPanel(true);
} }
}, [selectedProviderId, providerSources, providers]); }, [selectedProviderId, providerSources, providers]);
@@ -773,8 +774,12 @@ export const ProvidersPage: React.FC = () => {
const hasStoredAuth = Boolean(selectedSources?.auth.exists); const hasStoredAuth = Boolean(selectedSources?.auth.exists);
const hasEnvCredentials = providerEnv.length > 0; const hasEnvCredentials = providerEnv.length > 0;
const hasCredentials = hasStoredAuth || hasEnvCredentials; const hasCredentials = hasStoredAuth || hasEnvCredentials;
const authStatusIncomplete = sourcesLoaded && !hasCredentials; const authStatusIncomplete = requiresProviderAuth(
const showModelsSection = providerModels.length > 0 && (!sourcesLoaded || hasCredentials); sourcesLoaded,
hasCredentials,
isEditableCustomProvider,
);
const showModelsSection = providerModels.length > 0 && !authStatusIncomplete;
const incompleteAuthHint = !showApiKeyAuth && oauthAuthMethods.length > 0 const incompleteAuthHint = !showApiKeyAuth && oauthAuthMethods.length > 0
? t('settings.providers.page.auth.useReconnectHint') ? t('settings.providers.page.auth.useReconnectHint')
: t('settings.providers.page.auth.incompleteHint'); : t('settings.providers.page.auth.incompleteHint');
@@ -1 +1,7 @@
export const shouldLoadAvailableProviders = (isAddMode: boolean): boolean => isAddMode; export const shouldLoadAvailableProviders = (isAddMode: boolean): boolean => isAddMode;
export const requiresProviderAuth = (
sourcesLoaded: boolean,
hasCredentials: boolean,
isConfigDefinedCustomProvider: boolean,
): boolean => sourcesLoaded && !hasCredentials && !isConfigDefinedCustomProvider;