From dd78b16cdcd49d9b8d85a4500dba29e7c78379ae Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:45:01 -0500 Subject: [PATCH] fix: normalize auth health provider aliases --- src/agents/auth-health.test.ts | 36 ++++++++++++++++++++++++++++++++++ src/agents/auth-health.ts | 18 ++++++++++------- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/agents/auth-health.test.ts b/src/agents/auth-health.test.ts index 4e2cc12cd82..2607efecf97 100644 --- a/src/agents/auth-health.test.ts +++ b/src/agents/auth-health.test.ts @@ -116,6 +116,42 @@ describe("buildAuthHealthSummary", () => { expect(statuses["github-copilot:invalid-expires"]).toBe("missing"); expect(reasonCodes["github-copilot:invalid-expires"]).toBe("invalid_expires"); }); + + it("normalizes provider aliases when filtering and grouping profile health", () => { + vi.spyOn(Date, "now").mockReturnValue(now); + const store = { + version: 1, + profiles: { + "zai:dot": { + type: "api_key" as const, + provider: "z.ai", + key: "sk-dot", + }, + "zai:dash": { + type: "api_key" as const, + provider: "z-ai", + key: "sk-dash", + }, + }, + }; + + const summary = buildAuthHealthSummary({ + store, + providers: ["zai"], + }); + + expect(summary.profiles.map((profile) => [profile.profileId, profile.provider])).toEqual([ + ["zai:dash", "zai"], + ["zai:dot", "zai"], + ]); + expect(summary.providers).toEqual([ + { + provider: "zai", + status: "static", + profiles: summary.profiles, + }, + ]); + }); }); describe("formatRemainingShort", () => { diff --git a/src/agents/auth-health.ts b/src/agents/auth-health.ts index 3876eb03f18..b7f1ef76982 100644 --- a/src/agents/auth-health.ts +++ b/src/agents/auth-health.ts @@ -9,6 +9,7 @@ import { evaluateStoredCredentialEligibility, resolveTokenExpiryState, } from "./auth-profiles/credential-state.js"; +import { normalizeProviderId } from "./provider-id.js"; export type AuthProfileSource = "store"; @@ -106,11 +107,12 @@ function buildProfileHealth(params: { const { profileId, credential, store, cfg, now, warnAfterMs } = params; const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId }); const source = resolveAuthProfileSource(profileId); + const provider = normalizeProviderId(credential.provider); if (credential.type === "api_key") { return { profileId, - provider: credential.provider, + provider, type: "api_key", status: "static", source, @@ -128,7 +130,7 @@ function buildProfileHealth(params: { eligibility.reasonCode === "expired" ? "expired" : "missing"; return { profileId, - provider: credential.provider, + provider, type: "token", status, reasonCode: eligibility.reasonCode, @@ -141,7 +143,7 @@ function buildProfileHealth(params: { if (!expiresAt) { return { profileId, - provider: credential.provider, + provider, type: "token", status: "static", source, @@ -151,7 +153,7 @@ function buildProfileHealth(params: { const { status, remainingMs } = resolveOAuthStatus(expiresAt, now, warnAfterMs); return { profileId, - provider: credential.provider, + provider, type: "token", status, reasonCode: status === "expired" ? "expired" : undefined, @@ -174,7 +176,7 @@ function buildProfileHealth(params: { hasRefreshToken && (rawStatus === "expired" || rawStatus === "expiring") ? "ok" : rawStatus; return { profileId, - provider: credential.provider, + provider, type: "oauth", status, expiresAt: credential.expires, @@ -193,11 +195,13 @@ export function buildAuthHealthSummary(params: { const now = Date.now(); const warnAfterMs = params.warnAfterMs ?? DEFAULT_OAUTH_WARN_MS; const providerFilter = params.providers - ? new Set(params.providers.map((p) => p.trim()).filter(Boolean)) + ? new Set(params.providers.map((p) => normalizeProviderId(p)).filter(Boolean)) : null; const profiles = Object.entries(params.store.profiles) - .filter(([_, cred]) => (providerFilter ? providerFilter.has(cred.provider) : true)) + .filter(([_, cred]) => + providerFilter ? providerFilter.has(normalizeProviderId(cred.provider)) : true, + ) .map(([profileId, credential]) => buildProfileHealth({ profileId,