From e455425d2e1e9418a2f01de5e96ff9dbca5370c2 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Sun, 1 Feb 2026 18:01:25 -0800 Subject: [PATCH] fix: return 400 on invalid tag/album payload --- apps/web/app/api/albums/handlers.ts | 10 +++++++++- apps/web/app/api/tags/handlers.ts | 10 +++++++++- apps/web/src/__tests__/albums-admin-auth.test.ts | 8 ++++++++ apps/web/src/__tests__/tags-admin-auth.test.ts | 8 ++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/web/app/api/albums/handlers.ts b/apps/web/app/api/albums/handlers.ts index 441be3c..a98fd62 100644 --- a/apps/web/app/api/albums/handlers.ts +++ b/apps/web/app/api/albums/handlers.ts @@ -61,7 +61,15 @@ export async function handleCreateAlbum(input: { return { status: 401, body: { error: "admin_required" } }; } - const body = createAlbumBodySchema.parse(input.body ?? {}); + const bodyParsed = createAlbumBodySchema.safeParse(input.body ?? {}); + if (!bodyParsed.success) { + return { + status: 400, + body: { error: "invalid_body", issues: bodyParsed.error.issues }, + }; + } + + const body = bodyParsed.data; const db = (input.db ?? getDb()) as DbLike; const rows = await db< { diff --git a/apps/web/app/api/tags/handlers.ts b/apps/web/app/api/tags/handlers.ts index 4c4c2d0..7a81e5c 100644 --- a/apps/web/app/api/tags/handlers.ts +++ b/apps/web/app/api/tags/handlers.ts @@ -50,7 +50,15 @@ export async function handleCreateTag(input: { return { status: 401, body: { error: "admin_required" } }; } - const body = createTagBodySchema.parse(input.body ?? {}); + const bodyParsed = createTagBodySchema.safeParse(input.body ?? {}); + if (!bodyParsed.success) { + return { + status: 400, + body: { error: "invalid_body", issues: bodyParsed.error.issues }, + }; + } + + const body = bodyParsed.data; const db = (input.db ?? getDb()) as DbLike; const rows = await db< { diff --git a/apps/web/src/__tests__/albums-admin-auth.test.ts b/apps/web/src/__tests__/albums-admin-auth.test.ts index 3f78be9..7d32f98 100644 --- a/apps/web/src/__tests__/albums-admin-auth.test.ts +++ b/apps/web/src/__tests__/albums-admin-auth.test.ts @@ -100,6 +100,14 @@ test("albums POST inserts and writes audit log", async () => { ); }); +test("albums POST rejects invalid body", async () => { + const { handleCreateAlbum } = await import("../../app/api/albums/handlers"); + const res = await handleCreateAlbum({ adminOk: true, body: { name: "" } }); + expect(res.status).toBe(400); + expect(res.body).toMatchObject({ error: "invalid_body" }); + expect(Array.isArray((res.body as { issues?: unknown }).issues)).toBe(true); +}); + test("album add asset inserts and writes audit log", async () => { const { handleAddAlbumAsset } = await import( "../../app/api/albums/handlers" diff --git a/apps/web/src/__tests__/tags-admin-auth.test.ts b/apps/web/src/__tests__/tags-admin-auth.test.ts index c88bd48..e74c438 100644 --- a/apps/web/src/__tests__/tags-admin-auth.test.ts +++ b/apps/web/src/__tests__/tags-admin-auth.test.ts @@ -73,3 +73,11 @@ test("tags POST inserts and writes audit log", async () => { true, ); }); + +test("tags POST rejects invalid body", async () => { + const { handleCreateTag } = await import("../../app/api/tags/handlers"); + const res = await handleCreateTag({ adminOk: true, body: { name: "" } }); + expect(res.status).toBe(400); + expect(res.body).toMatchObject({ error: "invalid_body" }); + expect(Array.isArray((res.body as { issues?: unknown }).issues)).toBe(true); +});