@@ -133,20 +133,47 @@ def _run(self, coro):
133133
134134 def test_read_only_by_default (self , tmp_path ):
135135 workspace = str (tmp_path )
136- os .environ ["SANDLOCK_WORKSPACE" ] = workspace
137136
138137 mcp = McpSandbox (workspace = workspace )
139138 mcp .add_tool ("run_python" , _run_python_tool )
140139
141140 result = self ._run (mcp .call_tool ("run_python" , {"code" : "print(42)" }))
142141 assert "42" in result
143142
143+ def test_clean_env_by_default (self , tmp_path ):
144+ """Tools get clean env — can't see agent's env vars."""
145+ workspace = str (tmp_path )
146+ os .environ ["SECRET_API_KEY" ] = "should-not-leak"
147+
148+ mcp = McpSandbox (workspace = workspace )
149+ mcp .add_tool ("run_python" , _run_python_tool )
150+
151+ result = self ._run (mcp .call_tool ("run_python" , {
152+ "code" : "import os; print(os.environ.get('SECRET_API_KEY', 'HIDDEN'))" ,
153+ }))
154+ assert "HIDDEN" in result
155+ assert "should-not-leak" not in result
156+
157+ def test_env_capability_passes_vars (self , tmp_path ):
158+ """Only explicitly granted env vars are visible."""
159+ workspace = str (tmp_path )
160+ ws_env = {"SANDLOCK_WORKSPACE" : workspace }
161+
162+ mcp = McpSandbox (workspace = workspace )
163+ mcp .add_tool ("read_file" , _read_file_tool ,
164+ capabilities = {"env" : ws_env })
165+
166+ (tmp_path / "test.txt" ).write_text ("hello" )
167+ result = self ._run (mcp .call_tool ("read_file" , {"path" : "test.txt" }))
168+ assert "hello" in result
169+
144170 def test_write_requires_capability (self , tmp_path ):
145171 workspace = str (tmp_path )
146- os . environ [ "SANDLOCK_WORKSPACE" ] = workspace
172+ ws_env = { "SANDLOCK_WORKSPACE" : workspace }
147173
148174 mcp = McpSandbox (workspace = workspace )
149- mcp .add_tool ("write_file" , _write_file_tool ) # no capabilities
175+ mcp .add_tool ("write_file" , _write_file_tool ,
176+ capabilities = {"env" : ws_env }) # env but no fs_writable
150177
151178 with pytest .raises (RuntimeError , match = "failed" ):
152179 self ._run (mcp .call_tool (
@@ -155,12 +182,13 @@ def test_write_requires_capability(self, tmp_path):
155182
156183 def test_write_with_capability (self , tmp_path ):
157184 workspace = str (tmp_path )
158- os . environ [ "SANDLOCK_WORKSPACE" ] = workspace
185+ ws_env = { "SANDLOCK_WORKSPACE" : workspace }
159186
160187 mcp = McpSandbox (workspace = workspace )
161188 mcp .add_tool ("write_file" , _write_file_tool ,
162- capabilities = {"fs_writable" : [workspace ]})
163- mcp .add_tool ("read_file" , _read_file_tool )
189+ capabilities = {"fs_writable" : [workspace ], "env" : ws_env })
190+ mcp .add_tool ("read_file" , _read_file_tool ,
191+ capabilities = {"env" : ws_env })
164192
165193 self ._run (mcp .call_tool (
166194 "write_file" , {"path" : "test.txt" , "content" : "hello" },
@@ -176,6 +204,7 @@ def test_get_policy(self, tmp_path):
176204 capabilities = {"fs_writable" : [workspace ]})
177205
178206 assert mcp .get_policy ("reader" ).fs_writable == []
207+ assert mcp .get_policy ("reader" ).clean_env is True
179208 assert workspace in mcp .get_policy ("writer" ).fs_writable
180209
181210 def test_unknown_tool_raises (self , tmp_path ):
@@ -194,14 +223,16 @@ def test_openai_format(self, tmp_path):
194223
195224 def test_full_workflow (self , tmp_path ):
196225 workspace = str (tmp_path )
197- os . environ [ "SANDLOCK_WORKSPACE" ] = workspace
226+ ws_env = { "SANDLOCK_WORKSPACE" : workspace }
198227
199228 mcp = McpSandbox (workspace = workspace )
200229 mcp .add_tool ("write_file" , _write_file_tool ,
201- capabilities = {"fs_writable" : [workspace ]})
202- mcp .add_tool ("read_file" , _read_file_tool )
230+ capabilities = {"fs_writable" : [workspace ], "env" : ws_env })
231+ mcp .add_tool ("read_file" , _read_file_tool ,
232+ capabilities = {"env" : ws_env })
203233 mcp .add_tool ("run_python" , _run_python_tool )
204- mcp .add_tool ("list_files" , _list_files_tool )
234+ mcp .add_tool ("list_files" , _list_files_tool ,
235+ capabilities = {"env" : ws_env })
205236
206237 async def workflow ():
207238 await mcp .call_tool ("write_file" ,
0 commit comments