mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(memory): skip OpenViking upload symlinks
This commit is contained in:
parent
26deeea830
commit
63991bbd97
2 changed files with 45 additions and 0 deletions
|
|
@ -336,10 +336,17 @@ ADD_RESOURCE_SCHEMA = {
|
||||||
|
|
||||||
def _zip_directory(dir_path: Path) -> Path:
|
def _zip_directory(dir_path: Path) -> Path:
|
||||||
"""Create a temporary zip file containing a directory tree."""
|
"""Create a temporary zip file containing a directory tree."""
|
||||||
|
root = dir_path.resolve()
|
||||||
zip_path = Path(tempfile.gettempdir()) / f"openviking_upload_{uuid.uuid4().hex}.zip"
|
zip_path = Path(tempfile.gettempdir()) / f"openviking_upload_{uuid.uuid4().hex}.zip"
|
||||||
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
||||||
for file_path in dir_path.rglob("*"):
|
for file_path in dir_path.rglob("*"):
|
||||||
|
if file_path.is_symlink():
|
||||||
|
continue
|
||||||
if file_path.is_file():
|
if file_path.is_file():
|
||||||
|
try:
|
||||||
|
file_path.resolve().relative_to(root)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
arcname = str(file_path.relative_to(dir_path)).replace("\\", "/")
|
arcname = str(file_path.relative_to(dir_path)).replace("\\", "/")
|
||||||
zipf.write(file_path, arcname=arcname)
|
zipf.write(file_path, arcname=arcname)
|
||||||
return zip_path
|
return zip_path
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import json
|
import json
|
||||||
|
import zipfile
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
|
@ -156,6 +157,43 @@ def test_tool_add_resource_uploads_existing_local_directory_and_cleans_zip(tmp_p
|
||||||
assert result["root_uri"] == "viking://resources/docs"
|
assert result["root_uri"] == "viking://resources/docs"
|
||||||
|
|
||||||
|
|
||||||
|
def test_tool_add_resource_directory_zip_skips_symlink_escape(tmp_path):
|
||||||
|
secret = tmp_path / "outside-secret.txt"
|
||||||
|
secret.write_text("do not upload\n", encoding="utf-8")
|
||||||
|
docs = tmp_path / "docs"
|
||||||
|
docs.mkdir()
|
||||||
|
(docs / "guide.md").write_text("# Guide\n", encoding="utf-8")
|
||||||
|
link = docs / "leak.txt"
|
||||||
|
try:
|
||||||
|
link.symlink_to(secret)
|
||||||
|
except OSError as exc:
|
||||||
|
pytest.skip(f"symlinks unavailable in test environment: {exc}")
|
||||||
|
|
||||||
|
provider = OpenVikingMemoryProvider()
|
||||||
|
provider._client = MagicMock()
|
||||||
|
archive_entries = {}
|
||||||
|
|
||||||
|
def inspect_upload(path):
|
||||||
|
with zipfile.ZipFile(path) as archive:
|
||||||
|
archive_entries["names"] = archive.namelist()
|
||||||
|
archive_entries["payloads"] = {
|
||||||
|
name: archive.read(name)
|
||||||
|
for name in archive.namelist()
|
||||||
|
}
|
||||||
|
return "upload_docs.zip"
|
||||||
|
|
||||||
|
provider._client.upload_temp_file.side_effect = inspect_upload
|
||||||
|
provider._client.post.return_value = {
|
||||||
|
"status": "ok",
|
||||||
|
"result": {"root_uri": "viking://resources/docs"},
|
||||||
|
}
|
||||||
|
|
||||||
|
json.loads(provider._tool_add_resource({"url": str(docs)}))
|
||||||
|
|
||||||
|
assert archive_entries["names"] == ["guide.md"]
|
||||||
|
assert b"do not upload" not in b"".join(archive_entries["payloads"].values())
|
||||||
|
|
||||||
|
|
||||||
def test_tool_add_resource_cleans_local_directory_zip_when_add_fails(tmp_path):
|
def test_tool_add_resource_cleans_local_directory_zip_when_add_fails(tmp_path):
|
||||||
docs = tmp_path / "docs"
|
docs = tmp_path / "docs"
|
||||||
docs.mkdir()
|
docs.mkdir()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue