feat(dashboard): catalogue all memory-provider API keys in OPTIONAL_ENV_VARS

The dashboard Keys page and `hermes setup` render API-key rows from
OPTIONAL_ENV_VARS, but only Honcho had an entry — so Hindsight,
Supermemory, Mem0, RetainDB, ByteRover, and OpenViking read their keys
straight from os.environ yet had no place to set them in the GUI.

Add catalog entries (category=tool, password-masked, with get-key URLs
and the tool each powers) for all six, plus the relevant base-URL/endpoint
companions. Pure declaration: the generic GET /api/env endpoint, the
save/reveal write path, and the sandbox env blocklist (which auto-derives
from tool-category OPTIONAL_ENV_VARS) all pick these up with no further
wiring.

Adds a behavior-contract test asserting every memory provider's primary
credential key is catalogued, tool-categorised, and password-masked.
This commit is contained in:
Ben 2026-06-29 11:10:15 +10:00 committed by Teknium
parent c8fd47be14
commit dee41d0716
2 changed files with 120 additions and 0 deletions

View file

@ -700,6 +700,49 @@ class TestOptionalEnvVarsRegistry:
assert "HERMES_MAX_ITERATIONS" not in OPTIONAL_ENV_VARS
class TestMemoryProviderEnvVarsRegistry:
"""Every memory provider that reads an API key from the environment must
have that key catalogued in OPTIONAL_ENV_VARS so the dashboard Keys page
and `hermes setup` surface it (previously only Honcho was listed, leaving
Hindsight/Supermemory/Mem0/RetainDB/ByteRover/OpenViking invisible).
This is a behavior contract, not a snapshot: it asserts each provider's
primary credential key is present, tool-categorised, and password-masked
not a frozen count of entries.
"""
# provider primary-credential env key -> the tool-call name it powers.
MEMORY_PROVIDER_KEYS = {
"HONCHO_API_KEY": "honcho_context",
"HINDSIGHT_API_KEY": "hindsight_recall",
"SUPERMEMORY_API_KEY": "supermemory_search",
"MEM0_API_KEY": "mem0_search",
"RETAINDB_API_KEY": "retaindb_search",
"BRV_API_KEY": "brv_query",
"OPENVIKING_API_KEY": "viking_search",
}
def test_memory_provider_keys_are_catalogued(self):
from hermes_cli.config import OPTIONAL_ENV_VARS
missing = [k for k in self.MEMORY_PROVIDER_KEYS if k not in OPTIONAL_ENV_VARS]
assert not missing, f"memory provider keys missing from OPTIONAL_ENV_VARS: {missing}"
def test_memory_provider_keys_are_tool_category(self):
from hermes_cli.config import OPTIONAL_ENV_VARS
for key in self.MEMORY_PROVIDER_KEYS:
assert OPTIONAL_ENV_VARS[key]["category"] == "tool", key
def test_memory_provider_keys_are_password_masked(self):
from hermes_cli.config import OPTIONAL_ENV_VARS
for key in self.MEMORY_PROVIDER_KEYS:
assert OPTIONAL_ENV_VARS[key].get("password") is True, key
def test_memory_provider_keys_advertise_their_tool(self):
from hermes_cli.config import OPTIONAL_ENV_VARS
for key, tool in self.MEMORY_PROVIDER_KEYS.items():
assert tool in OPTIONAL_ENV_VARS[key].get("tools", []), key
class TestConfigMigrationSecretPrompts:
def test_required_secret_env_prompt_uses_masked_prompt(self, tmp_path, monkeypatch):
from hermes_cli import config as cfg_mod