test: cover request debug dump redaction
Keep request dump writes on the shared atomic JSON path, add regression coverage for request body/error/stdout redaction, and map the salvaged contributor email for release attribution.
This commit is contained in:
@@ -1913,6 +1913,58 @@ def test_dump_api_request_debug_uses_chat_completions_url(monkeypatch, tmp_path)
|
||||
assert payload["request"]["url"] == "http://127.0.0.1:9208/v1/chat/completions"
|
||||
|
||||
|
||||
def test_dump_api_request_debug_redacts_request_and_error_secrets(monkeypatch, tmp_path, capsys):
|
||||
"""Request debug dumps should redact secrets before disk/stdout output."""
|
||||
import json
|
||||
|
||||
_patch_agent_bootstrap(monkeypatch)
|
||||
monkeypatch.setenv("HERMES_DUMP_REQUEST_STDOUT", "1")
|
||||
agent = run_agent.AIAgent(
|
||||
model="gpt-4o",
|
||||
base_url="http://127.0.0.1:9208/v1",
|
||||
api_key="sk-ant-providersecret1234567890",
|
||||
quiet_mode=True,
|
||||
max_iterations=1,
|
||||
skip_context_files=True,
|
||||
skip_memory=True,
|
||||
)
|
||||
agent.logs_dir = tmp_path
|
||||
|
||||
notion_token = "ntn_abc123def456ghi789jkl"
|
||||
error_secret = "sk-ant-errorsecret1234567890"
|
||||
response_secret = "sk-ant-responsesecret1234567890"
|
||||
response = SimpleNamespace(status_code=400, text=f"provider echoed {response_secret}")
|
||||
|
||||
class ProviderError(RuntimeError):
|
||||
body: object
|
||||
response: object
|
||||
|
||||
error = ProviderError(f"bad token {error_secret}")
|
||||
error.body = {"message": f"bad token {error_secret}"}
|
||||
error.response = response
|
||||
|
||||
dump_file = agent._dump_api_request_debug(
|
||||
{
|
||||
"model": "gpt-4o",
|
||||
"messages": [{"role": "user", "content": f"use {notion_token}"}],
|
||||
"metadata": {"NOTION_API_KEY": notion_token},
|
||||
},
|
||||
reason="provider_error",
|
||||
error=error,
|
||||
)
|
||||
|
||||
assert dump_file is not None
|
||||
dumped_text = dump_file.read_text()
|
||||
stdout_text = capsys.readouterr().out
|
||||
for raw in (notion_token, error_secret, response_secret, "providersecret1234567890"):
|
||||
assert raw not in dumped_text
|
||||
assert raw not in stdout_text
|
||||
|
||||
payload = json.loads(dumped_text)
|
||||
assert payload["request"]["headers"]["Authorization"].startswith("Bearer sk-ant-p...")
|
||||
assert "***" in dumped_text or "..." in dumped_text
|
||||
|
||||
|
||||
# --- Reasoning-only response tests (fix for empty content retry loop) ---
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user