fix(file): anchor device symlink guard to task cwd

The read_file device guard now walks symlink hops before the file operation
layer, but that hop walk still interpreted relative paths against the Python
process cwd. In sessions where TERMINAL_CWD points at the task workspace, a
relative workspace symlink to a blocked alias such as /dev/../dev/stdin could
therefore miss the intermediate device target before later task-cwd resolution.

Anchor relative device checks to the task base before symlink-hop inspection so
the pre-I/O guard sees the same workspace path that read_file would otherwise
read. Absolute device paths and the existing final realpath fallback remain
unchanged.

Refs #10141
Refs #29158
This commit is contained in:
Eugeniusz Gilewski 2026-06-21 19:15:21 +02:00 committed by Teknium
parent e267237671
commit def3f6388f
2 changed files with 34 additions and 3 deletions

View file

@ -170,6 +170,33 @@ class TestDevicePathBlocking(unittest.TestCase):
self.assertIn("device file", result["error"])
mock_ops.assert_not_called()
@patch("tools.file_tools._get_file_ops")
def test_read_file_tool_rejects_task_cwd_relative_device_alias_symlink(self, mock_ops):
if not os.path.exists("/dev/stdin"):
self.skipTest("/dev/stdin is not available on this platform")
with tempfile.TemporaryDirectory() as tmpdir:
workspace = os.path.join(tmpdir, "workspace")
process_cwd = os.path.join(tmpdir, "process")
os.mkdir(workspace)
os.mkdir(process_cwd)
link_path = os.path.join(workspace, "stdin-link")
try:
os.symlink("/dev/../dev/stdin", link_path)
except OSError as exc:
self.skipTest(f"symlink unavailable: {exc}")
old_cwd = os.getcwd()
try:
os.chdir(process_cwd)
with patch.dict(os.environ, {"TERMINAL_CWD": workspace}, clear=False):
result = json.loads(read_file_tool("stdin-link", task_id="dev_rel_link_test"))
finally:
os.chdir(old_cwd)
self.assertIn("error", result)
self.assertIn("device file", result["error"])
mock_ops.assert_not_called()
# ---------------------------------------------------------------------------
# Character-count limits