mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
fix(quota,i18n): close B26 audit gap on DELETE plan + pt-BR translation
Two gaps found in second-pass code review of Group B: 1. B26 violation: DELETE /api/quota/plans/[connectionId] did not emit logAuditEvent. Per master plan B26, every plan mutation must audit. Now emits quota.plan.updated with metadata.reverted=true to mark the revert-to-auto/catalog semantic. Test integration extended with assertion that audit event is present after DELETE. 2. pt-BR / pt locales had "costsSection": "Costs" (English label) instead of the Portuguese "Custos". Other section labels in the same block are left in English intentionally (analytics, monitoring) — they are project-wide untranslated terms; "Custos" is the established repo translation for the Costs section title. Validation: - npm run typecheck:core: clean - tests/integration/quota-plans-crud.test.ts: 10/10 pass (includes new assertion on DELETE → audit event) - eslint --no-warn-ignored on touched files: clean
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Auth: requireManagementAuth
|
||||
* Zod: PlanUpsertSchema from @/shared/schemas/quota (PUT only)
|
||||
* Audit: quota.plan.updated on PUT (B26)
|
||||
* Audit: quota.plan.updated on PUT and DELETE (B26 — DELETE reverts override to auto/catalog)
|
||||
* Sanitization: all error responses via buildErrorBody (Hard Rule #12, B25)
|
||||
*
|
||||
* For PUT: provider is derived from the connectionId via getProviderConnectionById.
|
||||
@@ -115,9 +115,21 @@ export async function DELETE(request: Request, { params }: RouteParams): Promise
|
||||
|
||||
try {
|
||||
const { connectionId } = await params;
|
||||
// deleteProviderPlan returns true if a row was deleted, false if not found
|
||||
// We return 204 either way (idempotent delete)
|
||||
|
||||
const existing = getProviderPlan(connectionId);
|
||||
const provider = existing?.provider ?? (await resolveProvider(connectionId));
|
||||
|
||||
deleteProviderPlan(connectionId);
|
||||
|
||||
const ctx = getAuditRequestContext(request);
|
||||
logAuditEvent({
|
||||
action: "quota.plan.updated",
|
||||
target: connectionId,
|
||||
metadata: { provider, source: "auto", reverted: true },
|
||||
ipAddress: ctx.ipAddress ?? undefined,
|
||||
requestId: ctx.requestId,
|
||||
});
|
||||
|
||||
return new Response(null, { status: 204 });
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "Failed to delete plan";
|
||||
|
||||
@@ -819,7 +819,7 @@
|
||||
"agentsAiSection": "Agents & AI",
|
||||
"cacheContextSection": "Cache & Context",
|
||||
"analyticsSection": "Analytics",
|
||||
"costsSection": "Costs",
|
||||
"costsSection": "Custos",
|
||||
"monitoringSection": "Monitoring",
|
||||
"auditSecuritySection": "Audit & Security",
|
||||
"devtoolsSection": "Dev Tools",
|
||||
|
||||
@@ -819,7 +819,7 @@
|
||||
"agentsAiSection": "Agents & AI",
|
||||
"cacheContextSection": "Cache & Context",
|
||||
"analyticsSection": "Analytics",
|
||||
"costsSection": "Costs",
|
||||
"costsSection": "Custos",
|
||||
"monitoringSection": "Monitoring",
|
||||
"auditSecuritySection": "Audit & Security",
|
||||
"devtoolsSection": "Dev Tools",
|
||||
|
||||
@@ -238,6 +238,19 @@ test("DELETE /api/quota/plans/[connectionId] clears override → 204; GET revert
|
||||
// After delete, should fall back to catalog or empty (source=auto or manual-empty)
|
||||
// For a connectionId with no catalog match, source=manual + dimensions=[]
|
||||
assert.ok(["auto", "manual"].includes(body.plan.source));
|
||||
|
||||
// B26: DELETE must emit logAuditEvent with quota.plan.updated + metadata.reverted=true
|
||||
const logs = compliance.getAuditLog({ action: "quota.plan.updated", limit: 20 });
|
||||
const events = Array.isArray(logs) ? logs : [];
|
||||
const deleteEvt = events.find(
|
||||
(e) =>
|
||||
typeof e === "object" &&
|
||||
e !== null &&
|
||||
(e as Record<string, unknown>).action === "quota.plan.updated" &&
|
||||
(e as Record<string, unknown>).target === connectionId &&
|
||||
(e as { metadata?: { reverted?: boolean } }).metadata?.reverted === true
|
||||
);
|
||||
assert.ok(deleteEvt, "quota.plan.updated audit event (reverted=true) must be present after DELETE");
|
||||
});
|
||||
|
||||
test("DELETE /api/quota/plans/[connectionId] is idempotent → 204 even when not found", async () => {
|
||||
|
||||
Reference in New Issue
Block a user