From e3f75fd241ad50b4e934e4426804ebea4d38f795 Mon Sep 17 00:00:00 2001 From: Shakker Date: Sun, 2 Aug 2026 15:05:09 +0100 Subject: [PATCH] fix: require admin scope for chat resets --- ui/src/pages/chat/chat-commands.test.ts | 11 ++++++----- ui/src/pages/chat/chat-commands.ts | 2 +- ui/src/pages/chat/chat-send.test.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/src/pages/chat/chat-commands.test.ts b/ui/src/pages/chat/chat-commands.test.ts index 435ab23f7c44..f3d8044f6b5a 100644 --- a/ui/src/pages/chat/chat-commands.test.ts +++ b/ui/src/pages/chat/chat-commands.test.ts @@ -257,6 +257,7 @@ describe("refreshSlashCommands", () => { describe("conversation reset confirmation", () => { it.each([ ["stop", "chat.abort"], + ["reset", "chat.send"], ["clear", "sessions.reset"], ["compact", "sessions.compact"], ] as const)("rejects /%s without its exact operator scope", async (command, method) => { @@ -351,7 +352,7 @@ describe("conversation reset confirmation", () => { connected: true, connectionEpoch: 1, hello: { - auth: { role: "operator", scopes: ["operator.write"] }, + auth: { role: "operator", scopes: ["operator.admin"] }, features: { methods: ["chat.send"] }, } as ApplicationGatewaySnapshot["hello"], sessionKey: "agent:main:current", @@ -372,7 +373,7 @@ describe("conversation reset confirmation", () => { expect(sendResetMessage).not.toHaveBeenCalled(); }); - it("rechecks /reset write scope after confirmation", async () => { + it("rechecks /reset admin scope after confirmation", async () => { let settleConfirmation: ((confirmed: boolean) => void) | undefined; const confirmation = new Promise((resolve) => { settleConfirmation = resolve; @@ -382,7 +383,7 @@ describe("conversation reset confirmation", () => { ...legacyConnectedSessionAccess(), connectionEpoch: 1, hello: { - auth: { role: "operator", scopes: ["operator.write"] }, + auth: { role: "operator", scopes: ["operator.admin"] }, features: { methods: ["chat.send"] }, } as ApplicationGatewaySnapshot["hello"], sessionKey: "agent:main:current", @@ -396,14 +397,14 @@ describe("conversation reset confirmation", () => { sendResetMessage, }); host.hello = { - auth: { role: "operator", scopes: ["operator.read"] }, + auth: { role: "operator", scopes: ["operator.write"] }, features: { methods: ["chat.send"] }, } as ApplicationGatewaySnapshot["hello"]; settleConfirmation?.(true); await expect(pending).resolves.toBe("failed"); expect(sendResetMessage).not.toHaveBeenCalled(); - expect(host.lastError).toContain("operator.write"); + expect(host.lastError).toContain("operator.admin"); }); it("continues /reset when the session key changes to an equivalent alias", async () => { diff --git a/ui/src/pages/chat/chat-commands.ts b/ui/src/pages/chat/chat-commands.ts index 5c9b32746253..7c32b0674913 100644 --- a/ui/src/pages/chat/chat-commands.ts +++ b/ui/src/pages/chat/chat-commands.ts @@ -140,7 +140,7 @@ export function readChatResetTargetAccess( } const access = readSessionMethodAccess(currentSessionAccessSnapshot(host), { method: "chat.send", - requiredScope: "operator.write", + requiredScope: "operator.admin", }); return access.allowed ? { allowed: true } : access; } diff --git a/ui/src/pages/chat/chat-send.test.ts b/ui/src/pages/chat/chat-send.test.ts index 6c24d4ca2f27..7b6dbb7aa6ed 100644 --- a/ui/src/pages/chat/chat-send.test.ts +++ b/ui/src/pages/chat/chat-send.test.ts @@ -4378,7 +4378,7 @@ describe("handleSendChat", () => { connectionEpoch: 1, confirmConversationReset: vi.fn(async () => await confirmation.promise), hello: { - auth: { role: "operator", scopes: ["operator.write"] }, + auth: { role: "operator", scopes: ["operator.admin"] }, features: { methods: ["chat.send"] }, }, });