mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-04 07:31:58 +00:00
fix(plugins): widen _sanitize_plugin_name for category-namespaced names
Follow-up to PR #28832 — the dashboard plugin routes now accept slashed names like `observability/langfuse` and `image_gen/openai`, but `_sanitize_plugin_name` still rejected forward slash and so dashboard update + remove on those plugins fell through to '404 not found' even though they exist on disk. Adds an opt-in `allow_subdir=True` flag that: - Permits internal forward slashes (category-namespaced plugin keys emitted by `_discover_all_plugins`). - Strips leading and trailing slashes. - Still rejects `..` and backslash, and still asserts the resolved target lives inside `plugins_dir`. Opted in at the two read-paths that operate on installed plugins: `_require_installed_plugin` (CLI update/remove) and `_user_installed_plugin_dir` (dashboard update/remove). The install path keeps the default (`allow_subdir=False`) because freshly-cloned plugins always land top-level under `~/.hermes/plugins/<name>/`. Adds 6 targeted unit tests covering the new flag's allow/reject matrix.
This commit is contained in:
parent
487c398dcf
commit
8cf977c8b1
2 changed files with 54 additions and 4 deletions
|
|
@ -65,6 +65,36 @@ class TestSanitizePluginName:
|
|||
with pytest.raises(ValueError, match="must not be empty"):
|
||||
_sanitize_plugin_name("", tmp_path)
|
||||
|
||||
# ── allow_subdir=True ──
|
||||
|
||||
def test_allow_subdir_accepts_single_slash(self, tmp_path):
|
||||
target = _sanitize_plugin_name(
|
||||
"observability/langfuse", tmp_path, allow_subdir=True
|
||||
)
|
||||
assert target == (tmp_path / "observability" / "langfuse").resolve()
|
||||
|
||||
def test_allow_subdir_strips_leading_trailing_slash(self, tmp_path):
|
||||
target = _sanitize_plugin_name(
|
||||
"/image_gen/openai/", tmp_path, allow_subdir=True
|
||||
)
|
||||
assert target == (tmp_path / "image_gen" / "openai").resolve()
|
||||
|
||||
def test_allow_subdir_still_rejects_dot_dot(self, tmp_path):
|
||||
with pytest.raises(ValueError, match="must not contain"):
|
||||
_sanitize_plugin_name("foo/../bar", tmp_path, allow_subdir=True)
|
||||
|
||||
def test_allow_subdir_still_rejects_backslash(self, tmp_path):
|
||||
with pytest.raises(ValueError, match="must not contain"):
|
||||
_sanitize_plugin_name("foo\\bar", tmp_path, allow_subdir=True)
|
||||
|
||||
def test_allow_subdir_rejects_empty_after_strip(self, tmp_path):
|
||||
with pytest.raises(ValueError, match="must not be empty"):
|
||||
_sanitize_plugin_name("///", tmp_path, allow_subdir=True)
|
||||
|
||||
def test_allow_subdir_resolves_inside_plugins_dir(self, tmp_path):
|
||||
target = _sanitize_plugin_name("a/b/c", tmp_path, allow_subdir=True)
|
||||
assert target.is_relative_to(tmp_path.resolve())
|
||||
|
||||
|
||||
# ── _resolve_git_url ──────────────────────────────────────────────────────
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue