mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-23 10:42:00 +00:00
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:
parent
e267237671
commit
def3f6388f
2 changed files with 34 additions and 3 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue