fix(vscode): validate Ollama quota responses consistently

Share the Ollama request and parser between credential validation and quota refresh so unparseable pages cannot produce successful empty usage. Reject redirects and bound requests with a timeout while preserving both plan formats.

Tested with 94 quota tests, VS Code type-check and ESLint, and the extension build. Reviewed dead-code output; existing anti-slop findings remain outside the changed code.
This commit is contained in:
Bohdan Triapitsyn
2026-09-07 19:41:40 +03:00
parent c9bef8bc05
commit ab7ee73992
5 changed files with 182 additions and 95 deletions
+3 -5
View File
@@ -3,6 +3,7 @@ import os from 'node:os';
import path from 'node:path';
import { execFileSync } from 'node:child_process';
import { fetchExeDevUsage } from './exeDevQuota';
import { fetchOllamaUsage } from './ollamaQuota';
export type ManagedProvider = 'exe-dev' | 'ollama-cloud' | 'cursor';
export type ManagedCredential = Record<string, string>;
@@ -53,13 +54,10 @@ export const importCursorCredential = () => {
return credential;
};
export const validateCredential = async (provider: ManagedProvider, credential: ManagedCredential) => {
export const validateCredential = async (provider: ManagedProvider, credential: ManagedCredential, fetchImpl: (url: string, init: RequestInit) => Promise<Response> = fetch) => {
if (provider === 'exe-dev') await fetchExeDevUsage(credential.usageToken);
if (provider === 'ollama-cloud') {
const response = await fetch('https://ollama.com/settings', { headers: { Cookie: credential.cookie }, redirect: 'manual', signal: AbortSignal.timeout(15_000) });
if (!response.ok || (response.status >= 300 && response.status < 400)) throw new Error('Ollama Cloud authentication failed');
const html = await response.text();
if (!/Session\s+usage|Weekly\s+usage|Premium[^0-9]*[0-9]+\s*\/\s*[0-9]+|Monthly\s+usage/i.test(html)) throw new Error('Ollama Cloud usage data could not be parsed');
await fetchOllamaUsage(credential.cookie, fetchImpl);
}
if (provider === 'cursor') {
if (!credential.accessToken && credential.refreshToken) {