From af7d3a428da4f79f27679c158c3398a4994b57f8 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Fri, 28 Aug 2026 13:13:40 +0900 Subject: [PATCH] fix(gui): reject invalid quota expiry dates --- gui/src/provider-workspace/report.ts | 9 ++++++++- gui/tests/provider-capacity-credits.test.tsx | 6 ++++++ gui/tests/provider-capacity.test.ts | 16 ++++++++++++++++ src/providers/quota.ts | 3 ++- tests/command-code-quota.test.ts | 5 ++--- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/gui/src/provider-workspace/report.ts b/gui/src/provider-workspace/report.ts index 539fbba2f2..67d02fedd2 100644 --- a/gui/src/provider-workspace/report.ts +++ b/gui/src/provider-workspace/report.ts @@ -39,6 +39,13 @@ const finite = (value: unknown): number | undefined => ( typeof value === "number" && Number.isFinite(value) ? value : undefined ); +const dateTimestamp = (value: unknown): number | undefined => { + const timestamp = finite(value); + if (timestamp === undefined) return undefined; + const milliseconds = timestamp > 10_000_000_000 ? timestamp : timestamp * 1000; + return Number.isFinite(new Date(milliseconds).getTime()) ? timestamp : undefined; +}; + function quotaFromUnknown(quota: unknown, fallbackUpdatedAt?: number): AccountQuota | null { if (!quota || typeof quota !== "object" || Array.isArray(quota)) return null; const q = quota as Record; @@ -61,7 +68,7 @@ function quotaFromUnknown(quota: unknown, fallbackUpdatedAt?: number): AccountQu const creditsLimit = finite(creditsRaw?.limit); const creditsRemaining = finite(creditsRaw?.remaining); const creditsPercent = finite(creditsRaw?.percent); - const creditsExpiresAt = finite(creditsRaw?.expiresAt); + const creditsExpiresAt = dateTimestamp(creditsRaw?.expiresAt); const creditsUsd = creditsUsed !== undefined && creditsLimit !== undefined && creditsRemaining !== undefined diff --git a/gui/tests/provider-capacity-credits.test.tsx b/gui/tests/provider-capacity-credits.test.tsx index 35045aa870..55e7d3bd0e 100644 --- a/gui/tests/provider-capacity-credits.test.tsx +++ b/gui/tests/provider-capacity-credits.test.tsx @@ -39,3 +39,9 @@ test("credits with an expiry render the localized billing-period end date", () = expect(markup).toContain("Credits balance"); expect(markup).toContain("Billing period ends 26 Aug 2026"); }); + +test("credits with an out-of-range expiry render without the billing-period line", () => { + const markup = renderCredits(1e20); + expect(markup).toContain("Credits balance"); + expect(markup).not.toContain("Billing period ends"); +}); diff --git a/gui/tests/provider-capacity.test.ts b/gui/tests/provider-capacity.test.ts index 3916b3eadb..4953a1f824 100644 --- a/gui/tests/provider-capacity.test.ts +++ b/gui/tests/provider-capacity.test.ts @@ -61,6 +61,22 @@ test("provider quota reports reject malformed required credits and drop malforme creditsUsd: { used: 12.5, limit: 50, remaining: 37.5, percent: 25 }, updatedAt: 123, }); + + expect(accountQuotaFromReport({ + updatedAt: 123, + quota: { + creditsUsd: { + used: 12.5, + limit: 50, + remaining: 37.5, + percent: 25, + expiresAt: 1e20, + }, + }, + })).toEqual({ + creditsUsd: { used: 12.5, limit: 50, remaining: 37.5, percent: 25 }, + updatedAt: 123, + }); }); test("capacity metadata preserves estimate, raw current quota, recovery percent, and incomplete coverage", () => { diff --git a/src/providers/quota.ts b/src/providers/quota.ts index 63c74b9cd6..39c3539aed 100644 --- a/src/providers/quota.ts +++ b/src/providers/quota.ts @@ -279,7 +279,8 @@ function normalizeResetAt(value: unknown): number | undefined { /** Unix 0 / negative values are sentinels, not reset clocks (Command Code fiveHour.resetAt: 0). */ function epochMillis(value: number): number | undefined { if (!Number.isFinite(value) || value <= 0) return undefined; - return value > 10_000_000_000 ? value : value * 1000; + const milliseconds = value > 10_000_000_000 ? value : value * 1000; + return Number.isFinite(new Date(milliseconds).getTime()) ? milliseconds : undefined; } function toFiniteNumber(value: unknown): number | undefined { diff --git a/tests/command-code-quota.test.ts b/tests/command-code-quota.test.ts index 3e8da6d0d3..477f218570 100644 --- a/tests/command-code-quota.test.ts +++ b/tests/command-code-quota.test.ts @@ -333,13 +333,13 @@ describe("Command Code provider quota", () => { expect(result.reports).toEqual([]); }); - test("a fully exhausted account still reports a zero-remaining credit window", async () => { + test("a fully exhausted account drops an out-of-range subscription expiry", async () => { globalThis.fetch = (async (input: RequestInfo | URL) => { const url = String(input); const body = url.includes("/alpha/whoami") ? {} : url.includes("/alpha/billing/subscriptions") - ? { data: { currentPeriodStart: "2026-08-01T00:00:00.000Z", currentPeriodEnd: "2026-09-01T00:00:00.000Z" } } + ? { data: { currentPeriodStart: "2026-08-01T00:00:00.000Z", currentPeriodEnd: 1e20 } } : url.includes("/alpha/usage/summary") ? { totalCost: 12 } : { @@ -358,7 +358,6 @@ describe("Command Code provider quota", () => { limit: 12, remaining: 0, percent: 100, - expiresAt: Date.parse("2026-09-01T00:00:00.000Z"), }, updatedAt: expect.any(Number), });