diff --git a/src/plugin-handlers/tool-config-handler-task-deny.test.ts b/src/plugin-handlers/tool-config-handler-task-deny.test.ts new file mode 100644 index 000000000..8ce3d6bc7 --- /dev/null +++ b/src/plugin-handlers/tool-config-handler-task-deny.test.ts @@ -0,0 +1,100 @@ +/// + +import { describe, expect, it } from "bun:test" +import type { OhMyOpenCodeConfig } from "../config" +import { OhMyOpenCodeConfigSchema } from "../config" +import { applyToolConfig } from "./tool-config-handler" + +type TestAgent = { + permission?: Record +} + +const TASK_DENIED_SUBAGENTS = [ + "librarian", + "explore", + "oracle", + "multimodal-looker", + "metis", + "momus", +] as const + +const TASK_ALLOWED_AGENT_NAMES = [ + "sisyphus", + "atlas", + "hephaestus", + "sisyphus-junior", +] as const + +function createParams(agentNames: readonly string[]): { + readonly config: Record + readonly pluginConfig: OhMyOpenCodeConfig + readonly agentResult: Record +} { + const agentResult: Record = {} + for (const agentName of agentNames) { + agentResult[agentName] = { permission: {} } + } + + return { + config: { tools: {}, permission: {} }, + pluginConfig: OhMyOpenCodeConfigSchema.parse({}), + agentResult, + } +} + +function requirePermission( + agentResult: Record, + agentName: string, +): Record { + const permission = agentResult[agentName]?.permission + if (!permission) { + throw new Error(`Missing permission for ${agentName}`) + } + return permission +} + +describe("applyToolConfig task permission hard denials", () => { + describe("#given read-only and specialist subagents", () => { + describe("#when applying tool config", () => { + for (const agentName of TASK_DENIED_SUBAGENTS) { + it(`#then should explicitly deny task for ${agentName}`, () => { + const params = createParams([agentName]) + + applyToolConfig(params) + + const permission = requirePermission(params.agentResult, agentName) + expect(permission.task).toBe("deny") + }) + } + }) + }) + + describe("#given librarian search permissions", () => { + describe("#when applying tool config", () => { + it("#then should keep grep_app allowed while task is denied", () => { + const params = createParams(["librarian"]) + + applyToolConfig(params) + + const permission = requirePermission(params.agentResult, "librarian") + expect(permission["grep_app_*"]).toBe("allow") + expect(permission.task).toBe("deny") + }) + }) + }) + + describe("#given primary and executor agents", () => { + describe("#when applying tool config", () => { + for (const agentName of TASK_ALLOWED_AGENT_NAMES) { + it(`#then should keep task allowed for ${agentName}`, () => { + const params = createParams([agentName]) + + applyToolConfig(params) + + const permission = requirePermission(params.agentResult, agentName) + expect(permission.task).toBe("allow") + }) + } + }) + }) +}) diff --git a/src/plugin-handlers/tool-config-handler.ts b/src/plugin-handlers/tool-config-handler.ts index f1139f75f..bf07b2261 100644 --- a/src/plugin-handlers/tool-config-handler.ts +++ b/src/plugin-handlers/tool-config-handler.ts @@ -4,6 +4,15 @@ import { isTaskSystemEnabled } from "../shared"; type AgentWithPermission = { permission?: Record }; +const TASK_DENIED_SUBAGENT_KEYS = [ + "librarian", + "explore", + "oracle", + "multimodal-looker", + "metis", + "momus", +] as const; + function getConfigQuestionPermission(): string | null { const configContent = process.env.OPENCODE_CONFIG_CONTENT; if (!configContent) return null; @@ -21,6 +30,12 @@ function agentByKey(agentResult: Record, key: string): AgentWit | undefined; } +function denyTaskForAgent(agentResult: Record, key: string): void { + const agent = agentByKey(agentResult, key); + if (!agent) return; + agent.permission = { ...agent.permission, task: "deny" }; +} + export function applyToolConfig(params: { config: Record; pluginConfig: OhMyOpenCodeConfig; @@ -59,6 +74,10 @@ export function applyToolConfig(params: { isCliRunMode ? "deny" : "allow"; + for (const agentKey of TASK_DENIED_SUBAGENT_KEYS) { + denyTaskForAgent(params.agentResult, agentKey); + } + const librarian = agentByKey(params.agentResult, "librarian"); if (librarian) { librarian.permission = { ...librarian.permission, "grep_app_*": "allow" };