From 910693e952775ca96f595cc0f1242fbc5e2e1360 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Wed, 19 Aug 2026 22:39:46 -0400 Subject: [PATCH] Refuse an empty vault-import body as a 400, and cover a non-backup body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without the explicit length check, parseBackupWrapper's JSON failure on an empty body escapes as an internal error — the server reporting a fault for a request the caller simply sent empty. Also pins that a body which is not a backup at all answers 4xx rather than 5xx, since the two failures take different paths and only one of them was exercised. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Vtx94nXDmNgXEeThUZP4QN --- js/packages/cli/test/api.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/js/packages/cli/test/api.test.ts b/js/packages/cli/test/api.test.ts index b4249184..2d2c06af 100644 --- a/js/packages/cli/test/api.test.ts +++ b/js/packages/cli/test/api.test.ts @@ -1041,6 +1041,25 @@ describe("vault export and import", () => { }); expect(refused.status).toBe(409); expect(refused.json.detail).toContain("belongs to profile"); + + // An empty body is a caller mistake, not a server fault. Without the + // explicit check, parseBackupWrapper's JSON error escapes as 500. + const empty = await call("POST", "/api/v1/vault/import", { + password: PASSWORD, + raw: "", + headers: { "content-type": "application/json" }, + }); + expect(empty.status).toBe(400); + expect(empty.json.detail).toContain("backup body is required"); + + // As is a body that is not a backup at all. + const garbage = await call("POST", "/api/v1/vault/import", { + password: PASSWORD, + raw: "{not a backup}", + headers: { "content-type": "application/json" }, + }); + expect(garbage.status).toBeGreaterThanOrEqual(400); + expect(garbage.status).toBeLessThan(500); }); });