feat(FN-3976): reclassify github import action gating
Completes FN-3976 by reclassifying GitHub import action gating in the engine's `gating-classifications.ts`, updating documentation in `docs/agents.md` accordingly, and adding test coverage across four gating test suites. Fusion-Task-Id: FN-3976
This commit is contained in:
@@ -116,6 +116,8 @@ describe("agent-action-gate", () => {
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_task_add_dep", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("task_agent_mutation");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_delegate_task", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("exempt");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_update_agent_config", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("task_agent_mutation");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_task_import_github", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("task_agent_mutation");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_task_import_github_issue", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("task_agent_mutation");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_update_identity", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("exempt");
|
||||
expect(evaluateAgentActionGate({ agentId: "a1", toolName: "fn_spawn_agent", args: {}, permissionPolicy: unrestrictedPolicy }).category).toBe("task_agent_mutation");
|
||||
});
|
||||
|
||||
@@ -17,4 +17,13 @@ describe("gating classifications provisioning split", () => {
|
||||
expect(TASK_AGENT_MUTATION_TOOLS.has("fn_agent_create")).toBe(true);
|
||||
expect(TASK_AGENT_MUTATION_TOOLS.has("fn_agent_delete")).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies github task imports as action-gated task mutations only", () => {
|
||||
expect(ACTION_GATE_TASK_AGENT_MANAGEMENT_TOOLS.has("fn_task_import_github")).toBe(true);
|
||||
expect(ACTION_GATE_TASK_AGENT_MANAGEMENT_TOOLS.has("fn_task_import_github_issue")).toBe(true);
|
||||
expect(PERMANENT_AGENT_TASK_MUTATION_TOOLS.has("fn_task_import_github")).toBe(false);
|
||||
expect(PERMANENT_AGENT_TASK_MUTATION_TOOLS.has("fn_task_import_github_issue")).toBe(false);
|
||||
expect(TASK_AGENT_MUTATION_TOOLS.has("fn_task_import_github")).toBe(true);
|
||||
expect(TASK_AGENT_MUTATION_TOOLS.has("fn_task_import_github_issue")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,6 +56,11 @@ const gitCases = [
|
||||
["echo hi\ngit checkout -b t", true, "git checkout -b"],
|
||||
] as const;
|
||||
|
||||
const ACTION_MUTATION_PERMANENT_READONLY_TOOLS = new Set([
|
||||
"fn_task_import_github",
|
||||
"fn_task_import_github_issue",
|
||||
]);
|
||||
|
||||
describe("gating-classifications parity", () => {
|
||||
it("locks coordination exempt membership", () => {
|
||||
expect([...COORDINATION_EXEMPT_TOOLS].sort()).toMatchInlineSnapshot(`
|
||||
@@ -151,6 +156,10 @@ describe("gating-classifications parity", () => {
|
||||
expect({ toolName, actionKind, permanentKind }).toEqual({ toolName, actionKind: "readonly", permanentKind: "mutating" });
|
||||
continue;
|
||||
}
|
||||
if (ACTION_MUTATION_PERMANENT_READONLY_TOOLS.has(toolName)) {
|
||||
expect({ toolName, actionKind, permanentKind }).toEqual({ toolName, actionKind: "mutating", permanentKind: "readonly" });
|
||||
continue;
|
||||
}
|
||||
|
||||
expect({ toolName, actionKind, permanentKind }).toEqual({ toolName, actionKind: permanentKind, permanentKind });
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ describe("permanent-agent-gating", () => {
|
||||
expect(classifyPermanentAgentToolCall("fn_task_create").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_delegate_task").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_update_agent_config").category).toBe("task_agent_mutation");
|
||||
expect(classifyPermanentAgentToolCall("fn_task_import_github").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_task_import_github_issue").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_update_identity").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_task_document_write").category).toBe("none");
|
||||
expect(classifyPermanentAgentToolCall("fn_memory_append").category).toBe("none");
|
||||
|
||||
@@ -7,7 +7,13 @@ export const FILE_WRITE_BUILTIN_TOOLS: ReadonlySet<string> = new Set(["write", "
|
||||
const SHARED_TASK_AGENT_TOOLS = ["fn_task_add_dep", "fn_spawn_agent", "fn_update_agent_config", "fn_agent_create", "fn_agent_delete"] as const;
|
||||
const PROVISIONING_TOOLS = ["fn_agent_create", "fn_agent_delete"] as const;
|
||||
|
||||
const ACTION_GATE_TASK_AGENT_ONLY_TOOLS = ["fn_task_create", "fn_delegate_task", "fn_update_identity"] as const;
|
||||
const ACTION_GATE_TASK_AGENT_ONLY_TOOLS = [
|
||||
"fn_task_create",
|
||||
"fn_delegate_task",
|
||||
"fn_task_import_github",
|
||||
"fn_task_import_github_issue",
|
||||
"fn_update_identity",
|
||||
] as const;
|
||||
const ACTION_GATE_SHARED_TASK_AGENT_TOOLS = SHARED_TASK_AGENT_TOOLS.filter(
|
||||
(tool) => !(PROVISIONING_TOOLS as readonly string[]).includes(tool),
|
||||
);
|
||||
@@ -20,8 +26,6 @@ const PERMANENT_TASK_AGENT_ONLY_TOOLS = [
|
||||
"fn_task_archive",
|
||||
"fn_task_unarchive",
|
||||
"fn_task_delete",
|
||||
"fn_task_import_github",
|
||||
"fn_task_import_github_issue",
|
||||
"fn_task_plan",
|
||||
"fn_mission_create",
|
||||
"fn_mission_delete",
|
||||
@@ -69,6 +73,8 @@ export const READONLY_FN_TOOLS: ReadonlySet<string> = new Set([
|
||||
"fn_task_document_write",
|
||||
"fn_task_document_read",
|
||||
"fn_delegate_task",
|
||||
"fn_task_import_github",
|
||||
"fn_task_import_github_issue",
|
||||
"fn_research_list",
|
||||
"fn_research_get",
|
||||
"fn_insight_list",
|
||||
|
||||
Reference in New Issue
Block a user