mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
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:
@@ -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);
|
||||
|
||||
32
tests/unit/quota-enforce-await-store.test.ts
Normal file
32
tests/unit/quota-enforce-await-store.test.ts
Normal 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`
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user