mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 12:04:41 +01:00
fix(issues): validate UUID query parameters on list and count endpoints (#17389)
Reject malformed UUID filters (participantAgentId, projectId, workspaceId, executionWorkspaceId, parentId, parentIssueId, descendantOf, createdFromIssueId, labelId) on GET /api/companies/:companyId/issues and /issues/count with a 422 instead of letting Postgres fail the uuid cast with a 500. Fixes PAPERCLIP-BACKEND-4M. Co-Authored-By: Devin Foley <devinfoley@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2 files changed
+121
-20
No files matched your search
@@ -791,6 +791,62 @@ describeEmbeddedPostgres("issue list routes assigneeAgentId filter", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
"projectId",
|
||||
"parentId",
|
||||
"parentIssueId",
|
||||
"workspaceId",
|
||||
"executionWorkspaceId",
|
||||
"descendantOf",
|
||||
"labelId",
|
||||
"participantAgentId",
|
||||
])("returns 422 instead of a DB error for malformed %s filters", async (param) => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: uniqueIssuePrefix(),
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
await seedCloudTenantMember(companyId);
|
||||
|
||||
const app = createApp(companyId);
|
||||
const res = await request(app)
|
||||
.get(`/api/companies/${companyId}/issues`)
|
||||
.query({ status: "todo", [param]: "d", limit: "20" });
|
||||
|
||||
expect(res.status, JSON.stringify(res.body)).toBe(422);
|
||||
expect(res.body).toMatchObject({ error: `${param} must be a UUID` });
|
||||
});
|
||||
|
||||
it.each([
|
||||
"projectId",
|
||||
"parentId",
|
||||
"parentIssueId",
|
||||
"workspaceId",
|
||||
"executionWorkspaceId",
|
||||
"descendantOf",
|
||||
"labelId",
|
||||
"participantAgentId",
|
||||
])("returns 422 from issues/count for malformed %s filters", async (param) => {
|
||||
const companyId = randomUUID();
|
||||
await db.insert(companies).values({
|
||||
id: companyId,
|
||||
name: "Paperclip",
|
||||
issuePrefix: uniqueIssuePrefix(),
|
||||
requireBoardApprovalForNewAgents: false,
|
||||
});
|
||||
await seedCloudTenantMember(companyId);
|
||||
|
||||
const app = createApp(companyId);
|
||||
const res = await request(app)
|
||||
.get(`/api/companies/${companyId}/issues/count`)
|
||||
.query({ attention: "blocked", [param]: "d" });
|
||||
|
||||
expect(res.status, JSON.stringify(res.body)).toBe(422);
|
||||
expect(res.body).toMatchObject({ error: `${param} must be a UUID` });
|
||||
});
|
||||
|
||||
it("returns opt-in live descendant counts for offscreen live descendants only", async () => {
|
||||
const companyId = randomUUID();
|
||||
const otherCompanyId = randomUUID();
|
||||
|
||||
Reference in new issue
Block a user