mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-04 21:01:40 +00:00
* 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
104 lines
3.5 KiB
TypeScript
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";
|
|
});
|
|
}
|