import logging import httpx import pytest from endpoint_monitor.checker import EndpointChecker, TargetBlockedError, validate_target from endpoint_monitor.logging import JsonFormatter, redact_url async def public_resolver(host: str, port: int) -> list[str]: return ["93.184.216.34"] @pytest.mark.parametrize("address", ["127.0.0.1", "10.0.0.1", "169.254.169.254", "::1", "fc00::1"]) async def test_dns_answers_block_non_public(address): async def resolver(host: str, port: int) -> list[str]: return [address] with pytest.raises(TargetBlockedError, match="non-public"): await validate_target("http://attacker.example/path", resolver) async def test_any_unsafe_dns_answer_blocks_target(): async def resolver(host: str, port: int) -> list[str]: return ["93.184.216.34", "127.0.0.1"] with pytest.raises(TargetBlockedError): await validate_target("https://mixed.example", resolver) async def test_redirect_hop_is_resolved_and_blocked(): seen = [] async def resolver(host: str, port: int) -> list[str]: seen.append(host) return ["127.0.0.1"] if host == "internal.example" else ["93.184.216.34"] def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(302, headers={"location": "http://internal.example/admin"}) checker = EndpointChecker(1, 3, resolver, httpx.MockTransport(handler)) with pytest.raises(TargetBlockedError): await checker.check("https://public.example/start", "id") assert seen == ["public.example", "internal.example"] async def test_success_latency_status_and_redaction(caplog): def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(503) checker = EndpointChecker(1, 1, public_resolver, httpx.MockTransport(handler)) with caplog.at_level(logging.INFO): result = await checker.check("https://example.com/path?token=supersecret#fragment", "abc") assert result.status.value == "down" assert result.http_status == 503 assert result.latency_ms >= 0 assert result.final_url == "https://example.com/path" assert "supersecret" not in caplog.text assert "fragment" not in caplog.text def test_redact_url_removes_credentials_query_fragment(): assert redact_url("https://user:pass@example.com:8443/a?q=secret#x") == "https://example.com:8443/a" def test_json_formatter_is_structured_and_does_not_add_message_secrets(): record = logging.LogRecord("x", logging.INFO, __file__, 1, "event", (), None) record.url = redact_url("https://example.com/?api_key=secret") rendered = JsonFormatter().format(record) assert '"event":"event"' in rendered assert "secret" not in rendered