Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions plugins/observability/langfuse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ def _env(name: str, default: str = "") -> str:
return os.environ.get(name, default).strip()


_PLACEHOLDER_CREDENTIAL_VALUES = {
"*",
"**",
"***",
"changeme",
"your_api_key",
"your-api-key",
"placeholder",
"example",
"dummy",
"null",
"none",
"test-key",
}


def _looks_placeholder_credential(value: str) -> bool:
cleaned = value.strip()
if not cleaned:
return True
return cleaned.lower() in _PLACEHOLDER_CREDENTIAL_VALUES


def _env_bool(*names: str) -> bool:
for name in names:
value = _env(name).lower()
Expand Down Expand Up @@ -110,6 +133,13 @@ def _get_langfuse() -> Optional[Langfuse]:
if not (public_key and secret_key):
_LANGFUSE_CLIENT = _INIT_FAILED
return None
if _looks_placeholder_credential(public_key) or _looks_placeholder_credential(secret_key):
logger.warning(
"Langfuse tracing disabled: placeholder credentials detected. "
"Set real HERMES_LANGFUSE_PUBLIC_KEY / HERMES_LANGFUSE_SECRET_KEY values."
)
_LANGFUSE_CLIENT = _INIT_FAILED
return None

base_url = _env("HERMES_LANGFUSE_BASE_URL") or _env("LANGFUSE_BASE_URL") or "https://cloud.langfuse.com"
environment = _env("HERMES_LANGFUSE_ENV") or _env("LANGFUSE_ENV")
Expand Down
11 changes: 11 additions & 0 deletions tests/plugins/test_langfuse_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ def test_get_langfuse_returns_none_without_credentials(self, monkeypatch):
langfuse_plugin = self._fresh_plugin()
assert langfuse_plugin._get_langfuse() is None

def test_get_langfuse_rejects_placeholder_credentials(self, monkeypatch, caplog):
monkeypatch.setenv("HERMES_LANGFUSE_PUBLIC_KEY", "placeholder")
monkeypatch.setenv("HERMES_LANGFUSE_SECRET_KEY", "test-key")

langfuse_plugin = self._fresh_plugin()
monkeypatch.setattr(langfuse_plugin, "Langfuse", lambda **kwargs: object())
caplog.set_level("WARNING")

assert langfuse_plugin._get_langfuse() is None
assert "placeholder credentials detected" in caplog.text.lower()

def test_get_langfuse_caches_failure_no_config_load(self, monkeypatch):
"""A miss must be cached β€” no per-hook config.yaml reads, no env re-reads."""
for k in (
Expand Down
Loading