Files
horus-3d/tests/unit/gatewayAgentSkillsAllowlist.test.ts
T
Luke The Dev 4fa4f13558 First Release of Claw3D (#11)
Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
2026-03-19 23:14:04 -05:00

285 lines
8.9 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { GatewayResponseError } from "@/lib/gateway/GatewayClient";
import type { GatewayClient } from "@/lib/gateway/GatewayClient";
import {
readGatewayAgentSkillsAllowlist,
updateGatewayAgentSkillsAllowlist,
} from "@/lib/gateway/agentConfig";
describe("gateway agent skills allowlist", () => {
it("reads and normalizes existing skills allowlist", async () => {
const client = {
call: vi.fn(async (method: string) => {
if (method === "config.get") {
return {
exists: true,
hash: "cfg-read-1",
config: {
agents: {
list: [{ id: "agent-1", skills: [" github ", "slack", "github"] }],
},
},
};
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await expect(
readGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
})
).resolves.toEqual(["github", "slack"]);
});
it("writes mode all by removing the skills key", async () => {
const client = {
call: vi.fn(async (method: string, params?: unknown) => {
if (method === "config.get") {
return {
exists: true,
hash: "cfg-all-1",
config: {
agents: {
list: [{ id: "agent-1", skills: ["github", "slack"] }],
},
},
};
}
if (method === "config.set") {
const payload = params as { raw?: string; baseHash?: string };
const parsed = JSON.parse(payload.raw ?? "") as {
agents?: { list?: Array<{ id?: string; skills?: string[] }> };
};
expect(payload.baseHash).toBe("cfg-all-1");
const entry = parsed.agents?.list?.find((item) => item.id === "agent-1");
expect(entry).toEqual({ id: "agent-1" });
return { ok: true };
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "all",
});
});
it("writes mode none and mode allowlist with normalized names", async () => {
const calls: Array<{ method: string; params?: unknown }> = [];
const client = {
call: vi.fn(async (method: string, params?: unknown) => {
calls.push({ method, params });
if (method === "config.get") {
return {
exists: true,
hash: `cfg-${calls.length}`,
config: {
agents: {
list: [{ id: "agent-1" }],
},
},
};
}
if (method === "config.set") {
return { ok: true };
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "none",
});
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "allowlist",
skillNames: [" slack ", "github", "slack"],
});
const nonePayload = calls.find(
(entry) => entry.method === "config.set"
)?.params as { raw?: string };
const setCalls = calls.filter((entry) => entry.method === "config.set");
const allowPayload = setCalls[1]?.params as { raw?: string };
expect(
(JSON.parse(nonePayload.raw ?? "") as { agents?: { list?: Array<{ id?: string; skills?: string[] }> } })
.agents?.list?.find((entry) => entry.id === "agent-1")
).toEqual({ id: "agent-1", skills: [] });
expect(
(JSON.parse(allowPayload.raw ?? "") as {
agents?: { list?: Array<{ id?: string; skills?: string[] }> };
}).agents?.list?.find((entry) => entry.id === "agent-1")
).toEqual({ id: "agent-1", skills: ["github", "slack"] });
});
it("retries once after stale hash and preserves concurrent config changes", async () => {
let getCount = 0;
let setCount = 0;
const client = {
call: vi.fn(async (method: string, params?: unknown) => {
if (method === "config.get") {
getCount += 1;
if (getCount === 1) {
return {
exists: true,
hash: "cfg-retry-1",
config: {
gateway: { reload: { mode: "hybrid" } },
agents: { list: [{ id: "agent-1" }] },
},
};
}
return {
exists: true,
hash: "cfg-retry-2",
config: {
gateway: { reload: { mode: "off" } },
agents: { list: [{ id: "agent-1" }] },
},
};
}
if (method === "config.set") {
setCount += 1;
const payload = params as { raw?: string; baseHash?: string };
const parsed = JSON.parse(payload.raw ?? "") as {
gateway?: { reload?: { mode?: string } };
agents?: { list?: Array<{ id?: string; skills?: string[] }> };
};
if (setCount === 1) {
expect(payload.baseHash).toBe("cfg-retry-1");
expect(parsed.gateway?.reload?.mode).toBe("hybrid");
throw new GatewayResponseError({
code: "INVALID_REQUEST",
message: "config changed since last load; re-run config.get and retry",
});
}
expect(payload.baseHash).toBe("cfg-retry-2");
expect(parsed.gateway?.reload?.mode).toBe("off");
expect(parsed.agents?.list?.find((entry) => entry.id === "agent-1")).toEqual({
id: "agent-1",
skills: ["github"],
});
return { ok: true };
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "allowlist",
skillNames: ["github"],
});
expect(getCount).toBe(2);
expect(setCount).toBe(2);
});
it("fails fast when mode allowlist omits skill names", async () => {
const client = {
call: vi.fn(),
} as unknown as GatewayClient;
await expect(
updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "allowlist",
})
).rejects.toThrow("Skills allowlist is required when mode is allowlist.");
expect(client.call).not.toHaveBeenCalled();
});
it("skips config.set when mode all is already implied", async () => {
const client = {
call: vi.fn(async (method: string) => {
if (method === "config.get") {
return {
exists: true,
hash: "cfg-skip-write",
config: { agents: { list: [{ id: "other-agent" }] } },
};
}
if (method === "config.set") {
throw new Error("config.set should not be called for no-op mode all");
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "all",
});
expect(client.call).toHaveBeenCalledTimes(1);
expect(client.call).toHaveBeenCalledWith("config.get", {});
});
it("skips config.set when mode all has no explicit skills on existing agent entry", async () => {
const client = {
call: vi.fn(async (method: string) => {
if (method === "config.get") {
return {
exists: true,
hash: "cfg-skip-write-existing",
config: { agents: { list: [{ id: "agent-1", name: "Agent One" }] } },
};
}
if (method === "config.set") {
throw new Error("config.set should not be called for no-op mode all");
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "all",
});
expect(client.call).toHaveBeenCalledTimes(1);
expect(client.call).toHaveBeenCalledWith("config.get", {});
});
it("skips config.set when allowlist is unchanged after normalization", async () => {
const client = {
call: vi.fn(async (method: string) => {
if (method === "config.get") {
return {
exists: true,
hash: "cfg-skip-write-allowlist",
config: { agents: { list: [{ id: "agent-1", skills: [" github ", "slack"] }] } },
};
}
if (method === "config.set") {
throw new Error("config.set should not be called for unchanged allowlist");
}
throw new Error(`unexpected method ${method}`);
}),
} as unknown as GatewayClient;
await updateGatewayAgentSkillsAllowlist({
client,
agentId: "agent-1",
mode: "allowlist",
skillNames: ["slack", "github", "github"],
});
expect(client.call).toHaveBeenCalledTimes(1);
expect(client.call).toHaveBeenCalledWith("config.get", {});
});
});