fix: resolve TODO.md security/perf/test-coverage backlog

Fixes the 13-item codebase health scan backlog: wraps meal-plan
generation in a transaction, adds missing userId/GIN indexes, fixes
an IPv6-parsing gap in the webhook SSRF guard (and an identical
duplicated bug in the AI URL-import path, now consolidated onto one
implementation), paginates the collections list, dedupes the AI
recipe Zod schemas, wires up Stripe tier sync, rate-limits AI key
rotation, gets `pnpm typecheck` actually working, and adds test
coverage for the previously-untested admin/webhooks routes.

Two flagged issues (collection removeRecipeId IDOR, tier-limit race)
turned out to already be fixed/non-issues on inspection — noted in
TODO.md rather than silently dropped.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-02 12:12:42 +02:00
parent 2154512e54
commit d2faf98ac1
38 changed files with 7598 additions and 315 deletions
@@ -0,0 +1,92 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { NextRequest } from "next/server";
const mockSession = { user: { id: "user-1" } };
vi.mock("@/lib/api-auth", () => ({
requireSession: vi.fn(),
}));
vi.mock("@/lib/webhooks", () => ({
dispatchWebhook: vi.fn().mockResolvedValue(undefined),
}));
const { mockWebhookFindFirst, mockDeliveryFindFirst } = vi.hoisted(() => ({
mockWebhookFindFirst: vi.fn(),
mockDeliveryFindFirst: vi.fn(),
}));
vi.mock("@epicure/db", () => ({
db: {
query: {
webhooks: { findFirst: mockWebhookFindFirst },
webhookDeliveries: { findFirst: mockDeliveryFindFirst },
},
},
webhooks: { id: "id", userId: "user_id" },
webhookDeliveries: { id: "id", webhookId: "webhook_id" },
eq: vi.fn((a, b) => ({ a, b, op: "eq" })),
and: vi.fn((...args) => ({ args, op: "and" })),
}));
const { requireSession } = await import("@/lib/api-auth");
const { dispatchWebhook } = await import("@/lib/webhooks");
import { POST } from "../route";
const VALID_DELIVERY_ID = "11111111-1111-1111-1111-111111111111";
function makeRequest(body?: unknown) {
return new NextRequest("http://localhost/api/v1/webhooks/wh-1/redeliver", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: body ? JSON.stringify(body) : undefined,
});
}
const ctx = { params: Promise.resolve({ id: "wh-1" }) };
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(requireSession).mockResolvedValue({ session: mockSession as never, response: null });
mockWebhookFindFirst.mockResolvedValue({ id: "wh-1" });
mockDeliveryFindFirst.mockResolvedValue({
id: VALID_DELIVERY_ID,
event: "recipe.created",
payload: { recipeId: "r-1" },
});
});
describe("POST /api/v1/webhooks/[id]/redeliver", () => {
it("returns 401 when not authenticated", async () => {
vi.mocked(requireSession).mockResolvedValue({
session: null,
response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 }),
} as never);
const res = await POST(makeRequest({ deliveryId: VALID_DELIVERY_ID }), ctx);
expect(res.status).toBe(401);
});
it("returns 404 when the webhook does not belong to the caller", async () => {
mockWebhookFindFirst.mockResolvedValue(undefined);
const res = await POST(makeRequest({ deliveryId: VALID_DELIVERY_ID }), ctx);
expect(res.status).toBe(404);
});
it("returns 400 when deliveryId is not a valid UUID", async () => {
const res = await POST(makeRequest({ deliveryId: "not-a-uuid" }), ctx);
expect(res.status).toBe(400);
});
it("returns 404 when the delivery is not found", async () => {
mockDeliveryFindFirst.mockResolvedValue(undefined);
const res = await POST(makeRequest({ deliveryId: VALID_DELIVERY_ID }), ctx);
expect(res.status).toBe(404);
});
it("replays the delivery payload via dispatchWebhook", async () => {
const res = await POST(makeRequest({ deliveryId: VALID_DELIVERY_ID }), ctx);
expect(res.status).toBe(200);
expect(dispatchWebhook).toHaveBeenCalledWith("user-1", "recipe.created", { recipeId: "r-1" });
});
});