diff --git a/apps/api/src/tools/task-board/automations.test.ts b/apps/api/src/tools/task-board/automations.test.ts new file mode 100644 index 0000000000..241013c783 --- /dev/null +++ b/apps/api/src/tools/task-board/automations.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "bun:test"; +import { TASK_BOARD_AUTOMATION_UPSERT } from "./automations"; + +/** + * Regression: `prompt` had no length cap — an unbounded `text` column, + * writable directly by any org member's tool call. Same gap as the task + * description cap (#6574's sibling), just on the automation's instruction. + */ +describe("TASK_BOARD_AUTOMATION_UPSERT prompt length", () => { + it("rejects a prompt over the cap", () => { + const result = TASK_BOARD_AUTOMATION_UPSERT.inputSchema.safeParse({ + columnKey: "todo", + prompt: "x".repeat(50_001), + }); + expect(result.success).toBe(false); + }); + + it("accepts a prompt at the cap", () => { + const result = TASK_BOARD_AUTOMATION_UPSERT.inputSchema.safeParse({ + columnKey: "todo", + prompt: "x".repeat(50_000), + }); + expect(result.success).toBe(true); + }); + + it("accepts a null prompt (the default instruction)", () => { + const result = TASK_BOARD_AUTOMATION_UPSERT.inputSchema.safeParse({ + columnKey: "todo", + prompt: null, + }); + expect(result.success).toBe(true); + }); +}); diff --git a/apps/api/src/tools/task-board/automations.ts b/apps/api/src/tools/task-board/automations.ts index d3560d1de0..326c3f1c54 100644 --- a/apps/api/src/tools/task-board/automations.ts +++ b/apps/api/src/tools/task-board/automations.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { defineTool } from "@/core/define-tool"; import { requireAuth } from "@/core/studio-context"; import { boardHandler } from "./board-handler"; +import { MAX_AUTOMATION_PROMPT_LENGTH } from "./schema"; const AutomationSchema = z.object({ columnKey: z.string(), @@ -46,6 +47,7 @@ export const TASK_BOARD_AUTOMATION_UPSERT = defineTool({ .describe("A column of this board — see TASK_BOARD_ITEM_LIST."), prompt: z .string() + .max(MAX_AUTOMATION_PROMPT_LENGTH) .nullable() .optional() .describe("What to do with a card landing here; null for the default."), diff --git a/apps/api/src/tools/task-board/schema.ts b/apps/api/src/tools/task-board/schema.ts index ceb8721067..07d11e91f7 100644 --- a/apps/api/src/tools/task-board/schema.ts +++ b/apps/api/src/tools/task-board/schema.ts @@ -16,6 +16,10 @@ export const MAX_TASK_TITLE_LENGTH = 500; * so nothing legitimate approaches this; same reasoning as the caps above. */ export const MAX_TASK_REPO_LENGTH = 200; +/** A column automation's prompt is an instruction, not the message body — + * same reasoning as MAX_TASK_DESCRIPTION_LENGTH. */ +export const MAX_AUTOMATION_PROMPT_LENGTH = 50_000; + export const TaskBoardItemStatusSchema = z.enum([ "triage", "todo",