fix(quota): await getQuotaStore() in enforce — quota never enforced/recorded (fail-open)

getQuotaStore() is async; enforce.ts used it without await, so store was a Promise
and store.peek/store.consume threw 'not a function' → enforceQuotaShare failed open
on every request and recordConsumption never wrote. Production quota was a silent
no-op (unit tests passed because they inject a sync mock store). Await it + guard.
This commit is contained in:
diegosouzapw
2026-05-31 17:20:10 -03:00
parent 10fa5e8903
commit be77a03aa0
2 changed files with 34 additions and 2 deletions

View File

@@ -103,7 +103,7 @@ export async function enforceQuotaShare(input: EnforceInput): Promise<EnforceDec
: 1;
// 4. For each active dimension, peek consumption and saturation.
const store = getQuotaStore();
const store = await getQuotaStore();
const dimensionsInfo: Array<{
key: { poolId: string; unit: QuotaUnit; window: import("./dimensions").QuotaWindow };
limit: number;
@@ -218,7 +218,7 @@ export async function recordConsumption(input: RecordConsumptionInput): Promise<
const plan = resolvePlan(input.connectionId, input.provider);
if (!plan.dimensions.length) return;
const store = getQuotaStore();
const store = await getQuotaStore();
for (const dim of plan.dimensions) {
const dimKey = { poolId, unit: dim.unit, window: dim.window };
const cost = costForUnit(input.cost, dim.unit);

View File

@@ -0,0 +1,32 @@
/**
* Regression: getQuotaStore() is async (returns Promise<QuotaStore>). enforce.ts
* called it WITHOUT await, so `store` was a Promise and `store.peek` / `store.consume`
* threw "peek is not a function" → enforceQuotaShare failed open on EVERY request and
* recordConsumption never recorded. The existing enforce unit tests inject a sync mock
* store, so they passed while production was a no-op. This guard asserts every
* getQuotaStore() call in enforce.ts is awaited.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
test("enforce.ts awaits every getQuotaStore() call (it is async)", () => {
const p = join(
fileURLToPath(import.meta.url),
"..",
"..",
"..",
"src/lib/quota/enforce.ts"
);
const src = readFileSync(p, "utf8");
const totalCalls = (src.match(/getQuotaStore\(\)/g) || []).length;
const awaitedCalls = (src.match(/await\s+getQuotaStore\(\)/g) || []).length;
assert.ok(totalCalls > 0, "expected enforce.ts to call getQuotaStore()");
assert.equal(
awaitedCalls,
totalCalls,
`every getQuotaStore() must be awaited — found ${totalCalls} call(s), ${awaitedCalls} awaited`
);
});