fix: use original session user for bridge callbacks instead of system user (RBAC)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
patrick-motsch 2026-02-13 17:26:56 +01:00
parent 77cbc5803a
commit 65128db713

View file

@ -363,11 +363,22 @@ async def bridgeStatusCallback(
logger.info(f"Bridge status callback: session={sessionId}, status={status}") logger.info(f"Bridge status callback: session={sessionId}, status={status}")
try: try:
# Update session status (bridge callbacks have no user context) # Load the original user who started the session (has RBAC roles in mandate)
from modules.datamodels.datamodelUam import User from modules.datamodels.datamodelUam import User
from modules.interfaces.interfaceDbApp import getRootInterface
systemUser = User(id="system", username="system", email="system@poweron.swiss") systemUser = User(id="system", username="system", email="system@poweron.swiss")
interface = interfaceDb.getInterface(systemUser, featureInstanceId=instanceId) interface = interfaceDb.getInterface(systemUser, featureInstanceId=instanceId)
# Look up original user from session for consistent context
session = interface.getSession(sessionId)
startedByUserId = session.get("startedByUserId") if session else None
if startedByUserId:
rootInterface = getRootInterface()
originalUser = rootInterface.getUser(startedByUserId)
if originalUser:
interface = interfaceDb.getInterface(originalUser, featureInstanceId=instanceId)
updates = {"status": status} updates = {"status": status}
if errorMessage: if errorMessage:
updates["errorMessage"] = errorMessage updates["errorMessage"] = errorMessage
@ -411,16 +422,27 @@ async def bridgeAudioWebsocket(
config = _getInstanceConfig(instanceId) config = _getInstanceConfig(instanceId)
logger.info(f"Bridge audio WebSocket config loaded: session={sessionId}") logger.info(f"Bridge audio WebSocket config loaded: session={sessionId}")
# Load the original user who started the session (has RBAC roles in mandate)
# Bridge callbacks have no HTTP auth, so we reconstruct the user context from the session record.
from modules.datamodels.datamodelUam import User from modules.datamodels.datamodelUam import User
systemUser = User(id="system", username="system", email="system@poweron.swiss") from modules.interfaces.interfaceDbApp import getRootInterface
# Look up mandateId from the session record (needed for AI billing context) systemUser = User(id="system", username="system", email="system@poweron.swiss")
sessionInterface = interfaceDb.getInterface(systemUser, featureInstanceId=instanceId) sessionInterface = interfaceDb.getInterface(systemUser, featureInstanceId=instanceId)
session = sessionInterface.getSession(sessionId) session = sessionInterface.getSession(sessionId)
mandateId = session.get("mandateId") if session else None mandateId = session.get("mandateId") if session else None
startedByUserId = session.get("startedByUserId") if session else None
service = TeamsbotService(systemUser, mandateId, instanceId, config) # Look up the original user (getRootInterface uses admin context, can load any user)
logger.info(f"Bridge audio WebSocket service created: session={sessionId}, mandateId={mandateId}") rootInterface = getRootInterface()
originalUser = rootInterface.getUser(startedByUserId) if startedByUserId else None
if not originalUser:
logger.warning(f"Could not load original user {startedByUserId}, falling back to system user")
originalUser = systemUser
service = TeamsbotService(originalUser, mandateId, instanceId, config)
logger.info(f"Bridge audio WebSocket service created: session={sessionId}, mandateId={mandateId}, user={originalUser.id}")
await service.handleAudioStream(websocket, sessionId) await service.handleAudioStream(websocket, sessionId)
except WebSocketDisconnect: except WebSocketDisconnect: