From c5e4d0100ee6a0f72a4be7a5aec894e4d674fdd6 Mon Sep 17 00:00:00 2001 From: AlexRV12 <71396855+AlexRV12@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:27:23 +0200 Subject: [PATCH] fix: fail open when whoami resolves without a role Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01L99mAR4LitqTcYY1Kn1ATH --- .../components/copilot/chat/global/sessionAccess.test.ts | 6 ++++++ .../lib/components/copilot/chat/global/sessionAccess.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/components/copilot/chat/global/sessionAccess.test.ts b/frontend/src/lib/components/copilot/chat/global/sessionAccess.test.ts index 0be7ee4f40..527d337ad9 100644 --- a/frontend/src/lib/components/copilot/chat/global/sessionAccess.test.ts +++ b/frontend/src/lib/components/copilot/chat/global/sessionAccess.test.ts @@ -83,4 +83,10 @@ describe('resolveSessionAccess', () => { expect(access.capabilities.has('write_draft')).toBe(true) expect(access.capabilities.has('deploy')).toBe(true) }) + + it('fails open on a body that resolves without a role, rather than throwing', async () => { + whoami.mockResolvedValueOnce(undefined) + const access = await resolveSessionAccess('ws') + expect(access.capabilities.has('write_draft')).toBe(true) + }) }) diff --git a/frontend/src/lib/components/copilot/chat/global/sessionAccess.ts b/frontend/src/lib/components/copilot/chat/global/sessionAccess.ts index 1e01c68e14..8fed511f2d 100644 --- a/frontend/src/lib/components/copilot/chat/global/sessionAccess.ts +++ b/frontend/src/lib/components/copilot/chat/global/sessionAccess.ts @@ -42,10 +42,14 @@ export function hasCapabilities( } export async function resolveSessionAccess(workspace: string): Promise { - let me: User + let me: User | undefined try { me = await UserService.whoami({ workspace }) - } catch { + } catch {} + // Checked rather than trusted: a body that arrives malformed resolves without + // throwing, and reading a capability off it would surface as a TypeError thrown + // out of the send rather than as the fail-open this whole path promises. + if (!me) { return fullSessionAccess(workspace) }