mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-06 12:50:54 -04:00
fix(providers): bind saved Requesty credentials to a canonical saved URL
The Requesty retarget boundary only checked the launch URL. A profile saved for a non-canonical Requesty-route URL and relaunched with a shell OPENAI_BASE_URL on canonical Requesty was not treated as a retarget, so its proxy key, REQUESTY_API_KEY, custom-auth trio and custom headers all reached Requesty. Profile apply already treats only a canonically saved Requesty profile's key as a Requesty key. Use the same rule on relaunch: saved credentials follow only between canonical Requesty URLs. Any other launch drops them, including the dedicated-key fallback. Explicit shell credentials still apply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3943,3 +3943,50 @@ test('a shell URL retarget drops a saved Requesty profile custom auth and header
|
|||||||
assert.equal(ownProxy.OPENAI_AUTH_HEADER_VALUE, 'saved-auth-secret')
|
assert.equal(ownProxy.OPENAI_AUTH_HEADER_VALUE, 'saved-auth-secret')
|
||||||
assert.equal(ownProxy.ANTHROPIC_CUSTOM_HEADERS, 'X-Requesty-Auth: saved-header-secret')
|
assert.equal(ownProxy.ANTHROPIC_CUSTOM_HEADERS, 'X-Requesty-Auth: saved-header-secret')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('a shell URL retarget onto canonical Requesty drops a saved proxy profile credentials', async () => {
|
||||||
|
// Credentials saved for a non-canonical Requesty-route URL belong to that
|
||||||
|
// proxy, so moving the profile onto canonical Requesty is a retarget too.
|
||||||
|
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_API_KEY: 'saved-proxy-key',
|
||||||
|
REQUESTY_API_KEY: 'saved-proxy-requesty-key',
|
||||||
|
OPENAI_AUTH_HEADER: 'X-Proxy-Auth',
|
||||||
|
OPENAI_AUTH_SCHEME: 'raw',
|
||||||
|
OPENAI_AUTH_HEADER_VALUE: 'saved-proxy-secret',
|
||||||
|
ANTHROPIC_CUSTOM_HEADERS: 'X-Proxy-Auth: saved-proxy-header',
|
||||||
|
})
|
||||||
|
|
||||||
|
const env = await buildStartupEnvFromProfile({
|
||||||
|
persisted,
|
||||||
|
processEnv: { OPENAI_BASE_URL: 'https://router.requesty.ai/v1' },
|
||||||
|
})
|
||||||
|
assert.equal(env.OPENAI_BASE_URL, 'https://router.requesty.ai/v1')
|
||||||
|
assert.equal(env.OPENAI_API_KEY, undefined)
|
||||||
|
assert.equal(env.REQUESTY_API_KEY, undefined)
|
||||||
|
assert.equal(env.OPENAI_AUTH_HEADER, undefined)
|
||||||
|
assert.equal(env.OPENAI_AUTH_SCHEME, undefined)
|
||||||
|
assert.equal(env.OPENAI_AUTH_HEADER_VALUE, undefined)
|
||||||
|
assert.equal(env.ANTHROPIC_CUSTOM_HEADERS, undefined)
|
||||||
|
assert.equal(
|
||||||
|
resolveRouteCredentialValue({
|
||||||
|
routeId: 'requesty',
|
||||||
|
baseUrl: env.OPENAI_BASE_URL,
|
||||||
|
processEnv: env,
|
||||||
|
}),
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
|
||||||
|
// An explicit shell Requesty key still authenticates the canonical launch.
|
||||||
|
const explicit = await buildStartupEnvFromProfile({
|
||||||
|
persisted,
|
||||||
|
processEnv: {
|
||||||
|
OPENAI_BASE_URL: 'https://router.requesty.ai/v1',
|
||||||
|
REQUESTY_API_KEY: 'shell-requesty-key',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert.equal(explicit.REQUESTY_API_KEY, 'shell-requesty-key')
|
||||||
|
assert.equal(explicit.OPENAI_API_KEY, undefined)
|
||||||
|
})
|
||||||
|
|||||||
@@ -2260,14 +2260,19 @@ export async function buildLaunchEnv(options: {
|
|||||||
(persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' ||
|
(persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' ||
|
||||||
isCanonicalMergeGatewayInferenceBaseUrl(persistedOpenAIBaseUrl)) &&
|
isCanonicalMergeGatewayInferenceBaseUrl(persistedOpenAIBaseUrl)) &&
|
||||||
!isCanonicalMergeGatewayInferenceBaseUrl(env.OPENAI_BASE_URL)
|
!isCanonicalMergeGatewayInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||||
// Same for a saved Requesty profile: its key is valid only on the canonical
|
// Same for a saved Requesty profile: its key is a Requesty key only when the
|
||||||
// Requesty inference URLs, so a shell retarget elsewhere drops it.
|
// profile was saved for a canonical Requesty inference URL, and it is valid
|
||||||
|
// only on those URLs. Any other launch drops it, including one that moves a
|
||||||
|
// profile saved for a non-canonical URL onto canonical Requesty.
|
||||||
const persistedRequestyProfileIdentity =
|
const persistedRequestyProfileIdentity =
|
||||||
persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'requesty' ||
|
persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'requesty' ||
|
||||||
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl)
|
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl)
|
||||||
const retargetedRequestyProfile =
|
const retargetedRequestyProfile =
|
||||||
persistedRequestyProfileIdentity &&
|
persistedRequestyProfileIdentity &&
|
||||||
!isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
|
!(
|
||||||
|
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl) &&
|
||||||
|
isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
|
||||||
|
)
|
||||||
// A saved Runcrate profile mirrors its dedicated key into the generic
|
// A saved Runcrate profile mirrors its dedicated key into the generic
|
||||||
// OPENAI_API_KEY alias. A shell URL retarget must not hand that saved key to
|
// OPENAI_API_KEY alias. A shell URL retarget must not hand that saved key to
|
||||||
// the new endpoint; only an explicit shell credential may follow the URL.
|
// the new endpoint; only an explicit shell credential may follow the URL.
|
||||||
@@ -2278,8 +2283,8 @@ export async function buildLaunchEnv(options: {
|
|||||||
// Requesty supports custom auth headers, so its saved credential can also
|
// Requesty supports custom auth headers, so its saved credential can also
|
||||||
// ride in the custom-auth trio or custom headers. Those belong to the
|
// ride in the custom-auth trio or custom headers. Those belong to the
|
||||||
// endpoint the profile was saved for: a shell retarget away from it drops
|
// endpoint the profile was saved for: a shell retarget away from it drops
|
||||||
// them, while a saved non-canonical profile relaunched at its own URL keeps
|
// them in either direction, while a saved non-canonical profile relaunched
|
||||||
// them, matching profile apply.
|
// at its own URL keeps them, matching profile apply.
|
||||||
const shellRetargetedRequestyProfile =
|
const shellRetargetedRequestyProfile =
|
||||||
retargetedRequestyProfile &&
|
retargetedRequestyProfile &&
|
||||||
!isSameConfiguredEndpoint(env.OPENAI_BASE_URL, persistedOpenAIBaseUrl)
|
!isSameConfiguredEndpoint(env.OPENAI_BASE_URL, persistedOpenAIBaseUrl)
|
||||||
@@ -2657,12 +2662,13 @@ export async function buildLaunchEnv(options: {
|
|||||||
: undefined
|
: undefined
|
||||||
// Same ownership rule for a selected canonical Requesty profile, including
|
// Same ownership rule for a selected canonical Requesty profile, including
|
||||||
// startup files that only persisted the saved key as OPENAI_API_KEY. Only
|
// startup files that only persisted the saved key as OPENAI_API_KEY. Only
|
||||||
// a persisted Requesty profile owns that key; another profile's generic
|
// a Requesty profile saved for a canonical URL owns that key; another
|
||||||
// key is not a Requesty credential.
|
// profile's generic key is not a Requesty credential.
|
||||||
const persistedRequestyProfileKey =
|
const persistedRequestyProfileKey =
|
||||||
dedicatedKey === 'REQUESTY_API_KEY' &&
|
dedicatedKey === 'REQUESTY_API_KEY' &&
|
||||||
effectiveOpenAIRouteId === 'requesty' &&
|
effectiveOpenAIRouteId === 'requesty' &&
|
||||||
persistedRequestyProfileIdentity &&
|
persistedRequestyProfileIdentity &&
|
||||||
|
!retargetedRequestyProfile &&
|
||||||
!!dedicatedBaseUrl &&
|
!!dedicatedBaseUrl &&
|
||||||
isCanonicalRequestyInferenceBaseUrl(dedicatedBaseUrl)
|
isCanonicalRequestyInferenceBaseUrl(dedicatedBaseUrl)
|
||||||
? sanitizeApiKey(persistedEnv.REQUESTY_API_KEY) ||
|
? sanitizeApiKey(persistedEnv.REQUESTY_API_KEY) ||
|
||||||
@@ -2726,10 +2732,12 @@ export async function buildLaunchEnv(options: {
|
|||||||
? sanitizeApiKey(persistedOpenAICredential.value)
|
? sanitizeApiKey(persistedOpenAICredential.value)
|
||||||
: undefined)
|
: undefined)
|
||||||
: undefined
|
: undefined
|
||||||
// A retargeted Runcrate launch may only use an explicit shell credential;
|
// A retargeted Runcrate or Requesty launch may only use an explicit shell
|
||||||
// the saved profile key belongs to the endpoint it was saved for.
|
// credential; the saved profile key belongs to the endpoint it was saved
|
||||||
|
// for.
|
||||||
const persistedDedicatedKey =
|
const persistedDedicatedKey =
|
||||||
retargetedRuncrateProfile && dedicatedKey === 'RUNCRATE_API_KEY'
|
(retargetedRuncrateProfile && dedicatedKey === 'RUNCRATE_API_KEY') ||
|
||||||
|
(retargetedRequestyProfile && dedicatedKey === 'REQUESTY_API_KEY')
|
||||||
? undefined
|
? undefined
|
||||||
: sanitizeApiKey(persistedEnv[dedicatedKey])
|
: sanitizeApiKey(persistedEnv[dedicatedKey])
|
||||||
const shellDedicatedKey =
|
const shellDedicatedKey =
|
||||||
|
|||||||
Reference in New Issue
Block a user