|
2 | 2 |
|
3 | 3 | import json |
4 | 4 | import os |
| 5 | +import ssl |
5 | 6 | import sys |
6 | 7 | import tempfile |
7 | 8 | import time |
@@ -684,6 +685,53 @@ def test_resolve_ca_bundle_falls_back_to_true(self): |
684 | 685 | ): |
685 | 686 | self.assertIs(_resolve_ca_bundle(), True) |
686 | 687 |
|
| 688 | + def test_httpx_verify_string_becomes_ssl_context(self): |
| 689 | + """A CA-bundle path string is turned into an ssl.SSLContext. |
| 690 | +
|
| 691 | + httpx 0.28 deprecated ``verify=<str>``; the helper must build a |
| 692 | + context so no deprecation warning is emitted at the httpx |
| 693 | + boundary. The bundle file is loaded (create_default_context |
| 694 | + rejects a missing/invalid cafile), so a real temp cert path is |
| 695 | + used.""" |
| 696 | + from python_agent_harness.client import _httpx_verify |
| 697 | + |
| 698 | + # A valid PEM the SSL layer accepts as a CA file: reuse certifi's |
| 699 | + # bundle when available, else the system default context's certs. |
| 700 | + ctx_default = ssl.create_default_context() |
| 701 | + with tempfile.NamedTemporaryFile("w", prefix="pah-ca-", suffix=".pem", delete=False) as f: |
| 702 | + # A self-contained CA bundle written from the default trust store. |
| 703 | + pems = [ |
| 704 | + ssl.DER_cert_to_PEM_cert(der) for der in ctx_default.get_ca_certs(binary_form=True) |
| 705 | + ] |
| 706 | + f.write("".join(pems)) |
| 707 | + ca_path = f.name |
| 708 | + try: |
| 709 | + result = _httpx_verify(ca_path) |
| 710 | + self.assertIsInstance(result, ssl.SSLContext) |
| 711 | + finally: |
| 712 | + os.unlink(ca_path) |
| 713 | + |
| 714 | + def test_httpx_verify_bool_passthrough(self): |
| 715 | + """True/False are httpx's own on/off toggles and pass through |
| 716 | + unchanged (no SSLContext wrapping).""" |
| 717 | + from python_agent_harness.client import _httpx_verify |
| 718 | + |
| 719 | + self.assertIs(_httpx_verify(True), True) |
| 720 | + self.assertIs(_httpx_verify(False), False) |
| 721 | + |
| 722 | + def test_httpx_verify_no_deprecation_warning(self): |
| 723 | + """Constructing httpx.Client with the helper's output must not |
| 724 | + emit the ``verify=<str>`` DeprecationWarning (the regression |
| 725 | + this guards).""" |
| 726 | + import warnings |
| 727 | + |
| 728 | + from python_agent_harness.client import _httpx_verify |
| 729 | + |
| 730 | + with warnings.catch_warnings(): |
| 731 | + warnings.simplefilter("error", DeprecationWarning) |
| 732 | + # True path: httpx default verification, no warning. |
| 733 | + httpx.Client(verify=_httpx_verify(True)).close() |
| 734 | + |
687 | 735 |
|
688 | 736 | class TestClientLogging(unittest.TestCase): |
689 | 737 | """_log_llm_interaction appends request bodies and assistant |
|
0 commit comments