From 49afd9f3205e7df02cacce443bfb4a2a6d38d67f Mon Sep 17 00:00:00 2001 From: RockChinQ <45992437+RockChinQ@users.noreply.github.com> Date: Sat, 24 Oct 2026 12:06:00 +0000 Subject: [PATCH] fix(box): ignore box.local.env in multi-workspace deployments Co-Authored-By: Claude Opus 5.5 Co-authored-by: multica-agent --- src/langbot/pkg/box/service.py | 7 +++++++ src/langbot/templates/config.yaml | 2 ++ tests/unit_tests/box/test_box_service.py | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/langbot/pkg/box/service.py b/src/langbot/pkg/box/service.py index 7c5dbaadb..55d4f39ab 100644 --- a/src/langbot/pkg/box/service.py +++ b/src/langbot/pkg/box/service.py @@ -1843,10 +1843,17 @@ class BoxService: can read settings such as a service base URL. A per-call ``env`` supplied by the agent or caller overrides the matching defaults. Non-dict configs and non-string keys or values are ignored. + + The setting is instance-wide, so it is disabled in multi-workspace + deployments to keep operator values from reaching every tenant's sandbox. """ raw_env = self._local_config().get('env') if not isinstance(raw_env, dict): return {} + if self._cloud_managed: + if raw_env: + self.ap.logger.warning('box.local.env is ignored in multi-workspace deployments.') + return {} env: dict[str, str] = {} for key, value in raw_env.items(): diff --git a/src/langbot/templates/config.yaml b/src/langbot/templates/config.yaml index 098cdcb9f..cd43709db 100644 --- a/src/langbot/templates/config.yaml +++ b/src/langbot/templates/config.yaml @@ -391,6 +391,8 @@ box: workspace_quota_mb: null # Optional disk quota override (>= 0). null = profile default. # Extra environment variables injected into every Box exec payload. # The agent-supplied per-call env overrides matching keys. Values must be strings. + # Every sandbox command, including untrusted agent commands, can read them; + # do not put secrets here. Loaded at startup; ignored in multi-workspace deployments. env: {} # Default nsjail cgroup memory limit for each MCP stdio server process, in MB. # Node.js MCP servers (npx/bunx) need more memory than Python ones because V8 diff --git a/tests/unit_tests/box/test_box_service.py b/tests/unit_tests/box/test_box_service.py index 68f680ec4..dd849316f 100644 --- a/tests/unit_tests/box/test_box_service.py +++ b/tests/unit_tests/box/test_box_service.py @@ -466,6 +466,26 @@ def test_box_build_spec_ignores_invalid_local_env_entries(): assert spec.env == {} +def test_box_build_spec_ignores_local_env_in_multi_workspace_deployment(): + logger = Mock() + app = make_app(logger) + app.deployment = SimpleNamespace(multi_workspace_enabled=True) + app.instance_config.data['box'].update( + { + 'backend': 'nsjail', + 'admission': {'required': True, 'workspace_quota_mb': 32}, + } + ) + app.instance_config.data['box']['local']['env'] = {'JENKINS_BASE_URL': 'https://jenkins.example.com'} + service = BoxService(app, client=Mock()) + + spec = service.build_spec({'cmd': 'echo hi', 'session_id': 'cloud-env', 'env': {'PER_CALL': '1'}}) + + assert service.default_env == {} + assert spec.env == {'PER_CALL': '1'} + logger.warning.assert_any_call('box.local.env is ignored in multi-workspace deployments.') + + @pytest.mark.asyncio async def test_box_service_get_sessions_delegates_to_client(): client = Mock()