fix(monitoring): address review — persist install_id, drop dead config, single redaction path
- Cut the leftover telemetry.* DEFAULT_CONFIG block (nothing reads it) and the legacy telemetry-key fallback in policy.py. - install_id: persist the minted UUID back to config.yaml on first use so service.instance.id survives gateway restarts (fail-open when the write is not possible); regression test covers the restart path. - Remove the no-op gateway_health_export.redaction config keys. Redaction is always-on by design and deliberately not configurable; status output now says so. - Collapse redaction to one unconditional secrets+PII scrub: drop the none/pii content modes (they served the dropped trajectories plane) and fold gateway_health.py's duplicate bearer/token/email/phone regex layer into agent/monitoring/redaction.py.
This commit is contained in:
committed by
Victor Kyriazakos
parent
505d12f662
commit
87a15733c0
@@ -1,56 +1,69 @@
|
||||
"""Export redaction pipeline tests — the security-critical layer.
|
||||
"""Export redaction tests — the security-critical layer.
|
||||
|
||||
Invariants:
|
||||
* Secrets ALWAYS stripped, every export path, no flag disables it.
|
||||
* One unconditional scrub: secrets AND PII, no modes, no knobs.
|
||||
* Fails CLOSED: if the redactor can't run, the raw string is never emitted.
|
||||
* PII (emails, phones, UUID-shaped ids) stripped in 'pii' mode — the mode
|
||||
the gateway diagnostics path always uses.
|
||||
* Structure (subsystem names, error codes) survives; free-text PII does not.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import agent.monitoring.redaction as R
|
||||
|
||||
|
||||
def test_secret_always_stripped_in_none_mode():
|
||||
def test_secret_key_always_stripped():
|
||||
fake_key = "sk-ant-api03-" + "A" * 24 # constructed to dodge literal-scrubbers
|
||||
text = f"calling with key {fake_key} and moving on"
|
||||
out = R.redact_for_export(text, content_mode=R.CONTENT_NONE)
|
||||
out = R.redact_for_export(f"calling with key {fake_key} and moving on")
|
||||
assert out is not None
|
||||
assert fake_key not in out
|
||||
|
||||
|
||||
def test_secret_always_stripped_in_pii_mode():
|
||||
fake_token = "ghp_" + "0123456789abcdef" * 2 + "0123"
|
||||
text = f"token {fake_token} leaked"
|
||||
out = R.redact_for_export(text, content_mode=R.CONTENT_PII)
|
||||
def test_token_shapes_stripped():
|
||||
ghp = "ghp_" + "0123456789abcdef" * 2 + "0123"
|
||||
slack = "xoxb-" + "123456789012-abcdefABCDEF"
|
||||
out = R.redact_for_export(f"token {ghp} and {slack} leaked")
|
||||
assert out is not None
|
||||
assert fake_token not in out
|
||||
assert ghp not in out
|
||||
assert slack not in out
|
||||
assert "[redacted]" in out
|
||||
|
||||
|
||||
def test_bearer_header_stripped():
|
||||
out = R.redact_for_export("Authorization: Bearer abc.def-ghi_jkl")
|
||||
assert out is not None
|
||||
assert "abc.def-ghi_jkl" not in out
|
||||
|
||||
|
||||
def test_none_passthrough():
|
||||
assert R.redact_for_export(None, content_mode=R.CONTENT_NONE) is None
|
||||
assert R.redact_for_export(None) is None
|
||||
|
||||
|
||||
def test_pii_mode_strips_email_phone_uuid():
|
||||
def test_pii_always_stripped():
|
||||
text = ("reach alice@example.com or +1 415 555 0100, "
|
||||
"install 123e4567-e89b-12d3-a456-426614174000")
|
||||
out = R.redact_for_export(text, content_mode=R.CONTENT_PII)
|
||||
out = R.redact_for_export(text)
|
||||
assert out is not None
|
||||
assert "alice@example.com" not in out
|
||||
assert "426614174000" not in out
|
||||
assert "[email]" in out
|
||||
assert "[id]" in out
|
||||
assert "[phone]" in out
|
||||
|
||||
|
||||
def test_none_mode_keeps_ordinary_words():
|
||||
out = R.redact_for_export("just ordinary words", content_mode=R.CONTENT_NONE)
|
||||
assert out == "just ordinary words"
|
||||
def test_ordinary_words_survive():
|
||||
assert R.redact_for_export("just ordinary words") == "just ordinary words"
|
||||
|
||||
|
||||
def test_pii_mode_preserves_non_pii_structure():
|
||||
text = "platform.slack entered fatal after auth_failed"
|
||||
out = R.redact_for_export(text, content_mode=R.CONTENT_PII)
|
||||
def test_structure_preserved():
|
||||
out = R.redact_for_export("platform.slack entered fatal after auth_failed")
|
||||
assert out is not None
|
||||
assert "platform.slack" in out
|
||||
assert "auth_failed" in out
|
||||
|
||||
|
||||
def test_fails_closed_when_redactor_unavailable():
|
||||
with mock.patch("agent.redact.redact_sensitive_text", side_effect=RuntimeError):
|
||||
out = R.redact_for_export("secret sauce sk-live-key")
|
||||
assert out == "[redaction-unavailable]"
|
||||
|
||||
@@ -14,8 +14,8 @@ def test_default_config_keeps_gateway_health_export_disabled():
|
||||
assert cfg["warning_error_events_enabled"] is True
|
||||
assert cfg["export_interval_seconds"] == 60
|
||||
assert cfg["logs_export_interval_seconds"] == 5
|
||||
assert cfg["redaction"]["enabled"] is True
|
||||
assert cfg["redaction"]["include_raw_stack"] is False
|
||||
# Redaction is always-on and deliberately NOT configurable.
|
||||
assert "redaction" not in cfg
|
||||
|
||||
|
||||
def test_gateway_health_snapshot_maps_runtime_status_to_low_cardinality_metrics():
|
||||
@@ -340,3 +340,25 @@ def test_gateway_diagnostic_log_handler_never_raises_on_malformed_record():
|
||||
)
|
||||
|
||||
handler.emit(record)
|
||||
|
||||
|
||||
def test_install_id_persists_across_calls(tmp_path, monkeypatch):
|
||||
"""A minted install id must survive restarts (service.instance.id continuity)."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
(tmp_path / "config.yaml").write_text("{}\n")
|
||||
|
||||
import hermes_cli.config as cfg_mod
|
||||
from agent.monitoring.policy import ensure_install_id
|
||||
|
||||
first = ensure_install_id(cfg_mod.load_config())
|
||||
assert first and first != "unknown"
|
||||
# Persisted: a fresh load (simulating a new gateway process) returns the same id.
|
||||
second = ensure_install_id(cfg_mod.load_config())
|
||||
assert second == first
|
||||
assert first in (tmp_path / "config.yaml").read_text()
|
||||
|
||||
|
||||
def test_install_id_existing_value_wins(monkeypatch):
|
||||
from agent.monitoring.policy import ensure_install_id
|
||||
|
||||
assert ensure_install_id({"monitoring": {"install_id": "keep-me"}}) == "keep-me"
|
||||
|
||||
Reference in New Issue
Block a user