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()