mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:20:43 +00:00
fix(cli): stabilize oauth session auth epochs
This commit is contained in:
@@ -23,6 +23,8 @@ const defaultCliAuthEpochDeps: CliAuthEpochDeps = {
|
||||
|
||||
const cliAuthEpochDeps: CliAuthEpochDeps = { ...defaultCliAuthEpochDeps };
|
||||
|
||||
export const CLI_AUTH_EPOCH_VERSION = 2;
|
||||
|
||||
export function setCliAuthEpochTestDeps(overrides: Partial<CliAuthEpochDeps>): void {
|
||||
Object.assign(cliAuthEpochDeps, overrides);
|
||||
}
|
||||
@@ -41,24 +43,16 @@ function encodeUnknown(value: unknown): string {
|
||||
|
||||
function encodeClaudeCredential(credential: ClaudeCliCredential): string {
|
||||
if (credential.type === "oauth") {
|
||||
return JSON.stringify([
|
||||
"oauth",
|
||||
credential.provider,
|
||||
credential.access,
|
||||
credential.refresh,
|
||||
credential.expires,
|
||||
]);
|
||||
return JSON.stringify(["oauth", credential.provider, credential.refresh]);
|
||||
}
|
||||
return JSON.stringify(["token", credential.provider, credential.token, credential.expires]);
|
||||
return JSON.stringify(["token", credential.provider, credential.token]);
|
||||
}
|
||||
|
||||
function encodeCodexCredential(credential: CodexCliCredential): string {
|
||||
return JSON.stringify([
|
||||
credential.type,
|
||||
credential.provider,
|
||||
credential.access,
|
||||
credential.refresh,
|
||||
credential.expires,
|
||||
credential.accountId ?? null,
|
||||
]);
|
||||
}
|
||||
@@ -81,7 +75,6 @@ function encodeAuthProfileCredential(credential: AuthProfileCredential): string
|
||||
credential.provider,
|
||||
credential.token ?? null,
|
||||
encodeUnknown(credential.tokenRef),
|
||||
credential.expires ?? null,
|
||||
credential.email ?? null,
|
||||
credential.displayName ?? null,
|
||||
]);
|
||||
@@ -89,12 +82,9 @@ function encodeAuthProfileCredential(credential: AuthProfileCredential): string
|
||||
return JSON.stringify([
|
||||
"oauth",
|
||||
credential.provider,
|
||||
credential.access,
|
||||
credential.refresh,
|
||||
credential.expires,
|
||||
credential.clientId ?? null,
|
||||
credential.email ?? null,
|
||||
credential.displayName ?? null,
|
||||
credential.enterpriseUrl ?? null,
|
||||
credential.projectId ?? null,
|
||||
credential.accountId ?? null,
|
||||
|
||||
@@ -72,6 +72,7 @@ export async function runPreparedCliAgent(
|
||||
? { authProfileId: context.effectiveAuthProfileId }
|
||||
: {}),
|
||||
...(context.authEpoch ? { authEpoch: context.authEpoch } : {}),
|
||||
authEpochVersion: context.authEpochVersion,
|
||||
...(context.extraSystemPromptHash
|
||||
? { extraSystemPromptHash: context.extraSystemPromptHash }
|
||||
: {}),
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
makeBootstrapWarn as makeBootstrapWarnImpl,
|
||||
resolveBootstrapContextForRun as resolveBootstrapContextForRunImpl,
|
||||
} from "../bootstrap-files.js";
|
||||
import { resolveCliAuthEpoch } from "../cli-auth-epoch.js";
|
||||
import { CLI_AUTH_EPOCH_VERSION, resolveCliAuthEpoch } from "../cli-auth-epoch.js";
|
||||
import { resolveCliBackendConfig } from "../cli-backends.js";
|
||||
import { hashCliSessionText, resolveCliSessionReuse } from "../cli-session.js";
|
||||
import { resolveHeartbeatPromptForSystemPrompt } from "../heartbeat-system-prompt.js";
|
||||
@@ -188,15 +188,16 @@ export async function prepareCliRunContext(
|
||||
modelId,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
});
|
||||
const skipLocalCredentialEpoch = shouldSkipLocalCliCredentialEpoch({
|
||||
authEpochMode: backendResolved.authEpochMode,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
authCredential,
|
||||
preparedExecution,
|
||||
});
|
||||
const authEpoch = await resolveCliAuthEpoch({
|
||||
provider: params.provider,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
skipLocalCredential: shouldSkipLocalCliCredentialEpoch({
|
||||
authEpochMode: backendResolved.authEpochMode,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
authCredential,
|
||||
preparedExecution,
|
||||
}),
|
||||
skipLocalCredential: skipLocalCredentialEpoch,
|
||||
});
|
||||
const preparedBackendEnv =
|
||||
preparedExecution?.env && Object.keys(preparedExecution.env).length > 0
|
||||
@@ -232,6 +233,7 @@ export async function prepareCliRunContext(
|
||||
binding: params.cliSessionBinding,
|
||||
authProfileId: effectiveAuthProfileId,
|
||||
authEpoch,
|
||||
authEpochVersion: CLI_AUTH_EPOCH_VERSION,
|
||||
extraSystemPromptHash,
|
||||
mcpConfigHash: preparedBackendFinal.mcpConfigHash,
|
||||
mcpResumeHash: preparedBackendFinal.mcpResumeHash,
|
||||
@@ -332,6 +334,7 @@ export async function prepareCliRunContext(
|
||||
bootstrapPromptWarningLines: bootstrapPromptWarning.lines,
|
||||
heartbeatPrompt,
|
||||
authEpoch,
|
||||
authEpochVersion: CLI_AUTH_EPOCH_VERSION,
|
||||
extraSystemPromptHash,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,5 +68,6 @@ export type PreparedCliRunContext = {
|
||||
bootstrapPromptWarningLines: string[];
|
||||
heartbeatPrompt?: string;
|
||||
authEpoch?: string;
|
||||
authEpochVersion: number;
|
||||
extraSystemPromptHash?: string;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ export function getCliSessionBinding(
|
||||
sessionId: bindingSessionId,
|
||||
authProfileId: normalizeOptionalString(fromBindings?.authProfileId),
|
||||
authEpoch: normalizeOptionalString(fromBindings?.authEpoch),
|
||||
authEpochVersion: fromBindings?.authEpochVersion,
|
||||
extraSystemPromptHash: normalizeOptionalString(fromBindings?.extraSystemPromptHash),
|
||||
mcpConfigHash: normalizeOptionalString(fromBindings?.mcpConfigHash),
|
||||
mcpResumeHash: normalizeOptionalString(fromBindings?.mcpResumeHash),
|
||||
@@ -78,6 +79,9 @@ export function setCliSessionBinding(
|
||||
...(normalizeOptionalString(binding.authEpoch)
|
||||
? { authEpoch: normalizeOptionalString(binding.authEpoch) }
|
||||
: {}),
|
||||
...(typeof binding.authEpochVersion === "number" && Number.isFinite(binding.authEpochVersion)
|
||||
? { authEpochVersion: binding.authEpochVersion }
|
||||
: {}),
|
||||
...(normalizeOptionalString(binding.extraSystemPromptHash)
|
||||
? { extraSystemPromptHash: normalizeOptionalString(binding.extraSystemPromptHash) }
|
||||
: {}),
|
||||
@@ -122,6 +126,7 @@ export function resolveCliSessionReuse(params: {
|
||||
binding?: CliSessionBinding;
|
||||
authProfileId?: string;
|
||||
authEpoch?: string;
|
||||
authEpochVersion?: number;
|
||||
extraSystemPromptHash?: string;
|
||||
mcpConfigHash?: string;
|
||||
mcpResumeHash?: string;
|
||||
@@ -144,7 +149,10 @@ export function resolveCliSessionReuse(params: {
|
||||
return { invalidatedReason: "auth-profile" };
|
||||
}
|
||||
const storedAuthEpoch = normalizeOptionalString(binding?.authEpoch);
|
||||
if (storedAuthEpoch !== currentAuthEpoch) {
|
||||
if (
|
||||
binding?.authEpochVersion === params.authEpochVersion &&
|
||||
storedAuthEpoch !== currentAuthEpoch
|
||||
) {
|
||||
return { invalidatedReason: "auth-epoch" };
|
||||
}
|
||||
const storedExtraSystemPromptHash = normalizeOptionalString(binding?.extraSystemPromptHash);
|
||||
|
||||
@@ -72,6 +72,7 @@ export type CliSessionBinding = {
|
||||
sessionId: string;
|
||||
authProfileId?: string;
|
||||
authEpoch?: string;
|
||||
authEpochVersion?: number;
|
||||
extraSystemPromptHash?: string;
|
||||
mcpConfigHash?: string;
|
||||
mcpResumeHash?: string;
|
||||
|
||||
Reference in New Issue
Block a user