Add sanitized fetch health for agents

This commit is contained in:
nzinci
2026-07-30 22:24:25 +03:00
parent d38c886af9
commit 1f903e1b7c
8 changed files with 170 additions and 1 deletions
+64 -1
View File
@@ -1,4 +1,23 @@
from services.fetch_health import record_success, record_failure, get_health_snapshot
import json
import pytest
from services import fetch_health
from services.fetch_health import (
get_agent_health_snapshot,
get_health_snapshot,
record_failure,
record_success,
)
@pytest.fixture(autouse=True)
def clear_fetch_health():
with fetch_health._lock:
fetch_health._health.clear()
yield
with fetch_health._lock:
fetch_health._health.clear()
def test_record_success_and_failure():
@@ -13,3 +32,47 @@ def test_record_success_and_failure():
assert entry["last_ok"] is not None
assert entry["last_error"] is not None
assert entry["last_duration_ms"] is not None
def test_agent_health_snapshot_is_sanitized():
fake_secret = "RECOGNIZABLE_FAKE_SECRET_FOR_FETCH_HEALTH"
entry = {
"ok_count": 3,
"error_count": 2,
"last_ok": "2026-07-30T12:00:00.000000",
"last_error": "2026-07-30T11:00:00.000000",
"last_error_msg": f"upstream failed with {fake_secret}",
"last_duration_ms": 125.4,
"avg_duration_ms": 98.7,
"last_count": 42,
}
with fetch_health._lock:
fetch_health._health["latest_success"] = dict(entry)
fetch_health._health["latest_failure"] = {
**entry,
"last_ok": "2026-07-30T10:00:00.000000",
"last_error": "2026-07-30T13:00:00.000000",
}
snapshot = get_agent_health_snapshot()
assert {key: value for key, value in snapshot.items() if key != "tasks"} == {
"scope": "process",
"persistent": False,
"observed_only": True,
"semantics": "latest_recorded_task_outcome",
}
safe_fields = {
"condition",
"ok_count",
"error_count",
"last_ok",
"last_error",
"last_duration_ms",
}
assert set(snapshot["tasks"]["latest_success"]) == safe_fields
assert snapshot["tasks"]["latest_success"]["condition"] == "healthy"
assert snapshot["tasks"]["latest_failure"]["condition"] == "degraded"
serialized = json.dumps(snapshot)
assert "last_error_msg" not in serialized
assert fake_secret not in serialized
@@ -130,6 +130,32 @@ class TestAuthenticatedRequestSucceeds:
tool_names = {tool["name"] for tool in data["tools"]}
assert set(data["available_commands"]).issubset(tool_names)
def test_fetch_health_read_command_dispatch_and_discovery(self, remote_client):
from services.openclaw_channel import READ_COMMANDS, _dispatch_command
snapshot = {
"scope": "process",
"persistent": False,
"observed_only": True,
"semantics": "latest_recorded_task_outcome",
"tasks": {},
}
with patch(
"services.fetch_health.get_agent_health_snapshot", return_value=snapshot
):
result = _dispatch_command("get_fetch_health", {})
assert "get_fetch_health" in READ_COMMANDS
assert result == {"ok": True, "data": snapshot}
headers = _sign("GET", "/api/ai/tools")
r = remote_client.get("/api/ai/tools", headers=headers)
assert r.status_code == 200, r.text
tool = next(
tool for tool in r.json()["tools"] if tool["name"] == "get_fetch_health"
)
assert tool["parameters"] == {}
# ---------------------------------------------------------------------------
# 2. Tampered body rejected (P1A body-binding at route layer)
+23
View File
@@ -1,5 +1,6 @@
"""Regression coverage for OpenClaw skill HMAC environment names."""
import asyncio
import importlib.util
from pathlib import Path
@@ -36,3 +37,25 @@ def test_openclaw_skill_accepts_legacy_key_as_hmac_secret_alias(monkeypatch):
assert "X-SB-Signature" in headers
assert "Authorization" not in headers
assert "X-Admin-Key" not in headers
def test_openclaw_skill_get_fetch_health_unwraps_command_result(monkeypatch):
module = _load_sb_query(monkeypatch)
client = module.ShadowBrokerClient()
commands = []
async def send_command(cmd, args=None):
commands.append((cmd, args))
return {
"result": {
"ok": True,
"data": {"scope": "process", "tasks": {}},
}
}
monkeypatch.setattr(client, "send_command", send_command)
result = asyncio.run(client.get_fetch_health())
assert commands == [("get_fetch_health", None)]
assert result == {"scope": "process", "tasks": {}}