feat(FN-3545): add agent permission policy model and persistence
Introduces a multi-agent permission policy model in `@fusion/core` (types, store persistence, API exposure) with corresponding dashboard UI wiring in the agent onboarding modal and task detail modal, plus a distributed task ID overlap retry mechanism for cluster creation, an inline fast mode toggle Fusion-Task-Id: FN-3545
This commit is contained in:
@@ -1862,6 +1862,7 @@ describe("Agent create/update routes", () => {
|
||||
reportsTo: agentId,
|
||||
runtimeConfig: { heartbeatIntervalMs: 60000 },
|
||||
permissions: { read: true },
|
||||
permissionPolicy: { presetId: "approval-required" },
|
||||
instructionsPath: "docs/reviewer.md",
|
||||
instructionsText: "Check test quality.",
|
||||
soul: "Analytical and thorough.",
|
||||
@@ -1879,6 +1880,16 @@ describe("Agent create/update routes", () => {
|
||||
reportsTo: agentId,
|
||||
runtimeConfig: { heartbeatIntervalMs: 60000 },
|
||||
permissions: { read: true },
|
||||
permissionPolicy: {
|
||||
presetId: "approval-required",
|
||||
rules: {
|
||||
"git-write": "require-approval",
|
||||
"file-write-delete": "require-approval",
|
||||
"shell-command": "require-approval",
|
||||
"network-api": "require-approval",
|
||||
"task-agent-management": "require-approval",
|
||||
},
|
||||
},
|
||||
instructionsPath: "docs/reviewer.md",
|
||||
instructionsText: "Check test quality.",
|
||||
soul: "Analytical and thorough.",
|
||||
@@ -1900,6 +1911,7 @@ describe("Agent create/update routes", () => {
|
||||
runtimeConfig: { heartbeatTimeoutMs: 120000 },
|
||||
pauseReason: "manual",
|
||||
permissions: { deploy: true },
|
||||
permissionPolicy: { presetId: "locked-down" },
|
||||
totalInputTokens: 42,
|
||||
totalOutputTokens: 21,
|
||||
instructionsPath: "agents/infra.md",
|
||||
@@ -1921,6 +1933,16 @@ describe("Agent create/update routes", () => {
|
||||
runtimeConfig: { heartbeatTimeoutMs: 120000 },
|
||||
pauseReason: "manual",
|
||||
permissions: { deploy: true },
|
||||
permissionPolicy: {
|
||||
presetId: "locked-down",
|
||||
rules: {
|
||||
"git-write": "block",
|
||||
"file-write-delete": "block",
|
||||
"shell-command": "block",
|
||||
"network-api": "block",
|
||||
"task-agent-management": "block",
|
||||
},
|
||||
},
|
||||
totalInputTokens: 42,
|
||||
totalOutputTokens: 21,
|
||||
instructionsPath: "agents/infra.md",
|
||||
@@ -1929,6 +1951,67 @@ describe("Agent create/update routes", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("POST /api/agents rejects invalid permissionPolicy preset", async () => {
|
||||
const res = await REQUEST(
|
||||
buildAgentApp(),
|
||||
"POST",
|
||||
"/api/agents",
|
||||
JSON.stringify({
|
||||
name: "Invalid Policy Agent",
|
||||
role: "executor",
|
||||
permissionPolicy: { presetId: "custom" },
|
||||
}),
|
||||
{ "Content-Type": "application/json" },
|
||||
);
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error).toContain("permissionPolicy.presetId");
|
||||
});
|
||||
|
||||
it("PATCH /api/agents/:id rejects invalid permissionPolicy payload shape", async () => {
|
||||
const res = await REQUEST(
|
||||
buildAgentApp(),
|
||||
"PATCH",
|
||||
`/api/agents/${agentId}`,
|
||||
JSON.stringify({
|
||||
permissionPolicy: "bad",
|
||||
}),
|
||||
{ "Content-Type": "application/json" },
|
||||
);
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error).toContain("permissionPolicy must be an object");
|
||||
});
|
||||
|
||||
it("POST /api/agents normalizes policy rules from preset and ignores caller-supplied rules", async () => {
|
||||
const res = await REQUEST(
|
||||
buildAgentApp(),
|
||||
"POST",
|
||||
"/api/agents",
|
||||
JSON.stringify({
|
||||
name: "Normalized Policy Agent",
|
||||
role: "executor",
|
||||
permissionPolicy: {
|
||||
presetId: "locked-down",
|
||||
rules: {
|
||||
"git-write": "allow",
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ "Content-Type": "application/json" },
|
||||
);
|
||||
|
||||
expect(res.status).toBe(201);
|
||||
expect(res.body.permissionPolicy.presetId).toBe("locked-down");
|
||||
expect(res.body.permissionPolicy.rules).toEqual({
|
||||
"git-write": "block",
|
||||
"file-write-delete": "block",
|
||||
"shell-command": "block",
|
||||
"network-api": "block",
|
||||
"task-agent-management": "block",
|
||||
});
|
||||
});
|
||||
|
||||
it("POST /api/agents returns 409 for duplicate non-ephemeral names", async () => {
|
||||
const first = await REQUEST(
|
||||
buildAgentApp(),
|
||||
|
||||
Reference in New Issue
Block a user