From 717bd4b8bfadbb508e68331611c11acd35385889 Mon Sep 17 00:00:00 2001 From: dadachann <185672915+dadachann@users.noreply.github.com> Date: Sun, 16 Aug 2026 17:01:02 +0000 Subject: [PATCH] fix(commands): pass trusted workspace scope to plugins --- src/langbot/pkg/command/cmdmgr.py | 10 ++++++++- tests/unit_tests/command/test_cmdmgr.py | 27 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/langbot/pkg/command/cmdmgr.py b/src/langbot/pkg/command/cmdmgr.py index 7560f7c43..31f28dfdf 100644 --- a/src/langbot/pkg/command/cmdmgr.py +++ b/src/langbot/pkg/command/cmdmgr.py @@ -3,6 +3,7 @@ from __future__ import annotations import typing import inspect +from ..api.http.context import ExecutionContext from ..core import app from . import operator from ..utils import importutil @@ -66,7 +67,14 @@ class CommandManager: require_context = getattr(self.ap.plugin_connector, 'require_workspace_context', None) if require_context is not None: - result = require_context(context) + result = require_context( + ExecutionContext( + instance_uuid=context.instance_uuid, + workspace_uuid=context.workspace_uuid, + placement_generation=context.placement_generation, + query_uuid=context.query_uuid, + ) + ) if inspect.isawaitable(result): await result diff --git a/tests/unit_tests/command/test_cmdmgr.py b/tests/unit_tests/command/test_cmdmgr.py index ade27cf48..afc251a13 100644 --- a/tests/unit_tests/command/test_cmdmgr.py +++ b/tests/unit_tests/command/test_cmdmgr.py @@ -11,6 +11,7 @@ from unittest.mock import AsyncMock, Mock from langbot.pkg.command import operator from langbot.pkg.command.cmdmgr import CommandManager +from langbot.pkg.api.http.context import ExecutionContext from tests.factories import FakeApp, command_query import langbot_plugin.api.entities.builtin.provider.session as provider_session @@ -393,6 +394,32 @@ class TestCommandManagerInternalExecute: assert len(results) == 1 assert results[0].text == 'plugin response' + @pytest.mark.asyncio + async def test_execute_selects_workspace_with_trusted_context(self): + """Plugin command discovery receives the typed runtime scope.""" + + fake_app = FakeApp() + mgr = CommandManager(fake_app) + mgr.cmd_list = [] + fake_app.plugin_connector.require_workspace_context = AsyncMock() + fake_app.plugin_connector.list_commands = AsyncMock(return_value=[]) + + ctx = self._create_context(command='help') + ctx.instance_uuid = 'instance-a' + ctx.workspace_uuid = 'workspace-a' + ctx.placement_generation = 4 + ctx.query_uuid = 'query-a' + + async for _ in mgr._execute(ctx, mgr.cmd_list): + pass + + selected = fake_app.plugin_connector.require_workspace_context.await_args.args[0] + assert isinstance(selected, ExecutionContext) + assert selected.instance_uuid == 'instance-a' + assert selected.workspace_uuid == 'workspace-a' + assert selected.placement_generation == 4 + assert selected.query_uuid == 'query-a' + @pytest.mark.asyncio async def test_execute_with_bound_plugins(self): """_execute passes bound_plugins to plugin connector."""