test(FN-4603): complete Step 3 — cover web fetch network_api gating

Fusion-Task-Id: FN-4603
Fusion-Task-Lineage: c74085e2-d91c-468f-883b-5c33818e53fd
This commit is contained in:
Fusion
2026-05-15 07:32:29 -07:00
committed by gsxdsm
parent d26b89c767
commit 73b5e70a40
2 changed files with 36 additions and 4 deletions

View File

@@ -17,16 +17,42 @@ describe("agent action gate project-default resolution", () => {
evaluateAgentActionGate({ agentId: "a1", toolName: "bash", args: { command: "git commit -m x" }, permissionPolicy }), evaluateAgentActionGate({ agentId: "a1", toolName: "bash", args: { command: "git commit -m x" }, permissionPolicy }),
evaluateAgentActionGate({ agentId: "a1", toolName: "write", args: { path: "x.ts", content: "x" }, permissionPolicy }), evaluateAgentActionGate({ agentId: "a1", toolName: "write", args: { path: "x.ts", content: "x" }, permissionPolicy }),
evaluateAgentActionGate({ agentId: "a1", toolName: "bash", args: { command: "pnpm test" }, permissionPolicy }), evaluateAgentActionGate({ agentId: "a1", toolName: "bash", args: { command: "pnpm test" }, permissionPolicy }),
evaluateAgentActionGate({ agentId: "a1", toolName: "fn_web_fetch", args: { url: "https://example.com" }, permissionPolicy }),
evaluateAgentActionGate({ agentId: "a1", toolName: "fn_task_add_dep", args: { task_id: "FN-1" }, permissionPolicy }), evaluateAgentActionGate({ agentId: "a1", toolName: "fn_task_add_dep", args: { task_id: "FN-1" }, permissionPolicy }),
]; ];
for (const decision of decisions) { for (const decision of decisions) {
if (decision.category === "exempt") {
continue;
}
expect(decision.disposition).toBe("require-approval"); expect(decision.disposition).toBe("require-approval");
} }
const webFetchDecision = evaluateAgentActionGate({
agentId: "a1",
toolName: "fn_web_fetch",
args: { url: "https://example.com" },
permissionPolicy,
});
expect(webFetchDecision.category).toBe("network_api");
expect(webFetchDecision.disposition).toBe("require-approval");
});
it.each([
["allow", "allow"],
["block", "block"],
["require-approval", "require-approval"],
] as const)("routes fn_web_fetch through network_api policy (%s)", (networkDisposition, expected) => {
const permissionPolicy = resolveEffectiveAgentPermissionPolicy(undefined, {
rules: { network_api: networkDisposition },
});
const decision = evaluateAgentActionGate({
agentId: "a1",
toolName: "fn_web_fetch",
args: { url: "https://example.com" },
permissionPolicy,
});
expect(decision.category).toBe("network_api");
expect(decision.disposition).toBe(expected);
}); });
it("keeps per-agent custom rule over project default", () => { it("keeps per-agent custom rule over project default", () => {

View File

@@ -106,6 +106,12 @@ describe("gating-classifications parity", () => {
} }
}); });
it("classifies fn_web_fetch as network_api in both action and permanent sets", () => {
expect(ACTION_GATE_NETWORK_API_TOOLS.has("fn_web_fetch")).toBe(true);
expect(NETWORK_API_TOOLS.has("fn_web_fetch")).toBe(true);
expect(COORDINATION_EXEMPT_TOOLS.includes("fn_web_fetch")).toBe(false);
});
it("keeps fn_* category equivalence mappings across gates", () => { it("keeps fn_* category equivalence mappings across gates", () => {
const fnTools = new Set<string>(); const fnTools = new Set<string>();
for (const source of [ for (const source of [