mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:30:42 +00:00
fix(agents): reuse cached Claude keychain credentials
This commit is contained in:
@@ -205,7 +205,7 @@ describe("cli credentials", () => {
|
||||
it.each([
|
||||
{
|
||||
name: "caches Claude Code CLI credentials within the TTL window",
|
||||
allowKeychainPromptSecondRead: false,
|
||||
allowKeychainPromptSecondRead: true,
|
||||
advanceMs: 0,
|
||||
expectedCalls: 1,
|
||||
expectSameObject: true,
|
||||
@@ -240,6 +240,62 @@ describe("cli credentials", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it("does not let no-keychain Claude cache misses poison keychain reads", async () => {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-claude-cache-"));
|
||||
vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
|
||||
|
||||
const withoutKeychain = readClaudeCliCredentialsCached({
|
||||
allowKeychainPrompt: false,
|
||||
ttlMs: CLI_CREDENTIALS_CACHE_TTL_MS,
|
||||
platform: "darwin",
|
||||
homeDir: tempDir,
|
||||
execSync: execSyncMock,
|
||||
});
|
||||
|
||||
expect(withoutKeychain).toBeNull();
|
||||
expect(execSyncMock).not.toHaveBeenCalled();
|
||||
|
||||
mockClaudeCliCredentialRead();
|
||||
const withKeychain = readClaudeCliCredentialsCached({
|
||||
allowKeychainPrompt: true,
|
||||
ttlMs: CLI_CREDENTIALS_CACHE_TTL_MS,
|
||||
platform: "darwin",
|
||||
homeDir: tempDir,
|
||||
execSync: execSyncMock,
|
||||
});
|
||||
|
||||
expect(withKeychain).toMatchObject({
|
||||
type: "oauth",
|
||||
provider: "anthropic",
|
||||
refresh: "cached-refresh",
|
||||
});
|
||||
expect(execSyncMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("reuses cached Claude keychain credentials for no-prompt reads", async () => {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-claude-cache-"));
|
||||
vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
|
||||
mockClaudeCliCredentialRead();
|
||||
|
||||
const withKeychain = readClaudeCliCredentialsCached({
|
||||
allowKeychainPrompt: true,
|
||||
ttlMs: CLI_CREDENTIALS_CACHE_TTL_MS,
|
||||
platform: "darwin",
|
||||
homeDir: tempDir,
|
||||
execSync: execSyncMock,
|
||||
});
|
||||
const withoutPrompt = readClaudeCliCredentialsCached({
|
||||
allowKeychainPrompt: false,
|
||||
ttlMs: CLI_CREDENTIALS_CACHE_TTL_MS,
|
||||
platform: "darwin",
|
||||
homeDir: tempDir,
|
||||
execSync: execSyncMock,
|
||||
});
|
||||
|
||||
expect(withoutPrompt).toEqual(withKeychain);
|
||||
expect(execSyncMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("reads Codex credentials from keychain when available", async () => {
|
||||
const tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-codex-"));
|
||||
process.env.CODEX_HOME = tempHome;
|
||||
|
||||
@@ -455,14 +455,30 @@ export function readClaudeCliCredentialsCached(options?: {
|
||||
homeDir?: string;
|
||||
execSync?: ExecSyncFn;
|
||||
}): ClaudeCliCredential | null {
|
||||
const platform = options?.platform ?? process.platform;
|
||||
const ttlMs = options?.ttlMs ?? 0;
|
||||
const credentialsPath = resolveClaudeCliCredentialsPath(options?.homeDir);
|
||||
const keychainCacheKey = `${credentialsPath}:keychain`;
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
platform === "darwin" &&
|
||||
options?.allowKeychainPrompt === false &&
|
||||
claudeCliCache?.cacheKey === keychainCacheKey &&
|
||||
claudeCliCache.value &&
|
||||
Date.now() - claudeCliCache.readAt < ttlMs
|
||||
) {
|
||||
return claudeCliCache.value;
|
||||
}
|
||||
const keychainIntent =
|
||||
platform === "darwin" && options?.allowKeychainPrompt !== false ? "keychain" : "file";
|
||||
return readCachedCliCredential({
|
||||
ttlMs: options?.ttlMs ?? 0,
|
||||
ttlMs,
|
||||
cache: claudeCliCache,
|
||||
cacheKey: resolveClaudeCliCredentialsPath(options?.homeDir),
|
||||
cacheKey: `${credentialsPath}:${keychainIntent}`,
|
||||
read: () =>
|
||||
readClaudeCliCredentials({
|
||||
allowKeychainPrompt: options?.allowKeychainPrompt,
|
||||
platform: options?.platform,
|
||||
platform,
|
||||
homeDir: options?.homeDir,
|
||||
execSync: options?.execSync,
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user