fix(auth): clear stale provider error metadata

Clear errorCode, lastErrorType, and lastErrorSource when an
account recovers so provider state returns to a fully clean
active status.

Add a focused regression test for recovered-account cleanup.
This commit is contained in:
Kfir Amar
2026-03-14 22:18:41 +02:00
parent 245243c7e7
commit 9c82b3d4ca
2 changed files with 71 additions and 2 deletions

View File

@@ -572,9 +572,12 @@ export async function markAccountUnavailable(
export async function clearAccountError(connectionId: string, currentConnection: any) {
// Only update if currently has error status
const hasError =
currentConnection.testStatus === "unavailable" ||
(currentConnection.testStatus && currentConnection.testStatus !== "active") ||
currentConnection.lastError ||
currentConnection.rateLimitedUntil;
currentConnection.rateLimitedUntil ||
currentConnection.errorCode ||
currentConnection.lastErrorType ||
currentConnection.lastErrorSource;
if (!hasError) return; // Skip if already clean
@@ -582,6 +585,9 @@ export async function clearAccountError(connectionId: string, currentConnection:
testStatus: "active",
lastError: null,
lastErrorAt: null,
lastErrorType: null,
lastErrorSource: null,
errorCode: null,
rateLimitedUntil: null,
backoffLevel: 0,
});

View File

@@ -0,0 +1,63 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-auth-clear-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const auth = await import("../../src/sse/services/auth.ts");
async function resetStorage() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("clearAccountError clears stale provider error metadata after recovery", async () => {
await resetStorage();
core.getDbInstance().exec('ALTER TABLE provider_connections ADD COLUMN "group" TEXT');
const created = await providersDb.createProviderConnection({
provider: "codex",
authType: "oauth",
email: "recover@example.com",
accessToken: "access",
refreshToken: "refresh",
testStatus: "error",
lastError: "Health check: token refresh failed",
lastErrorType: "token_refresh_failed",
lastErrorSource: "oauth",
errorCode: "refresh_failed",
rateLimitedUntil: new Date(Date.now() + 60_000).toISOString(),
backoffLevel: 2,
});
await auth.clearAccountError(created.id, {
...created,
testStatus: "error",
lastError: "Health check: token refresh failed",
lastErrorType: "token_refresh_failed",
lastErrorSource: "oauth",
errorCode: "refresh_failed",
rateLimitedUntil: new Date(Date.now() + 60_000).toISOString(),
backoffLevel: 2,
});
const updated = await providersDb.getProviderConnectionById(created.id);
assert.equal(updated.testStatus, "active");
assert.equal(updated.lastError, undefined);
assert.equal(updated.lastErrorType, undefined);
assert.equal(updated.lastErrorSource, undefined);
assert.equal(updated.errorCode, undefined);
assert.equal(updated.rateLimitedUntil, undefined);
assert.equal(updated.backoffLevel, 0);
});