main
  1import logging
  2from typing import Any, Dict, cast
  3
  4import pytest
  5
  6from openai._utils import SensitiveHeadersFilter
  7
  8
  9@pytest.fixture
 10def logger_with_filter() -> logging.Logger:
 11    logger = logging.getLogger("test_logger")
 12    logger.setLevel(logging.DEBUG)
 13    logger.addFilter(SensitiveHeadersFilter())
 14    return logger
 15
 16
 17def test_keys_redacted(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
 18    with caplog.at_level(logging.DEBUG):
 19        logger_with_filter.debug(
 20            "Request options: %s",
 21            {
 22                "method": "post",
 23                "url": "chat/completions",
 24                "headers": {"api-key": "12345", "Authorization": "Bearer token"},
 25            },
 26        )
 27
 28    log_record = cast(Dict[str, Any], caplog.records[0].args)
 29    assert log_record["method"] == "post"
 30    assert log_record["url"] == "chat/completions"
 31    assert log_record["headers"]["api-key"] == "<redacted>"
 32    assert log_record["headers"]["Authorization"] == "<redacted>"
 33    assert (
 34        caplog.messages[0]
 35        == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'api-key': '<redacted>', 'Authorization': '<redacted>'}}"
 36    )
 37
 38
 39def test_keys_redacted_case_insensitive(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
 40    with caplog.at_level(logging.DEBUG):
 41        logger_with_filter.debug(
 42            "Request options: %s",
 43            {
 44                "method": "post",
 45                "url": "chat/completions",
 46                "headers": {"Api-key": "12345", "authorization": "Bearer token"},
 47            },
 48        )
 49
 50    log_record = cast(Dict[str, Any], caplog.records[0].args)
 51    assert log_record["method"] == "post"
 52    assert log_record["url"] == "chat/completions"
 53    assert log_record["headers"]["Api-key"] == "<redacted>"
 54    assert log_record["headers"]["authorization"] == "<redacted>"
 55    assert (
 56        caplog.messages[0]
 57        == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'Api-key': '<redacted>', 'authorization': '<redacted>'}}"
 58    )
 59
 60
 61def test_no_headers(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
 62    with caplog.at_level(logging.DEBUG):
 63        logger_with_filter.debug(
 64            "Request options: %s",
 65            {"method": "post", "url": "chat/completions"},
 66        )
 67
 68    log_record = cast(Dict[str, Any], caplog.records[0].args)
 69    assert log_record["method"] == "post"
 70    assert log_record["url"] == "chat/completions"
 71    assert "api-key" not in log_record
 72    assert "Authorization" not in log_record
 73    assert caplog.messages[0] == "Request options: {'method': 'post', 'url': 'chat/completions'}"
 74
 75
 76def test_headers_without_sensitive_info(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
 77    with caplog.at_level(logging.DEBUG):
 78        logger_with_filter.debug(
 79            "Request options: %s",
 80            {
 81                "method": "post",
 82                "url": "chat/completions",
 83                "headers": {"custom": "value"},
 84            },
 85        )
 86
 87    log_record = cast(Dict[str, Any], caplog.records[0].args)
 88    assert log_record["method"] == "post"
 89    assert log_record["url"] == "chat/completions"
 90    assert log_record["headers"] == {"custom": "value"}
 91    assert (
 92        caplog.messages[0]
 93        == "Request options: {'method': 'post', 'url': 'chat/completions', 'headers': {'custom': 'value'}}"
 94    )
 95
 96
 97def test_standard_debug_msg(logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
 98    with caplog.at_level(logging.DEBUG):
 99        logger_with_filter.debug("Sending HTTP Request: %s %s", "POST", "chat/completions")
100    assert caplog.messages[0] == "Sending HTTP Request: POST chat/completions"