diff --git a/CHANGES/7237.bugfix b/CHANGES/7237.bugfix new file mode 100644 index 00000000000..26f85ea9c95 --- /dev/null +++ b/CHANGES/7237.bugfix @@ -0,0 +1 @@ +Fixed ``PermissionError`` when .netrc is unreadable due to permissions. diff --git a/aiohttp/helpers.py b/aiohttp/helpers.py index bc116c3ae32..fa7b8a2ace7 100644 --- a/aiohttp/helpers.py +++ b/aiohttp/helpers.py @@ -3,6 +3,7 @@ import asyncio import base64 import binascii +import contextlib import dataclasses import datetime import enum @@ -213,8 +214,11 @@ def netrc_from_env() -> Optional[netrc.netrc]: except netrc.NetrcParseError as e: client_logger.warning("Could not parse .netrc file: %s", e) except OSError as e: + netrc_exists = False + with contextlib.suppress(OSError): + netrc_exists = netrc_path.is_file() # we couldn't read the file (doesn't exist, permissions, etc.) - if netrc_env or netrc_path.is_file(): + if netrc_env or netrc_exists: # only warn if the environment wanted us to load it, # or it appears like the default file does actually exist client_logger.warning("Could not read .netrc file: %s", e) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index aa1dcf6b214..0f37089d59f 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -6,6 +6,7 @@ import platform import weakref from math import ceil, modf +from pathlib import Path from unittest import mock from urllib.request import getproxies_environment @@ -993,6 +994,26 @@ def test_netrc_from_env(expected_username: str): assert netrc_obj.authenticators("example.com")[0] == expected_username +@pytest.fixture +def protected_dir(tmp_path: Path): + protected_dir = tmp_path / "protected" + protected_dir.mkdir() + try: + protected_dir.chmod(0o600) + yield protected_dir + finally: + protected_dir.rmdir() + + +def test_netrc_from_home_does_not_raise_if_access_denied( + protected_dir: Path, monkeypatch: pytest.MonkeyPatch +): + monkeypatch.setattr(Path, "home", lambda: protected_dir) + monkeypatch.delenv("NETRC", raising=False) + + helpers.netrc_from_env() + + @pytest.mark.parametrize( ["netrc_contents", "expected_auth"], [