Files
hermes-agent/tests/hermes_cli/test_web_plugins_catalog.py
ethernet d0d4e91434 Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts:
#	hermes_cli/plugins_cmd.py
#	hermes_cli/plugins_cmd_catalog.py
#	tests/hermes_cli/test_web_plugins_catalog.py
#	website/docs/reference/cli-commands.md
#	website/docs/user-guide/features/plugin-catalog.md
2026-09-22 02:59:10 -04:00

82 lines
4.2 KiB
Python

"""Dashboard plugin-catalog surface: GET /api/dashboard/plugins/catalog merges installed state via the
installer-owned install-metadata ``catalog`` record; the install endpoint has no kill-list bypass."""
from __future__ import annotations
import pytest
import hermes_yaml as yaml
from hermes_cli import plugin_catalog as pc_cat
VALID_SHA = "38fe0fb53eff98d477f807432e965429e665ca33"
OTHER_SHA = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@pytest.fixture
def client(monkeypatch, tmp_path, _isolate_hermes_home):
try:
from starlette.testclient import TestClient
except ImportError:
pytest.skip("fastapi/starlette not installed")
import hermes_state
from hermes_constants import get_hermes_home
from hermes_cli.web_server import app, _SESSION_HEADER_NAME, _SESSION_TOKEN
monkeypatch.setattr(hermes_state, "DEFAULT_DB_PATH", get_hermes_home() / "state.db")
catalog_dir = tmp_path / "catalog"
catalog_dir.mkdir()
(catalog_dir / "alpha-plugin.yaml").write_text(yaml.safe_dump({
"name": "alpha-plugin", "repo": "https://github.com/example/alpha-plugin", "sha": VALID_SHA,
"description": "d", "maintainer": "Example", "tier": "official",
"capabilities": {"provides_tools": ["tool_a"], "requires_env": ["EXAMPLE_API_KEY"]}}))
(catalog_dir / "removed.yaml").write_text(yaml.safe_dump({"removed": [
{"name": "bad-plugin", "repo": "https://github.com/evil/bad-plugin", "reason": "exfiltrated env vars"}]}))
monkeypatch.setattr(pc_cat, "get_catalog_dir", lambda: catalog_dir)
monkeypatch.setattr(pc_cat, "fetch_live_catalog", lambda **_: None)
c = TestClient(app)
c.headers[_SESSION_HEADER_NAME] = _SESSION_TOKEN
return c
def _install(name: str, sidecar: dict | None):
"""A user-dir plugin; *sidecar* records catalog provenance the way the installer does — on the
installer-owned ``.install-metadata.json`` record (an in-tree ``.hermes-catalog.json`` is inert)."""
from hermes_constants import get_hermes_home
from hermes_cli.plugins_cmd import _read_install_metadata, _write_install_metadata
d = get_hermes_home() / "plugins" / name
d.mkdir(parents=True)
(d / "plugin.yaml").write_text(yaml.safe_dump({"name": name, "version": "1.0", "description": "x"}))
if sidecar:
block = {"name": sidecar["catalog_name"], "sha": sidecar["sha"], "tier": sidecar.get("tier", "community")}
_write_install_metadata({**_read_install_metadata(), name: {
"pinned": True, "revision": sidecar["sha"], "source": "https://github.com/example/alpha-plugin.git",
"catalog": block}})
def test_catalog_endpoint_merges_installed_state_from_sidecar(client):
from starlette.testclient import TestClient
from hermes_cli.web_server import app
assert TestClient(app).get("/api/dashboard/plugins/catalog").status_code == 401
# Manifest name differs from the catalog name (the common case): matched through the sidecar.
_install("alpha", {"catalog_name": "alpha-plugin", "sha": OTHER_SHA, "tier": "official"})
data = client.get("/api/dashboard/plugins/catalog").json()
[entry] = data["entries"]
assert (entry["name"], entry["sha_short"], entry["capabilities"]["provides_tools"]) == ("alpha-plugin", VALID_SHA[:7], ["tool_a"])
assert "tool_a" in entry["capability_summary"]
assert (entry["installed"], entry["installed_sha"], entry["update_available"]) == (True, OTHER_SHA, True)
assert entry["runtime_status"] == "inactive"
assert data["removed"][0]["reason"] == "exfiltrated env vars"
def test_install_endpoint_refuses_removed_plugins_with_no_bypass(client, monkeypatch):
from hermes_cli import plugins_cmd
monkeypatch.setattr(plugins_cmd, "_install_plugin_core", lambda *a, **k: pytest.fail("kill-listed install ran"))
for body in ({"identifier": "https://github.com/evil/bad-plugin.git"},
{"identifier": "", "catalog_name": "bad-plugin"}, {"identifier": "evil/bad-plugin"}):
resp = client.post("/api/dashboard/agent-plugins/install", json=body)
assert resp.status_code == 400, body
assert "removed" in resp.json()["detail"] or "not in the Hermes plugin catalog" in resp.json()["detail"]
assert client.post("/api/dashboard/agent-plugins/install", json={"identifier": ""}).status_code == 400