fix(agent-teams): add strict identifier validation rules
This commit is contained in:
parent
db08cc22cc
commit
f4e4fdb2e4
@ -1,6 +1,11 @@
|
|||||||
/// <reference types="bun-types" />
|
/// <reference types="bun-types" />
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { validateAgentName, validateTeamName } from "./name-validation"
|
import {
|
||||||
|
validateAgentName,
|
||||||
|
validateAgentNameOrLead,
|
||||||
|
validateTaskId,
|
||||||
|
validateTeamName,
|
||||||
|
} from "./name-validation"
|
||||||
|
|
||||||
describe("agent-teams name validation", () => {
|
describe("agent-teams name validation", () => {
|
||||||
test("accepts valid team names", () => {
|
test("accepts valid team names", () => {
|
||||||
@ -55,4 +60,19 @@ describe("agent-teams name validation", () => {
|
|||||||
expect(validResult).toBeNull()
|
expect(validResult).toBeNull()
|
||||||
expect(invalidResult).toBe("agent_name_invalid")
|
expect(invalidResult).toBe("agent_name_invalid")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("allows team-lead for inbox-compatible validation", () => {
|
||||||
|
//#then
|
||||||
|
expect(validateAgentNameOrLead("team-lead")).toBeNull()
|
||||||
|
expect(validateAgentNameOrLead("worker_1")).toBeNull()
|
||||||
|
expect(validateAgentNameOrLead("worker one")).toBe("agent_name_invalid")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("validates task ids", () => {
|
||||||
|
//#then
|
||||||
|
expect(validateTaskId("T-123")).toBeNull()
|
||||||
|
expect(validateTaskId("")).toBe("task_id_required")
|
||||||
|
expect(validateTaskId("../../etc/passwd")).toBe("task_id_invalid")
|
||||||
|
expect(validateTaskId("a".repeat(129))).toBe("task_id_too_long")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
const VALID_NAME_RE = /^[A-Za-z0-9_-]+$/
|
const VALID_NAME_RE = /^[A-Za-z0-9_-]+$/
|
||||||
const MAX_NAME_LENGTH = 64
|
const MAX_NAME_LENGTH = 64
|
||||||
|
const VALID_TASK_ID_RE = /^[A-Za-z0-9_-]+$/
|
||||||
|
const MAX_TASK_ID_LENGTH = 128
|
||||||
|
|
||||||
function validateName(value: string, label: "team" | "agent"): string | null {
|
function validateName(value: string, label: "team" | "agent"): string | null {
|
||||||
if (!value || !value.trim()) {
|
if (!value || !value.trim()) {
|
||||||
@ -27,3 +29,26 @@ export function validateAgentName(agentName: string): string | null {
|
|||||||
}
|
}
|
||||||
return validateName(agentName, "agent")
|
return validateName(agentName, "agent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function validateAgentNameOrLead(agentName: string): string | null {
|
||||||
|
if (agentName === "team-lead") {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return validateName(agentName, "agent")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateTaskId(taskId: string): string | null {
|
||||||
|
if (!taskId || !taskId.trim()) {
|
||||||
|
return "task_id_required"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!VALID_TASK_ID_RE.test(taskId)) {
|
||||||
|
return "task_id_invalid"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taskId.length > MAX_TASK_ID_LENGTH) {
|
||||||
|
return "task_id_too_long"
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|||||||
29
src/tools/agent-teams/types.test.ts
Normal file
29
src/tools/agent-teams/types.test.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/// <reference types="bun-types" />
|
||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import { TeamTeammateMemberSchema } from "./types"
|
||||||
|
|
||||||
|
describe("agent-teams types", () => {
|
||||||
|
test("rejects reserved agentType for teammate schema", () => {
|
||||||
|
//#given
|
||||||
|
const invalidTeammate = {
|
||||||
|
agentId: "worker@team",
|
||||||
|
name: "worker",
|
||||||
|
agentType: "team-lead",
|
||||||
|
model: "native",
|
||||||
|
prompt: "do work",
|
||||||
|
color: "blue",
|
||||||
|
planModeRequired: false,
|
||||||
|
joinedAt: Date.now(),
|
||||||
|
cwd: "/tmp",
|
||||||
|
subscriptions: [],
|
||||||
|
backendType: "native",
|
||||||
|
isActive: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = TeamTeammateMemberSchema.safeParse(invalidTeammate)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -27,7 +27,9 @@ export const TeamLeadMemberSchema = z.object({
|
|||||||
export const TeamTeammateMemberSchema = z.object({
|
export const TeamTeammateMemberSchema = z.object({
|
||||||
agentId: z.string(),
|
agentId: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
agentType: z.string(),
|
agentType: z.string().refine((value) => value !== "team-lead", {
|
||||||
|
message: "agent_type_reserved",
|
||||||
|
}),
|
||||||
model: z.string(),
|
model: z.string(),
|
||||||
prompt: z.string(),
|
prompt: z.string(),
|
||||||
color: z.string(),
|
color: z.string(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user