diff --git a/tests/agent/test_prompt_builder.py b/tests/agent/test_prompt_builder.py index a2d8ec56d7e35..858c880ec8fb6 100644 --- a/tests/agent/test_prompt_builder.py +++ b/tests/agent/test_prompt_builder.py @@ -928,6 +928,43 @@ class TestFindHermesMd: (repo / ".git").mkdir() assert _find_hermes_md(repo) is None + def test_no_git_root_checks_cwd_only(self, tmp_path): + """Outside a git repo, only cwd is checked — parents are NOT walked. + + Walking parents with no git root to stop the loop would climb all + the way to / and pick up a .hermes.md planted in /tmp, /home, or / + on a shared system — a cross-user prompt-injection vector. + """ + from unittest.mock import patch + + parent = tmp_path / "parent" + parent.mkdir() + (parent / ".hermes.md").write_text("planted by another user") + cwd = parent / "work" + cwd.mkdir() + # No git root anywhere up the tree. + with patch("agent.prompt_builder._find_git_root", return_value=None): + assert _find_hermes_md(cwd) is None + + def test_no_git_root_finds_in_cwd(self, tmp_path): + """Outside a git repo, a .hermes.md in cwd itself is still found.""" + from unittest.mock import patch + + (tmp_path / ".hermes.md").write_text("local rules") + with patch("agent.prompt_builder._find_git_root", return_value=None): + assert _find_hermes_md(tmp_path) == tmp_path / ".hermes.md" + + def test_walks_parents_inside_git_repo(self, tmp_path): + """Inside a git repo, parent walk up to the git root still works.""" + from unittest.mock import patch + + (tmp_path / ".hermes.md").write_text("repo root rules") + sub = tmp_path / "a" / "b" + sub.mkdir(parents=True) + # Simulate cwd being inside a repo rooted at tmp_path. + with patch("agent.prompt_builder._find_git_root", return_value=tmp_path): + assert _find_hermes_md(sub) == tmp_path / ".hermes.md" + class TestFindGitRoot: def test_finds_git_dir(self, tmp_path):