fix(adapters): scope spawnBot replay to spawning member in shared Spaces
spawnKey is unique per Space, not per user. createBot already rejects cross-member replay, but spawnBot caught that error and returned the other member's bot anyway. Match createBot by requiring existing.userId === spawnedBy.userId before treating a spawnKey conflict as idempotent. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
This commit is contained in:
parent
33ce657201
commit
4264ef682f
@ -41,6 +41,7 @@ describe("spawned bot creation", () => {
|
|||||||
id: "child-1",
|
id: "child-1",
|
||||||
name: "Scout",
|
name: "Scout",
|
||||||
title: "Venue researcher",
|
title: "Venue researcher",
|
||||||
|
userId: "user-1",
|
||||||
thread: { id: "thread-1" },
|
thread: { id: "thread-1" },
|
||||||
});
|
});
|
||||||
const enqueue = vi.fn().mockResolvedValue(undefined);
|
const enqueue = vi.fn().mockResolvedValue(undefined);
|
||||||
@ -95,6 +96,45 @@ describe("spawned bot creation", () => {
|
|||||||
expect(enqueue).toHaveBeenCalledOnce();
|
expect(enqueue).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("rejects a spawnKey that belongs to another member in the shared Space", async () => {
|
||||||
|
const conflict = new Error("unique spawn key");
|
||||||
|
const findUnique = vi.fn().mockResolvedValue({
|
||||||
|
id: "child-owner",
|
||||||
|
name: "Scout",
|
||||||
|
title: "Venue researcher",
|
||||||
|
userId: "owner-user",
|
||||||
|
thread: { id: "thread-owner" },
|
||||||
|
});
|
||||||
|
const createBot = vi.fn().mockRejectedValue(conflict);
|
||||||
|
const createReposSpy = vi.spyOn(await import("@rakazo/db"), "createRepos").mockReturnValue({
|
||||||
|
createBot,
|
||||||
|
} as unknown as ReturnType<typeof createRepos>);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
spawnBot(
|
||||||
|
{
|
||||||
|
prisma: { bot: { findUnique } } as unknown as PrismaClient,
|
||||||
|
jobs: { enqueue: vi.fn() } as unknown as JobPublisher,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spawnedBy: {
|
||||||
|
id: "parent-2",
|
||||||
|
name: "Other",
|
||||||
|
spaceId: "workspace-1",
|
||||||
|
userId: "other-user",
|
||||||
|
},
|
||||||
|
runId: "run-2",
|
||||||
|
spawnKey: "tool-call-shared",
|
||||||
|
name: "Scout",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).rejects.toThrow("unique spawn key");
|
||||||
|
|
||||||
|
expect(createBot).toHaveBeenCalledOnce();
|
||||||
|
expect(findUnique).toHaveBeenCalledOnce();
|
||||||
|
createReposSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it("passes computerMode through to createBot", async () => {
|
it("passes computerMode through to createBot", async () => {
|
||||||
const createBot = vi.fn().mockResolvedValue({
|
const createBot = vi.fn().mockResolvedValue({
|
||||||
id: "child-2",
|
id: "child-2",
|
||||||
|
|||||||
@ -94,6 +94,7 @@ export async function spawnBot(
|
|||||||
include: { thread: true },
|
include: { thread: true },
|
||||||
});
|
});
|
||||||
if (!existing) throw error;
|
if (!existing) throw error;
|
||||||
|
if (existing.userId !== input.spawnedBy.userId) throw error;
|
||||||
if (!existing.thread) throw new Error(`Spawned bot ${existing.id} is missing its thread`);
|
if (!existing.thread) throw new Error(`Spawned bot ${existing.id} is missing its thread`);
|
||||||
duplicate = true;
|
duplicate = true;
|
||||||
created = {
|
created = {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user