fix(agent-teams): add strict identifier validation rules

This commit is contained in:
Nguyen Khac Trung Kien
2026-02-08 08:53:54 +07:00
committed by YeonGyu-Kim
parent db08cc22cc
commit f4e4fdb2e4
4 changed files with 78 additions and 2 deletions

View File

@@ -1,6 +1,11 @@
/// <reference types="bun-types" />
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", () => {
test("accepts valid team names", () => {
@@ -55,4 +60,19 @@ describe("agent-teams name validation", () => {
expect(validResult).toBeNull()
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")
})
})

View File

@@ -1,5 +1,7 @@
const VALID_NAME_RE = /^[A-Za-z0-9_-]+$/
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 {
if (!value || !value.trim()) {
@@ -27,3 +29,26 @@ export function validateAgentName(agentName: string): string | null {
}
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
}

View 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)
})
})

View File

@@ -27,7 +27,9 @@ export const TeamLeadMemberSchema = z.object({
export const TeamTeammateMemberSchema = z.object({
agentId: z.string(),
name: z.string(),
agentType: z.string(),
agentType: z.string().refine((value) => value !== "team-lead", {
message: "agent_type_reserved",
}),
model: z.string(),
prompt: z.string(),
color: z.string(),