fix(providers): keep saved Requesty keys off shell-retargeted launches

A relaunch with a shell OPENAI_BASE_URL that points a saved Requesty
profile at a non-canonical URL still carried the profile's persisted
OPENAI_API_KEY to that URL. Drop persisted generic credentials for that
retarget, as the Merge and Runcrate guards already do; explicit shell
credentials still apply.

Also require the persisted profile to be a Requesty profile before its
generic key is recovered as REQUESTY_API_KEY, so a shell retarget of
another profile to Requesty no longer adopts that profile's key over a
shell REQUESTY_API_KEY.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jatmn
2026-11-04 16:03:24 -08:00
co-authored by Claude Opus 5.5
parent e3b9587014
commit 41f409bf8a
2 changed files with 77 additions and 2 deletions
+60
View File
@@ -3811,3 +3811,63 @@ test('OpenAI profile builder materializes the canonical Orca key only at its rou
})
assert.equal(custom?.ORCAROUTER_API_KEY, undefined)
})
test('a shell URL retarget does not carry a saved Requesty key to the new endpoint', async () => {
const persisted = profile('openai', {
OPENAI_BASE_URL: 'https://router.requesty.ai/v1',
OPENAI_MODEL: 'openai/gpt-5-mini',
OPENAI_API_KEY: 'saved-requesty-key',
REQUESTY_API_KEY: 'saved-requesty-key',
})
for (const shellBaseUrl of [
'https://example.test/v1',
'http://router.requesty.ai/v1',
]) {
const env = await buildLaunchEnv({
profile: 'openai',
persisted,
goal: 'balanced',
processEnv: { OPENAI_BASE_URL: shellBaseUrl },
})
assert.equal(env.OPENAI_BASE_URL, shellBaseUrl)
assert.equal(env.OPENAI_API_KEY, undefined)
assert.equal(env.REQUESTY_API_KEY, undefined)
}
const regional = await buildLaunchEnv({
profile: 'openai',
persisted,
goal: 'balanced',
processEnv: { OPENAI_BASE_URL: 'https://router.eu.requesty.ai/v1' },
})
assert.equal(regional.OPENAI_API_KEY, 'saved-requesty-key')
assert.equal(regional.REQUESTY_API_KEY, 'saved-requesty-key')
})
test('a shell URL retarget to Requesty does not adopt another profile key as the Requesty key', async () => {
const env = await buildLaunchEnv({
profile: 'openai',
persisted: profile('openai', {
OPENAI_BASE_URL: 'https://api.openai.com/v1',
OPENAI_MODEL: 'gpt-4o',
OPENAI_API_KEY: 'sk-saved-openai',
}),
goal: 'balanced',
processEnv: {
OPENAI_BASE_URL: 'https://router.requesty.ai/v1',
REQUESTY_API_KEY: 'shell-requesty-key',
},
})
assert.equal(env.REQUESTY_API_KEY, 'shell-requesty-key')
assert.equal(
resolveRouteCredentialValue({
routeId: 'requesty',
baseUrl: env.OPENAI_BASE_URL,
processEnv: env,
}),
'shell-requesty-key',
)
})
+17 -2
View File
@@ -2260,6 +2260,14 @@ 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.
const persistedRequestyProfileIdentity =
persistedEnv.CLAUDE_CODE_PROVIDER_ROUTE_ID === 'requesty' ||
isCanonicalRequestyInferenceBaseUrl(persistedOpenAIBaseUrl)
const retargetedRequestyProfile =
persistedRequestyProfileIdentity &&
!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.
@@ -2283,7 +2291,11 @@ export async function buildLaunchEnv(options: {
: processEnv
const openAICredential = resolveOpenAICredentialEnvOverride(
shellCredentialSource,
retargetedMergeProfile || retargetedRuncrateProfile ? {} : persistedEnv,
retargetedMergeProfile ||
retargetedRuncrateProfile ||
retargetedRequestyProfile
? {}
: persistedEnv,
)
if (openAICredential) {
env[openAICredential.envVar] = openAICredential.value
@@ -2632,10 +2644,13 @@ export async function buildLaunchEnv(options: {
: undefined)
: undefined
// Same ownership rule for a selected canonical Requesty profile, including
// startup files that only persisted the saved key as OPENAI_API_KEY.
// 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.
const persistedRequestyProfileKey =
dedicatedKey === 'REQUESTY_API_KEY' &&
effectiveOpenAIRouteId === 'requesty' &&
persistedRequestyProfileIdentity &&
!!dedicatedBaseUrl &&
isCanonicalRequestyInferenceBaseUrl(dedicatedBaseUrl)
? sanitizeApiKey(persistedEnv.REQUESTY_API_KEY) ||