fix(urllib): log the default-certificates fallback once, after every bundle failed
Each failed candidate used to claim "falling back to default certificates" even when the next candidate (certifi on macOS) loaded fine. Per-failure warnings now say "trying the next bundle"; the default-certificates warning is emitted once at the final (None, None) return. Level unchanged (WARNING). PROOF: test_default_certificates_fallback_is_logged_once_after_all_bundles_fail fails on the previous per-candidate wording and passes with this change; tests/hermes_cli/test_urllib_security.py 22 passed.
This commit is contained in:
@@ -167,9 +167,9 @@ def _build_https_context(candidates: tuple[str, ...]) -> tuple[ssl.SSLContext |
|
|||||||
try:
|
try:
|
||||||
return ssl.create_default_context(cafile=path), path
|
return ssl.create_default_context(cafile=path), path
|
||||||
except (OSError, ssl.SSLError) as exc:
|
except (OSError, ssl.SSLError) as exc:
|
||||||
logger.warning(
|
logger.warning("CA bundle could not be loaded from %s: %s — trying the next bundle", path, exc)
|
||||||
"CA bundle could not be loaded from %s: %s — falling back to default certificates", path, exc
|
if candidates:
|
||||||
)
|
logger.warning("No configured CA bundle could be loaded — falling back to default certificates")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
import ssl
|
import ssl
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@@ -600,6 +601,30 @@ def test_fallback_bundle_change_does_not_invalidate_the_memo(monkeypatch, tmp_pa
|
|||||||
assert calls == [str(preferred)]
|
assert calls == [str(preferred)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_certificates_fallback_is_logged_once_after_all_bundles_fail(monkeypatch, caplog):
|
||||||
|
"""A failed candidate says "trying the next bundle"; the default-certificates line is emitted once."""
|
||||||
|
import hermes_cli.urllib_security as urllib_security
|
||||||
|
|
||||||
|
def create_default_context(*, cafile=None):
|
||||||
|
raise ssl.SSLError(f"bad bundle {cafile}")
|
||||||
|
|
||||||
|
monkeypatch.setattr(ssl, "create_default_context", create_default_context)
|
||||||
|
|
||||||
|
with caplog.at_level(logging.WARNING, logger=urllib_security.logger.name):
|
||||||
|
assert urllib_security._build_https_context(("/a.pem", "/b.pem")) == (None, None)
|
||||||
|
|
||||||
|
messages = [record.getMessage() for record in caplog.records]
|
||||||
|
per_failure = [m for m in messages if "trying the next bundle" in m]
|
||||||
|
assert [m.split(":")[0] for m in per_failure] == [
|
||||||
|
"CA bundle could not be loaded from /a.pem",
|
||||||
|
"CA bundle could not be loaded from /b.pem",
|
||||||
|
]
|
||||||
|
assert [m for m in messages if "falling back to default certificates" in m] == [
|
||||||
|
"No configured CA bundle could be loaded — falling back to default certificates"
|
||||||
|
]
|
||||||
|
assert all(record.levelno == logging.WARNING for record in caplog.records)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("candidates", "first_load_fails_for", "expected_load_sequence"),
|
("candidates", "first_load_fails_for", "expected_load_sequence"),
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user