Files
openclaw/src/agents/cli-execution-auth.ts
Jason (Json) 1a42e005fb fix(anthropic): forward selected profiles to Claude CLI (#112458)
* fix(anthropic): forward Claude CLI auth profiles

* fix(system-agent): inject CLI auth route stores

* fix(claude-cli): pass profile credentials by descriptor

* fix(anthropic): repair selected profile CI coverage

* fix(anthropic): preserve profile owner validation

* test(system-agent): preserve selected profile fixtures

* test(system-agent): narrow selected profile fixture

* test(system-agent): resolve profile store merge

* fix(anthropic): forward profiles to node Claude runs

* fix(system-agent): reconcile profile route projection

* test(system-agent): thread profile store through projection

* fix(anthropic): make selected profile authoritative

* fix(system-agent): type auth setup failures

* fix(system-agent): type setup auth failures

* style: format Claude profile maintenance

* fix(anthropic): keep gateway credentials off nodes

* fix(anthropic): clear ambient auth for selected profiles

* fix(anthropic): secure paired-node Claude auth

* fix(node-host): type Claude fd spawn streams

* style(node-host): satisfy Claude spawn lint

* fix(process): capture exit before secret delivery

* fix(anthropic): preserve node-native Claude auth
2026-07-21 23:27:37 -06:00

104 lines
3.5 KiB
TypeScript

/**
* Auth-profile forwarding shared by normal and narrow CLI-backed agent runs.
*/
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveAuthProfileOrder } from "./auth-profiles/order.js";
import { loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
import { resolveCliBackendConfig } from "./cli-backends.js";
const GOOGLE_GEMINI_CLI_PROVIDER_ID = "google-gemini-cli";
const GOOGLE_PROVIDER_ID = "google";
const CLAUDE_CLI_PROVIDER_ID = "claude-cli";
type CliExecutionAuthProfileSelection = {
authProfileId?: string;
authProfileIdSource?: "auto" | "user";
};
export class CliExecutionAuthProfileError extends Error {
override name = "CliExecutionAuthProfileError";
}
export function cliBackendAcceptsAuthProfileForwarding(params: {
provider: string;
config: OpenClawConfig;
agentId?: string;
}): boolean {
const backend = resolveCliBackendConfig(params.provider, params.config, {
agentId: params.agentId,
});
return backend?.id === GOOGLE_GEMINI_CLI_PROVIDER_ID || backend?.id === CLAUDE_CLI_PROVIDER_ID;
}
/**
* Resolve the profile a CLI backend may consume. Claude and Gemini use their
* native profile identities; Gemini may additionally bridge a canonical
* Google API key. A user-locked profile must fail closed here because falling
* through would silently run the request as another user.
*/
export function resolveCliExecutionAuthProfileId(params: {
cliExecutionProvider: string;
authProfileProvider: string;
config: OpenClawConfig;
agentDir: string;
selected?: CliExecutionAuthProfileSelection;
loadAuthProfileStoreForRuntime?: typeof loadAuthProfileStoreForRuntime;
}): string | undefined {
const loadStore = params.loadAuthProfileStoreForRuntime ?? loadAuthProfileStoreForRuntime;
const store = loadStore(params.agentDir, {
readOnly: true,
allowKeychainPrompt: false,
externalCliProviderIds: [params.cliExecutionProvider],
});
const selectedAuthProfileId = params.selected?.authProfileId?.trim();
if (selectedAuthProfileId) {
const credential = store.profiles[selectedAuthProfileId];
if (credential?.provider === params.cliExecutionProvider) {
return selectedAuthProfileId;
}
if (
params.cliExecutionProvider === GOOGLE_GEMINI_CLI_PROVIDER_ID &&
credential?.provider === GOOGLE_PROVIDER_ID &&
credential.type === "api_key" &&
params.selected?.authProfileIdSource !== "auto"
) {
return selectedAuthProfileId;
}
if (params.selected?.authProfileIdSource !== "auto") {
if (!credential) {
throw new CliExecutionAuthProfileError(
`No credentials found for profile "${selectedAuthProfileId}".`,
);
}
throw new CliExecutionAuthProfileError(
`CLI backend "${params.cliExecutionProvider}" cannot use auth profile "${selectedAuthProfileId}" owned by "${credential.provider}".`,
);
}
}
const cliProfileId = resolveAuthProfileOrder({
cfg: params.config,
store,
provider: params.cliExecutionProvider,
})[0];
if (cliProfileId) {
return cliProfileId;
}
if (
params.cliExecutionProvider !== GOOGLE_GEMINI_CLI_PROVIDER_ID ||
params.authProfileProvider !== GOOGLE_PROVIDER_ID
) {
return undefined;
}
return resolveAuthProfileOrder({
cfg: params.config,
store,
provider: GOOGLE_PROVIDER_ID,
}).find((profileId) => {
const credential = store.profiles[profileId];
return credential?.provider === GOOGLE_PROVIDER_ID && credential.type === "api_key";
});
}