Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(logs): redact sensitive headers #1850

Merged
merged 10 commits into from
Nov 6, 2024

Conversation

kristapratico
Copy link
Contributor

@kristapratico kristapratico commented Nov 5, 2024

  • I understand that this repository is auto-generated and my pull request may not be merged

Changes being requested

Adds a logging filter to the base client logger which redacts API keys and tokens from debug logs.

Additional context & links

closes #1082

@kristapratico kristapratico requested a review from a team as a code owner November 5, 2024 22:41
Copy link
Collaborator

@RobertCraigie RobertCraigie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Mostly minor nits

Comment on lines 33 to 38
if isinstance(record.args, dict) and "headers" in record.args:
if isinstance(record.args["headers"], dict):
logged_headers: Dict[str, Any] = record.args["headers"]
for header in logged_headers:
if header.lower() in ["api-key", "authorization"]:
logged_headers[header] = "<redacted>"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we have an is_dict() header that would make this slightly cleaner imo

Suggested change
if isinstance(record.args, dict) and "headers" in record.args:
if isinstance(record.args["headers"], dict):
logged_headers: Dict[str, Any] = record.args["headers"]
for header in logged_headers:
if header.lower() in ["api-key", "authorization"]:
logged_headers[header] = "<redacted>"
if is_dict(record.args) and "headers" in record.args and is_dict(record.args["headers"]):
headers = record.args["headers"]
for header in headers:
if str(header).lower() in ["api-key", "authorization"]:
headers[header] = "<redacted>"

and from ._utils import is_dict.

also a minor micro optimisation but I think we should extract the list of headers, e.g.

SENSITIVE_HEADERS = {"api-key", "authorization"}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also I haven't actually written a log filter before, is it bad that this mutates the original headers arg? i.e. should it be this?

            headers = record.args["headers"] = {**record.args["headers"]}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with your revisions, thanks! The logging docs for filter permits in-place modification:

If deemed appropriate, the record may be modified in-place.

src/openai/_utils/_logs.py Outdated Show resolved Hide resolved
tests/test_utils/test_logging.py Show resolved Hide resolved
@RobertCraigie RobertCraigie changed the title redact API key from debug logging fix(logs): redact sensitive headers Nov 6, 2024
Copy link
Collaborator

@RobertCraigie RobertCraigie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks Krista!



@pytest.mark.respx()
def test_azure_api_key_redacted(respx_mock: MockRouter, _logger_with_filter: logging.Logger, caplog: pytest.LogCaptureFixture) -> None:
Copy link
Collaborator

@RobertCraigie RobertCraigie Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I think you could've avoided the _logger_with_filter stuff by putting all these tests in a class and then doing

@pytest.fixture(autouse=True)
def _logger_with_filter() -> logging.Logger: ...

but totally not worth blocking on that change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Moved the tests in a class, however ruff still complains about the unused logger function, so kept it with underscore prefix.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah sorry tbc I meant that the class would just be for the logging tests as I assumed we wouldn't want the fixture to be setup for the other tests but if that would be fine then you don't need a class at all and it can just be at the module level

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! I completely misunderstood, my bad 😆. Updating...

@RobertCraigie
Copy link
Collaborator

ugh looks like mypy doesn't understand the type narrowing, feel free to just tell mypy to ignore that whole file. (that config is in mypy.ini::exclude

@RobertCraigie RobertCraigie changed the base branch from main to next November 6, 2024 21:17
@RobertCraigie RobertCraigie merged commit 466608f into openai:next Nov 6, 2024
2 checks passed
@stainless-app stainless-app bot mentioned this pull request Nov 6, 2024
stainless-app bot pushed a commit that referenced this pull request Nov 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

When debug logging is enabled, api-key header is also printed
2 participants