fix(exec): disable command guard in full access

This commit is contained in:
chengyongru
2026-08-24 11:44:00 +08:00
committed by chengyongru
parent b1cadf53c5
commit 09d3bd76c9
3 changed files with 50 additions and 11 deletions
+12 -8
View File
@@ -470,14 +470,18 @@ class ExecTool(Tool):
+ _WORKSPACE_BOUNDARY_NOTE
)
guard_error = self._guard_command(
command,
cwd,
restrict_to_workspace=access.restrict_to_workspace,
workspace_root=workspace_root,
)
if guard_error:
return guard_error
# Full access is an explicit trust decision. Keep the application-level
# command guard aligned with the selected access mode instead of
# continuing to block commands after workspace restriction is disabled.
if access.restrict_to_workspace:
guard_error = self._guard_command(
command,
cwd,
restrict_to_workspace=True,
workspace_root=workspace_root,
)
if guard_error:
return guard_error
if self.sandbox:
if _IS_WINDOWS:
+37 -3
View File
@@ -30,7 +30,7 @@ def _fake_resolve_public(hostname, port, family=0, type_=0):
@pytest.mark.asyncio
async def test_exec_blocks_curl_metadata():
tool = ExecTool()
tool = ExecTool(restrict_to_workspace=True)
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve_private):
result = await tool.execute(
command='curl -s -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/'
@@ -41,7 +41,7 @@ async def test_exec_blocks_curl_metadata():
@pytest.mark.asyncio
async def test_exec_blocks_wget_localhost():
tool = ExecTool()
tool = ExecTool(restrict_to_workspace=True)
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve_localhost):
result = await tool.execute(command="wget http://localhost:8080/secret -O /tmp/out")
assert "Error" in result
@@ -111,6 +111,40 @@ def test_exec_full_workspace_scope_still_blocks_metadata(tmp_path):
assert "internal/private" in error
@pytest.mark.parametrize(
"command",
[
"echo blocked",
"echo http://169.254.169.254/latest/meta-data/",
],
)
async def test_exec_full_access_skips_command_guard(tmp_path, command):
tool = ExecTool(
working_dir=str(tmp_path),
restrict_to_workspace=False,
deny_patterns=[r"echo\s+blocked"],
)
result = await tool.execute(command=command)
assert "Exit code: 0" in result
assert "Command blocked" not in result
async def test_exec_full_workspace_scope_skips_command_guard(tmp_path):
tool = ExecTool(working_dir=str(tmp_path), restrict_to_workspace=True)
scope = build_workspace_scope(tmp_path, "full", source_channel="websocket")
token = bind_workspace_scope(scope)
try:
result = await tool.execute(
command="echo http://169.254.169.254/latest/meta-data/",
)
finally:
reset_workspace_scope(token)
assert "Exit code: 0" in result
assert "Command blocked" not in result
@pytest.mark.asyncio
async def test_exec_allows_normal_commands():
tool = ExecTool(timeout=5)
@@ -131,7 +165,7 @@ async def test_exec_allows_curl_to_public_url():
@pytest.mark.asyncio
async def test_exec_blocks_chained_internal_url():
"""Internal URLs buried in chained commands should still be caught."""
tool = ExecTool()
tool = ExecTool(restrict_to_workspace=True)
with patch("nanobot.security.network.socket.getaddrinfo", _fake_resolve_private):
result = await tool.execute(
command="echo start && curl http://169.254.169.254/latest/meta-data/ && echo done"
+1
View File
@@ -525,6 +525,7 @@ def test_exec_session_mode_reuses_exec_safety_guard(tmp_path):
tool = ExecTool(
working_dir=str(tmp_path),
deny_patterns=[r"echo\s+blocked"],
restrict_to_workspace=True,
session_manager=manager,
)