Download tests/plugins/test_plugin_dashboard_auth_contract.py from SaylorTwift/hermes-agent: direct link, hf CLI and curl.
- Browser
- Download file 4.01 kB
-
https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/tests/plugins/test_plugin_dashboard_auth_contract.py
- Command line
-
hf download hf://SaylorTwift/hermes-agent/tests/plugins/test_plugin_dashboard_auth_contract.py
-
curl -L -o test_plugin_dashboard_auth_contract.py https://huggingface.co/SaylorTwift/hermes-agent/resolve/main/tests/plugins/test_plugin_dashboard_auth_contract.py
4.01 kB
| """Guardrail: dashboard plugins must NOT read the session token directly. | |
| The dashboard host exposes a sanctioned, gated-mode-aware auth surface on the | |
| plugin SDK (``window.__HERMES_PLUGIN_SDK__``): ``fetchJSON`` (JSON REST), | |
| ``authedFetch`` (uploads / blob downloads), and ``buildWsUrl`` / | |
| ``buildWsAuthParam`` (WebSockets). These handle BOTH dashboard auth modes β | |
| loopback (``X-Hermes-Session-Token`` header) and gated OAuth | |
| (``hermes_session_at`` cookie / single-use ``?ticket=``). | |
| Plugins that hand-roll ``fetch`` / ``WebSocket`` and read | |
| ``window.__HERMES_SESSION_TOKEN__`` directly send an empty token in gated mode | |
| and 401/1008. That bug shipped in the kanban and achievements plugins and was | |
| invisible until the dashboard ran gated on hosted Fly agents. | |
| This test fails if any bundled plugin's frontend reads the token global | |
| directly, forcing new/edited plugins through the SDK surface instead. It is | |
| the enforcement half of the "single sanctioned auth surface" design β the SDK | |
| helpers are the carrot, this test is the stick. | |
| If you have a legitimate reason to reference the token name (e.g. a comment | |
| explaining why NOT to use it), add the file to ``_ALLOWED_FILES`` with a note. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from pathlib import Path | |
| import pytest | |
| # Repo root: tests/plugins/<this file> β ../../ | |
| _REPO_ROOT = Path(__file__).resolve().parents[2] | |
| _PLUGINS_DIR = _REPO_ROOT / "plugins" | |
| # The forbidden global. Reading it directly bypasses the gated-mode auth path. | |
| _FORBIDDEN = "__HERMES_SESSION_TOKEN__" | |
| # Files explicitly allowed to mention the token (none today). Map path β | |
| # reason so the allowance is self-documenting if one is ever needed. | |
| _ALLOWED_FILES: dict[str, str] = {} | |
| def _plugin_frontend_bundles() -> list[Path]: | |
| """Every plugin-shipped JS bundle the dashboard loads into the browser.""" | |
| if not _PLUGINS_DIR.is_dir(): | |
| return [] | |
| # Plugin dashboards live at plugins/<name>/dashboard/dist/*.js | |
| return sorted(_PLUGINS_DIR.glob("*/dashboard/dist/*.js")) | |
| def test_there_are_plugin_bundles_to_check() -> None: | |
| """Sanity: the glob actually finds the bundles, so a future layout change | |
| doesn't silently turn this guard into a no-op.""" | |
| bundles = _plugin_frontend_bundles() | |
| names = {b.parent.parent.parent.name for b in bundles} | |
| # kanban + hermes-achievements are bundled today; assert at least one is | |
| # found so the guard can't pass vacuously. | |
| assert bundles, "no plugin dashboard bundles found β glob/layout drift?" | |
| assert names, "could not resolve plugin names from bundle paths" | |
| def test_plugin_bundle_does_not_read_session_token(bundle: Path) -> None: | |
| rel = str(bundle.relative_to(_REPO_ROOT)) | |
| text = bundle.read_text(encoding="utf-8", errors="replace") | |
| if rel in _ALLOWED_FILES: | |
| return # explicitly allowed (with a documented reason) | |
| # Only flag CODE reads of the token global, not mentions in ``//`` comments | |
| # (e.g. a comment explaining why the SDK helper is used instead). A line is | |
| # a code read if it contains the global and the global appears before any | |
| # ``//`` comment marker on that line. | |
| offending: list[str] = [] | |
| for i, line in enumerate(text.splitlines(), start=1): | |
| idx = line.find(_FORBIDDEN) | |
| if idx == -1: | |
| continue | |
| comment_idx = line.find("//") | |
| in_comment = comment_idx != -1 and comment_idx < idx | |
| if not in_comment: | |
| offending.append(f" {i}: {line.strip()}") | |
| if not offending: | |
| return | |
| pytest.fail( | |
| f"{rel} reads {_FORBIDDEN} directly β this bypasses gated-mode auth " | |
| f"and 401/1008s on OAuth-gated dashboards. Use the plugin SDK instead: " | |
| f"SDK.fetchJSON (JSON), SDK.authedFetch (uploads/downloads), or " | |
| f"SDK.buildWsUrl (WebSockets). Offending lines:\n" + "\n".join(offending) | |
| ) | |