diff --git a/src/agents/agent-auth-credentials.ts b/src/agents/agent-auth-credentials.ts index c7c5ec5fefb..75fe61a1ec1 100644 --- a/src/agents/agent-auth-credentials.ts +++ b/src/agents/agent-auth-credentials.ts @@ -1,5 +1,6 @@ import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id"; import { coerceSecretRef } from "../config/types.secrets.js"; +import { asDateTimestampMs } from "../shared/number-coercion.js"; import { normalizeOptionalString } from "../shared/string-coerce.js"; import type { AuthProfileCredential, AuthProfileStore } from "./auth-profiles.js"; @@ -46,12 +47,11 @@ function convertAuthProfileCredentialToAgent( } if (cred.type === "token") { - if ( - typeof cred.expires === "number" && - Number.isFinite(cred.expires) && - Date.now() >= cred.expires - ) { - return null; + if (cred.expires !== undefined) { + const expires = asDateTimestampMs(cred.expires); + if (expires === undefined || Date.now() >= expires) { + return null; + } } const token = normalizeOptionalString(cred.token) ?? ""; if (!token) { @@ -63,14 +63,15 @@ function convertAuthProfileCredentialToAgent( if (cred.type === "oauth") { const access = normalizeOptionalString(cred.access) ?? ""; const refresh = normalizeOptionalString(cred.refresh) ?? ""; - if (!access || !refresh || !Number.isFinite(cred.expires) || cred.expires <= 0) { + const expires = asDateTimestampMs(cred.expires); + if (!access || !refresh || expires === undefined || expires <= 0) { return null; } return { type: "oauth", access, refresh, - expires: cred.expires, + expires, }; } diff --git a/src/agents/agent-model-discovery.auth.test.ts b/src/agents/agent-model-discovery.auth.test.ts index fb5da0cd4d9..b427b6051f7 100644 --- a/src/agents/agent-model-discovery.auth.test.ts +++ b/src/agents/agent-model-discovery.auth.test.ts @@ -2,6 +2,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { describe, expect, it, vi } from "vitest"; +import { MAX_DATE_TIMESTAMP_MS } from "../shared/number-coercion.js"; import { resolveAgentCredentialMapFromStore } from "./agent-auth-credentials.js"; import { addEnvBackedAgentCredentials, @@ -132,6 +133,30 @@ describe("discoverAuthStorage", () => { expect(codexCredential?.refresh).toBe("oauth-refresh"); }); + it("drops runtime auth profiles with out-of-range expiry values", () => { + const credentials = resolveAgentCredentialMapFromStore({ + version: 1, + profiles: { + "anthropic:bad-token-expiry": { + type: "token", + provider: "anthropic", + token: "sk-ant-runtime", + expires: MAX_DATE_TIMESTAMP_MS + 1, + }, + "openai-codex:bad-oauth-expiry": { + type: "oauth", + provider: "openai-codex", + access: "oauth-access", + refresh: "oauth-refresh", + expires: MAX_DATE_TIMESTAMP_MS + 1, + }, + }, + }); + + expect(credentials.anthropic).toBeUndefined(); + expect(credentials["openai-codex"]).toBeUndefined(); + }); + it("keeps keyRef and tokenRef profiles visible only for read-only agent discovery", () => { const credentials = resolveAgentCredentialMapFromStore({ version: 1,