Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions src/agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,14 @@ describe("AgentConfigSchema", () => {
expect(result.success).toBe(true)
})

test("allows unknown fields via passthrough", () => {
test("rejects unknown fields (strict mode — prevents config injection)", () => {
const config = {
description: "Test",
customField: "custom value",
anotherCustom: 123,
}
const result = AgentConfigSchema.safeParse(config)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.customField).toBe("custom value")
expect(result.data.anotherCustom).toBe(123)
}
expect(result.success).toBe(false)
})
})

Expand Down Expand Up @@ -234,4 +230,29 @@ You follow best practices.`,
expect(result.success).toBe(true)
})
})

describe("strict mode — rejects unknown fields", () => {
test("rejects unknown top-level fields", () => {
const result = AgentConfigSchema.safeParse({
description: "hi",
mode: "subagent",
evil_field: "nope",
})
expect(result.success).toBe(false)
})

test("accepts all documented fields", () => {
const result = AgentConfigSchema.safeParse({
description: "a",
mode: "subagent",
model: "anthropic/claude-3-5-sonnet",
temperature: 0.7,
top_p: 0.9,
color: "#FF5733",
tools: { bash: true, edit: false },
disable: false,
})
expect(result.success).toBe(true)
})
})
})
6 changes: 3 additions & 3 deletions src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export const AgentConfigSchema = z.object({
description: z.string().optional(),
/** Agent mode: subagent, primary, or all */
mode: z.enum(["subagent", "primary", "all"]).optional(),
/** Additional options passed to the agent */
options: z.record(z.string(), z.any()).optional(),
/** Additional options passed to the agent — keys and values must be strings */
options: z.record(z.string(), z.string()).optional(),
/** Hex color code for the agent (e.g., #FF5733) */
color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
/** Maximum number of agentic iterations */
Expand All @@ -54,7 +54,7 @@ export const AgentConfigSchema = z.object({
maxSteps: z.number().int().positive().optional(),
/** Permission configuration for tools */
permission: Permission.optional(),
}).passthrough() // Allow unknown keys for forward compatibility
}).strict() // Reject unknown keys — prevents config injection from malicious repos

export type AgentConfig = z.infer<typeof AgentConfigSchema>

Expand Down