mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-06 12:50:54 -04:00
fix(requesty): apply the dedicated proxy and placeholder guards to Requesty
A saved Requesty proxy profile carries the requesty route id, but buildLaunchEnv's noncanonical-launch list and buildStartupEnvFromProfile's retained-proxy guard did not include Requesty. Ambient OPENAI_API_KEY, OPENAI_API_KEYS and REQUESTY_API_KEY could reach the proxy on relaunch, and a concrete shell selection skipped the guard entirely. LLMTR, Merge, Command Code and API Route already withhold them. REQUESTY_API_KEY was also missing from the placeholder-aware credential checks in validation, route credential resolution and the picker, so a template value such as SUA_CHAVE counted as usable and beat a real OPENAI_API_KEY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,7 @@ function hasUsableEnvValue(envVar: string, value: string | undefined): boolean {
|
||||
envVar === 'OPENAI_API_KEYS' ||
|
||||
envVar === 'OPENAI_API_KEY' ||
|
||||
envVar === 'LLMTR_API_KEY' ||
|
||||
envVar === 'REQUESTY_API_KEY' ||
|
||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||
envVar === 'CMD_API_KEY' ||
|
||||
envVar === 'COMMANDCODE_API_KEY' ||
|
||||
|
||||
@@ -245,6 +245,7 @@ function hasUsableEnvCredentialValue(
|
||||
envVar === 'APISMART_API_KEY' ||
|
||||
envVar === 'CONCENTRATE_API_KEY' ||
|
||||
envVar === 'LLMTR_API_KEY' ||
|
||||
envVar === 'REQUESTY_API_KEY' ||
|
||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||
envVar === 'CMD_API_KEY' ||
|
||||
envVar === 'COMMANDCODE_API_KEY' ||
|
||||
|
||||
@@ -3990,3 +3990,40 @@ test('a shell URL retarget onto canonical Requesty drops a saved proxy profile c
|
||||
assert.equal(explicit.REQUESTY_API_KEY, 'shell-requesty-key')
|
||||
assert.equal(explicit.OPENAI_API_KEY, undefined)
|
||||
})
|
||||
|
||||
test('a saved Requesty proxy profile withholds ambient credentials on restart', async () => {
|
||||
// The startup file a Requesty proxy profile writes: route identity, its own
|
||||
// URL and its own custom auth, but no saved key.
|
||||
const persisted = profile('openai', {
|
||||
CLAUDE_CODE_PROVIDER_ROUTE_ID: 'requesty',
|
||||
OPENAI_BASE_URL: 'https://requesty-proxy.example/v1',
|
||||
OPENAI_MODEL: 'openai/gpt-5-mini',
|
||||
OPENAI_AUTH_HEADER: 'X-Proxy-Auth',
|
||||
OPENAI_AUTH_SCHEME: 'raw',
|
||||
OPENAI_AUTH_HEADER_VALUE: 'saved-proxy-secret',
|
||||
})
|
||||
const ambient = {
|
||||
OPENAI_API_KEY: 'ambient-requesty-key',
|
||||
OPENAI_API_KEYS: 'ambient-requesty-key',
|
||||
REQUESTY_API_KEY: 'ambient-requesty-key',
|
||||
}
|
||||
|
||||
for (const processEnv of [
|
||||
ambient,
|
||||
// A concrete shell selection must not skip the saved profile's boundary.
|
||||
{
|
||||
...ambient,
|
||||
CLAUDE_CODE_USE_OPENAI: '1',
|
||||
OPENAI_BASE_URL: 'https://requesty-proxy.example/v1',
|
||||
OPENAI_MODEL: 'openai/gpt-5-mini',
|
||||
},
|
||||
]) {
|
||||
const env = await buildStartupEnvFromProfile({ persisted, processEnv })
|
||||
assert.equal(env.OPENAI_BASE_URL, 'https://requesty-proxy.example/v1')
|
||||
assert.equal(env.CLAUDE_CODE_PROVIDER_ROUTE_ID, 'requesty')
|
||||
assert.equal(env.OPENAI_API_KEY, undefined)
|
||||
assert.equal(env.OPENAI_API_KEYS, undefined)
|
||||
assert.equal(env.REQUESTY_API_KEY, undefined)
|
||||
assert.equal(env.OPENAI_AUTH_HEADER_VALUE, 'saved-proxy-secret')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2373,6 +2373,10 @@ export async function buildLaunchEnv(options: {
|
||||
effectiveOpenAIRouteId === 'llmtr' &&
|
||||
!!env.OPENAI_BASE_URL?.trim() &&
|
||||
!isCanonicalLlmtrInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||
const isNoncanonicalRequestyLaunch =
|
||||
effectiveOpenAIRouteId === 'requesty' &&
|
||||
!!env.OPENAI_BASE_URL?.trim() &&
|
||||
!isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||
const isNoncanonicalMergeGatewayLaunch =
|
||||
effectiveOpenAIRouteId === 'merge-gateway' &&
|
||||
!!env.OPENAI_BASE_URL?.trim() &&
|
||||
@@ -2390,6 +2394,7 @@ export async function buildLaunchEnv(options: {
|
||||
isNoncanonicalApismartLaunch ||
|
||||
isNoncanonicalConcentrateLaunch ||
|
||||
isNoncanonicalLlmtrLaunch ||
|
||||
isNoncanonicalRequestyLaunch ||
|
||||
isNoncanonicalMergeGatewayLaunch ||
|
||||
isNoncanonicalCommandcodeLaunch ||
|
||||
isNoncanonicalApiRouteLaunch
|
||||
@@ -2406,6 +2411,7 @@ export async function buildLaunchEnv(options: {
|
||||
} else if (
|
||||
!isNoncanonicalConcentrateLaunch &&
|
||||
!isNoncanonicalLlmtrLaunch &&
|
||||
!isNoncanonicalRequestyLaunch &&
|
||||
!isNoncanonicalMergeGatewayLaunch &&
|
||||
!isNoncanonicalCommandcodeLaunch
|
||||
) {
|
||||
@@ -2889,6 +2895,11 @@ export async function buildStartupEnvFromProfile(options?: {
|
||||
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'llmtr' &&
|
||||
!!persisted.env.OPENAI_BASE_URL?.trim() &&
|
||||
!isCanonicalLlmtrInferenceBaseUrl(persisted.env.OPENAI_BASE_URL)
|
||||
const persistedRequestyProxy =
|
||||
persisted?.profile === 'openai' &&
|
||||
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'requesty' &&
|
||||
!!persisted.env.OPENAI_BASE_URL?.trim() &&
|
||||
!isCanonicalRequestyInferenceBaseUrl(persisted.env.OPENAI_BASE_URL)
|
||||
const persistedMergeGatewayProxy =
|
||||
persisted?.profile === 'openai' &&
|
||||
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' &&
|
||||
@@ -2909,6 +2920,7 @@ export async function buildStartupEnvFromProfile(options?: {
|
||||
!persistedApismartProxy &&
|
||||
!persistedConcentrateProxy &&
|
||||
!persistedLlmtrProxy &&
|
||||
!persistedRequestyProxy &&
|
||||
!persistedMergeGatewayProxy &&
|
||||
!persistedCommandcodeProxy &&
|
||||
!persistedApiRouteProxy
|
||||
|
||||
@@ -618,6 +618,29 @@ test('noncanonical Requesty host paths do not validate a dedicated credential',
|
||||
await expect(getProviderValidationError(process.env)).resolves.toBeNull()
|
||||
})
|
||||
|
||||
test.each([undefined, '', 'undefined', 'null', 'SUA_CHAVE', 'requesty-key'])('Requesty validation, picker and runtime agree on usable dedicated credentials: %s', async key => {
|
||||
const { getProviderPresetUiMetadata } = await import('../integrations/providerUiMetadata.js')
|
||||
const { resolveRouteCredentialValue } = await import('../integrations/routeMetadata.js')
|
||||
const usable = key === 'requesty-key'
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
CLAUDE_CODE_USE_OPENAI: '1', OPENAI_MODEL: 'openai/gpt-5-mini',
|
||||
OPENAI_BASE_URL: 'https://router.requesty.ai/v1', REQUESTY_API_KEY: key,
|
||||
}
|
||||
const credential = () => resolveRouteCredentialValue({ routeId: 'requesty', baseUrl: env.OPENAI_BASE_URL, processEnv: env })
|
||||
|
||||
expect((await getProviderValidationError(env)) === null).toBe(usable)
|
||||
expect(credential()).toBe(usable ? key : undefined)
|
||||
expect(getProviderPresetUiMetadata('requesty', env).apiKey).toBe(usable ? key : '')
|
||||
|
||||
// An unusable dedicated key falls back to a usable generic credential.
|
||||
env.OPENAI_API_KEY = 'openai-fallback-key'
|
||||
await expect(getProviderValidationError(env)).resolves.toBeNull()
|
||||
expect(credential()).toBe(usable ? key : 'openai-fallback-key')
|
||||
delete env.OPENAI_API_KEY
|
||||
env.OPENAI_API_KEYS = 'pool-key-a,pool-key-b'
|
||||
await expect(getProviderValidationError(env)).resolves.toBeNull()
|
||||
})
|
||||
|
||||
test('noncanonical Concentrate host paths fall back to generic OpenAI validation', async () => {
|
||||
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
||||
process.env.OPENAI_BASE_URL = 'https://api.concentrate.ai/staging/v1'
|
||||
|
||||
@@ -158,6 +158,7 @@ function hasUsableCredentialEnvValue(
|
||||
envVar === 'API_ROUTE_API_KEY' ||
|
||||
envVar === 'CONCENTRATE_API_KEY' ||
|
||||
envVar === 'LLMTR_API_KEY' ||
|
||||
envVar === 'REQUESTY_API_KEY' ||
|
||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||
envVar === 'CMD_API_KEY' ||
|
||||
envVar === 'COMMANDCODE_API_KEY' ||
|
||||
|
||||
Reference in New Issue
Block a user