mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-12 23:43:52 -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_KEYS' ||
|
||||||
envVar === 'OPENAI_API_KEY' ||
|
envVar === 'OPENAI_API_KEY' ||
|
||||||
envVar === 'LLMTR_API_KEY' ||
|
envVar === 'LLMTR_API_KEY' ||
|
||||||
|
envVar === 'REQUESTY_API_KEY' ||
|
||||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||||
envVar === 'CMD_API_KEY' ||
|
envVar === 'CMD_API_KEY' ||
|
||||||
envVar === 'COMMANDCODE_API_KEY' ||
|
envVar === 'COMMANDCODE_API_KEY' ||
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ function hasUsableEnvCredentialValue(
|
|||||||
envVar === 'APISMART_API_KEY' ||
|
envVar === 'APISMART_API_KEY' ||
|
||||||
envVar === 'CONCENTRATE_API_KEY' ||
|
envVar === 'CONCENTRATE_API_KEY' ||
|
||||||
envVar === 'LLMTR_API_KEY' ||
|
envVar === 'LLMTR_API_KEY' ||
|
||||||
|
envVar === 'REQUESTY_API_KEY' ||
|
||||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||||
envVar === 'CMD_API_KEY' ||
|
envVar === 'CMD_API_KEY' ||
|
||||||
envVar === 'COMMANDCODE_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.REQUESTY_API_KEY, 'shell-requesty-key')
|
||||||
assert.equal(explicit.OPENAI_API_KEY, undefined)
|
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' &&
|
effectiveOpenAIRouteId === 'llmtr' &&
|
||||||
!!env.OPENAI_BASE_URL?.trim() &&
|
!!env.OPENAI_BASE_URL?.trim() &&
|
||||||
!isCanonicalLlmtrInferenceBaseUrl(env.OPENAI_BASE_URL)
|
!isCanonicalLlmtrInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||||
|
const isNoncanonicalRequestyLaunch =
|
||||||
|
effectiveOpenAIRouteId === 'requesty' &&
|
||||||
|
!!env.OPENAI_BASE_URL?.trim() &&
|
||||||
|
!isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||||
const isNoncanonicalMergeGatewayLaunch =
|
const isNoncanonicalMergeGatewayLaunch =
|
||||||
effectiveOpenAIRouteId === 'merge-gateway' &&
|
effectiveOpenAIRouteId === 'merge-gateway' &&
|
||||||
!!env.OPENAI_BASE_URL?.trim() &&
|
!!env.OPENAI_BASE_URL?.trim() &&
|
||||||
@@ -2390,6 +2394,7 @@ export async function buildLaunchEnv(options: {
|
|||||||
isNoncanonicalApismartLaunch ||
|
isNoncanonicalApismartLaunch ||
|
||||||
isNoncanonicalConcentrateLaunch ||
|
isNoncanonicalConcentrateLaunch ||
|
||||||
isNoncanonicalLlmtrLaunch ||
|
isNoncanonicalLlmtrLaunch ||
|
||||||
|
isNoncanonicalRequestyLaunch ||
|
||||||
isNoncanonicalMergeGatewayLaunch ||
|
isNoncanonicalMergeGatewayLaunch ||
|
||||||
isNoncanonicalCommandcodeLaunch ||
|
isNoncanonicalCommandcodeLaunch ||
|
||||||
isNoncanonicalApiRouteLaunch
|
isNoncanonicalApiRouteLaunch
|
||||||
@@ -2406,6 +2411,7 @@ export async function buildLaunchEnv(options: {
|
|||||||
} else if (
|
} else if (
|
||||||
!isNoncanonicalConcentrateLaunch &&
|
!isNoncanonicalConcentrateLaunch &&
|
||||||
!isNoncanonicalLlmtrLaunch &&
|
!isNoncanonicalLlmtrLaunch &&
|
||||||
|
!isNoncanonicalRequestyLaunch &&
|
||||||
!isNoncanonicalMergeGatewayLaunch &&
|
!isNoncanonicalMergeGatewayLaunch &&
|
||||||
!isNoncanonicalCommandcodeLaunch
|
!isNoncanonicalCommandcodeLaunch
|
||||||
) {
|
) {
|
||||||
@@ -2889,6 +2895,11 @@ export async function buildStartupEnvFromProfile(options?: {
|
|||||||
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'llmtr' &&
|
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'llmtr' &&
|
||||||
!!persisted.env.OPENAI_BASE_URL?.trim() &&
|
!!persisted.env.OPENAI_BASE_URL?.trim() &&
|
||||||
!isCanonicalLlmtrInferenceBaseUrl(persisted.env.OPENAI_BASE_URL)
|
!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 =
|
const persistedMergeGatewayProxy =
|
||||||
persisted?.profile === 'openai' &&
|
persisted?.profile === 'openai' &&
|
||||||
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' &&
|
persisted.env.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' &&
|
||||||
@@ -2909,6 +2920,7 @@ export async function buildStartupEnvFromProfile(options?: {
|
|||||||
!persistedApismartProxy &&
|
!persistedApismartProxy &&
|
||||||
!persistedConcentrateProxy &&
|
!persistedConcentrateProxy &&
|
||||||
!persistedLlmtrProxy &&
|
!persistedLlmtrProxy &&
|
||||||
|
!persistedRequestyProxy &&
|
||||||
!persistedMergeGatewayProxy &&
|
!persistedMergeGatewayProxy &&
|
||||||
!persistedCommandcodeProxy &&
|
!persistedCommandcodeProxy &&
|
||||||
!persistedApiRouteProxy
|
!persistedApiRouteProxy
|
||||||
|
|||||||
@@ -618,6 +618,29 @@ test('noncanonical Requesty host paths do not validate a dedicated credential',
|
|||||||
await expect(getProviderValidationError(process.env)).resolves.toBeNull()
|
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 () => {
|
test('noncanonical Concentrate host paths fall back to generic OpenAI validation', async () => {
|
||||||
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
||||||
process.env.OPENAI_BASE_URL = 'https://api.concentrate.ai/staging/v1'
|
process.env.OPENAI_BASE_URL = 'https://api.concentrate.ai/staging/v1'
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ function hasUsableCredentialEnvValue(
|
|||||||
envVar === 'API_ROUTE_API_KEY' ||
|
envVar === 'API_ROUTE_API_KEY' ||
|
||||||
envVar === 'CONCENTRATE_API_KEY' ||
|
envVar === 'CONCENTRATE_API_KEY' ||
|
||||||
envVar === 'LLMTR_API_KEY' ||
|
envVar === 'LLMTR_API_KEY' ||
|
||||||
|
envVar === 'REQUESTY_API_KEY' ||
|
||||||
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
envVar === 'MERGE_GATEWAY_API_KEY' ||
|
||||||
envVar === 'CMD_API_KEY' ||
|
envVar === 'CMD_API_KEY' ||
|
||||||
envVar === 'COMMANDCODE_API_KEY' ||
|
envVar === 'COMMANDCODE_API_KEY' ||
|
||||||
|
|||||||
Reference in New Issue
Block a user