fix(auth): extend legacy OAuth sidecar resolution to all secrets entry points

L4 patched only `loadAuthProfileStoreForSecretsRuntime`, but
`ensureAuthProfileStoreWithoutExternalProfiles` (used by the embedded
runner via `pi-embedded-runner/run.ts:59` and by `model-provider-auth.ts`)
and `loadAuthProfileStoreWithoutExternalProfiles` (used by
`model-auth-label`, `pi-auth-discovery`, the models list command, the
OAuth manager) are parallel entry points that ALSO needed the same flag
flip. Without this follow-up, cron-isolated lanes (`lane=cron-nested`,
`lane=session:agent:main:cron:...:run:...`) keep hitting the legacy
"No API key found for provider \"openai-codex\"" error path even though
direct user-Telegram lanes resolve fine.

Observed live 2026-05-20 17:45 PDT on the L4-patched v2026.5.19 build:
direct Telegram replies worked, but the 15-minute AgentOS task-board
sweep cron (`9584014c`) fired at 17:45:24 and surfaced the same
`FailoverError: No API key found for provider "openai-codex"` to the
delivery channel.

Fix:

  1. `loadAuthProfileStoreWithoutExternalProfiles`: default
     `resolveLegacyOAuthSidecars` from `false` to `true` — matches L4's
     reasoning for the secrets-runtime helper.

  2. `ensureAuthProfileStoreWithoutExternalProfiles`: accept the
     `resolveLegacyOAuthSidecars` option (was unsupported, hardcoded
     `false` downstream), default to `true`, and forward it through
     `resolveRuntimeAuthProfileStore` and both `loadAuthProfileStoreForAgent`
     call sites (requested agentDir + main fallback merge).

These functions are read-only and do not mutate persisted state, so
flipping the default is safe — they just include the credential material
that's been on disk all along.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Will (via Claude Code)
2026-05-20 17:49:45 -07:00
parent f7464c0f11
commit 4624e34c06

View File

@@ -614,7 +614,13 @@ export function loadAuthProfileStoreWithoutExternalProfiles(
const options: LoadAuthProfileStoreOptions = {
readOnly: true,
allowKeychainPrompt: loadOptions?.allowKeychainPrompt ?? false,
resolveLegacyOAuthSidecars: loadOptions?.resolveLegacyOAuthSidecars ?? false,
// L4.1 PATCH: default sidecar resolution to true so that any caller
// not explicitly overriding (model-auth-label, model-provider-auth,
// pi-auth-discovery, list.list-command, etc.) still picks up legacy
// OAuth credential material. Was inadvertently left at `false` in the
// upstream #82777/#83312 refactor and breaks isolated/sub-agent auth
// resolution paths (e.g., cron-nested lanes).
resolveLegacyOAuthSidecars: loadOptions?.resolveLegacyOAuthSidecars ?? true,
};
const store = loadAuthProfileStoreForAgent(agentDir, options);
const authPath = resolveAuthStorePath(agentDir);
@@ -649,20 +655,32 @@ export function ensureAuthProfileStore(
export function ensureAuthProfileStoreWithoutExternalProfiles(
agentDir?: string,
options?: { allowKeychainPrompt?: boolean },
options?: { allowKeychainPrompt?: boolean; resolveLegacyOAuthSidecars?: boolean },
): AuthProfileStore {
const runtimeStore = resolveRuntimeAuthProfileStore(agentDir, options);
// L4.1 PATCH: forward `resolveLegacyOAuthSidecars` through this entry
// point so embedded-runner sub-agents (cron-nested, isolated session
// lanes for AgentOS sweeps) can read the legacy sidecar credential
// material. Default true to match `loadAuthProfileStoreWithoutExternalProfiles`.
const resolveLegacyOAuthSidecars = options?.resolveLegacyOAuthSidecars ?? true;
const effectiveOptions: LoadAuthProfileStoreOptions = {
...(options ?? {}),
resolveLegacyOAuthSidecars,
};
const runtimeStore = resolveRuntimeAuthProfileStore(agentDir, effectiveOptions);
if (runtimeStore) {
return runtimeStore;
}
const store = loadAuthProfileStoreForAgent(agentDir, options);
const store = loadAuthProfileStoreForAgent(agentDir, effectiveOptions);
const authPath = resolveAuthStorePath(agentDir);
const mainAuthPath = resolveAuthStorePath();
if (!agentDir || authPath === mainAuthPath) {
return store;
}
const mainStore = loadAuthProfileStoreForAgent(undefined, options);
// L4.1 PATCH: use effectiveOptions (with sidecar resolution) for the main
// fallback load too, otherwise sub-agents that need to merge in the main
// store would still miss the legacy credential material.
const mainStore = loadAuthProfileStoreForAgent(undefined, effectiveOptions);
return mergeAuthProfileStores(mainStore, store);
}