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:
jatmn
2026-11-04 16:54:00 -08:00
co-authored by Claude Opus 5.5
parent 7d3dbb86a5
commit 55b02074f2
2 changed files with 65 additions and 10 deletions
+47
View File
@@ -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.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)
})
+18 -10
View File
@@ -2260,14 +2260,19 @@ export async function buildLaunchEnv(options: {
(persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'merge-gateway' ||
isCanonicalMergeGatewayInferenceBaseUrl(persistedOpenAIBaseUrl)) &&
!isCanonicalMergeGatewayInferenceBaseUrl(env.OPENAI_BASE_URL)
// Same for a saved Requesty profile: its key is valid only on the canonical
// Requesty inference URLs, so a shell retarget elsewhere drops it.
// Same for a saved Requesty profile: its key is a Requesty key only when the
// 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 =
persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'requesty' ||
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl)
const retargetedRequestyProfile =
persistedRequestyProfileIdentity &&
!isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
!(
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl) &&
isCanonicalRequestyInferenceBaseUrl(env.OPENAI_BASE_URL)
)
// 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
// 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
// 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
// them, while a saved non-canonical profile relaunched at its own URL keeps
// them, matching profile apply.
// them in either direction, while a saved non-canonical profile relaunched
// at its own URL keeps them, matching profile apply.
const shellRetargetedRequestyProfile =
retargetedRequestyProfile &&
!isSameConfiguredEndpoint(env.OPENAI_BASE_URL, persistedOpenAIBaseUrl)
@@ -2657,12 +2662,13 @@ export async function buildLaunchEnv(options: {
: undefined
// Same ownership rule for a selected canonical Requesty profile, including
// startup files that only persisted the saved key as OPENAI_API_KEY. Only
// a persisted Requesty profile owns that key; another profile's generic
// key is not a Requesty credential.
// a Requesty profile saved for a canonical URL owns that key; another
// profile's generic key is not a Requesty credential.
const persistedRequestyProfileKey =
dedicatedKey === 'REQUESTY_API_KEY' &&
effectiveOpenAIRouteId === 'requesty' &&
persistedRequestyProfileIdentity &&
!retargetedRequestyProfile &&
!!dedicatedBaseUrl &&
isCanonicalRequestyInferenceBaseUrl(dedicatedBaseUrl)
? sanitizeApiKey(persistedEnv.REQUESTY_API_KEY) ||
@@ -2726,10 +2732,12 @@ export async function buildLaunchEnv(options: {
? sanitizeApiKey(persistedOpenAICredential.value)
: undefined)
: undefined
// A retargeted Runcrate launch may only use an explicit shell credential;
// the saved profile key belongs to the endpoint it was saved for.
// A retargeted Runcrate or Requesty launch may only use an explicit shell
// credential; the saved profile key belongs to the endpoint it was saved
// for.
const persistedDedicatedKey =
retargetedRuncrateProfile && dedicatedKey === 'RUNCRATE_API_KEY'
(retargetedRuncrateProfile && dedicatedKey === 'RUNCRATE_API_KEY') ||
(retargetedRequestyProfile && dedicatedKey === 'REQUESTY_API_KEY')
? undefined
: sanitizeApiKey(persistedEnv[dedicatedKey])
const shellDedicatedKey =