fix(KB-090): improve refinement route validation with trimmed feedback
- Trim whitespace from feedback before length validation - Catch whitespace-only input at route level before store call - Update test to verify route-level validation blocks empty feedback - Use trimmed feedback for store operations and logging
This commit is contained in:
@@ -573,15 +573,15 @@ describe("POST /tasks/:id/refine", () => {
|
|||||||
expect(res.body.error).toContain("not found");
|
expect(res.body.error).toContain("not found");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 400 when feedback is whitespace only (rejected by store)", async () => {
|
it("returns 400 when feedback is whitespace only (caught at validation)", async () => {
|
||||||
(store.refineTask as ReturnType<typeof vi.fn>).mockRejectedValue(new Error("Feedback is required and cannot be empty"));
|
// Route-level validation now catches whitespace-only input before it reaches the store
|
||||||
|
|
||||||
const res = await REQUEST(buildApp(), "POST", "/api/tasks/KB-001/refine", JSON.stringify({ feedback: " " }), {
|
const res = await REQUEST(buildApp(), "POST", "/api/tasks/KB-001/refine", JSON.stringify({ feedback: " " }), {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.status).toBe(400);
|
expect(res.status).toBe(400);
|
||||||
expect(res.body.error).toContain("Feedback is required");
|
expect(res.body.error).toContain("feedback must be between 1 and 2000 characters");
|
||||||
|
expect(store.refineTask).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 500 on unexpected errors", async () => {
|
it("returns 500 on unexpected errors", async () => {
|
||||||
|
|||||||
@@ -722,13 +722,15 @@ export function createApiRoutes(store: TaskStore, options?: ServerOptions): Rout
|
|||||||
res.status(400).json({ error: "feedback is required and must be a string" });
|
res.status(400).json({ error: "feedback is required and must be a string" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (feedback.length === 0 || feedback.length > 2000) {
|
// Trim before checking length to catch whitespace-only input
|
||||||
|
const trimmedFeedback = feedback.trim();
|
||||||
|
if (trimmedFeedback.length === 0 || trimmedFeedback.length > 2000) {
|
||||||
res.status(400).json({ error: "feedback must be between 1 and 2000 characters" });
|
res.status(400).json({ error: "feedback must be between 1 and 2000 characters" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const refinedTask = await store.refineTask(req.params.id, feedback);
|
const refinedTask = await store.refineTask(req.params.id, trimmedFeedback);
|
||||||
await store.logEntry(req.params.id, "Refinement requested", feedback);
|
await store.logEntry(req.params.id, "Refinement requested", trimmedFeedback);
|
||||||
res.status(201).json(refinedTask);
|
res.status(201).json(refinedTask);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const status = err.code === "ENOENT" ? 404
|
const status = err.code === "ENOENT" ? 404
|
||||||
|
|||||||
Reference in New Issue
Block a user