Files
openclaw/src/agents/cli-execution-auth.ts
Peter Steinberger 96f0983a85 fix(onboarding): skip setup for configured gateways and require inference first (#102883)
* fix(crestodian): keep onboarding RPCs restart-safe

* fix(profiles): isolate approval state migrations

* fix(crestodian): bypass configured gateway setup

* test(crestodian): type onboarding mocks

* fix(onboarding): require inference before Crestodian

* fix(onboarding): enforce verified inference handoff

* fix(macos): reset setup on gateway endpoint edits

* chore(i18n): refresh native source inventory

* fix(gateway): keep socket on request cancellation

* test(packaging): require workspace templates

* fix(onboarding): bind setup to verified inference

* fix(onboarding): align inference gate contracts

* fix(crestodian): classify concurrent policy rejection

* test(crestodian): expect registry restoration

* fix(onboarding): bind setup to configured gateways

* fix(codex): preserve startup phase deadlines

* test(crestodian): match fail-closed policy ordering

* test(onboarding): assert bound gateway handoff

* fix(codex): bind runtime resolution to spawn cwd

* test(crestodian): assert policy rejection order

* fix(cli): preserve gateway routing across restarts

* fix(macos): fail closed during gateway edits

* test(macos): cover gateway route generation races

* chore: keep release notes out of onboarding PR

* fix(ci): refresh onboarding generated checks

* style(swift): align gateway channel formatting

* fix(ci): refresh plugin SDK surface budgets

* fix(ci): resync native string inventory

* refactor(swift): split gateway channel support

* test(doctor): isolate plugin compatibility registry

* test(macos): isolate gateway onboarding fixtures

* test(macos): assert gateway lease health ordering

* fix(codex): reconcile computer-use startup changes
2026-07-11 10:25:14 -07:00

95 lines
3.1 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";
export type CliExecutionAuthProfileSelection = {
authProfileId?: string;
authProfileIdSource?: "auto" | "user";
};
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;
}
/**
* Resolve the profile a CLI backend may consume. Gemini CLI prefers its own
* OAuth identity, then bridges a canonical Google API key when that model is
* explicitly routed through the CLI runtime. A user-locked profile must fail
* closed here; falling through would silently run the request as another user.
*/
export function resolveCliExecutionAuthProfileId(params: {
cliExecutionProvider: string;
authProfileProvider: string;
config: OpenClawConfig;
agentDir: string;
selected?: CliExecutionAuthProfileSelection;
}): string | undefined {
const store = loadAuthProfileStoreForRuntime(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 Error(`No credentials found for profile "${selectedAuthProfileId}".`);
}
throw new Error(
`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";
});
}