jaraco / keyring

MIT License
1.24k stars 152 forks source link

"Keyring config file contains incorrect values." when no config exists #635

Closed ThimoNeubauer closed 1 year ago

ThimoNeubauer commented 1 year ago

Since our CI upgraded to keyring 24.0.0 we keep seeing messages

Keyring config file contains incorrect values.
Config file: /u/users/svc_emag_kpi/.config/python_keyring/keyringrc.cfg

in our logging. That is slightly surprising because that file doesn't even exist:

[svc_emag_kpi@emag-kpis tmp]$ file /u/users/svc_emag_kpi/.config/python_keyring/keyringrc.cfg
/u/users/svc_emag_kpi/.config/python_keyring/keyringrc.cfg: cannot open (No such file or directory)

Here is a small reproducer using Python 3.8 on a CentOS 7 machine:

[svc_emag_kpi@emag-kpis ~]$ cd /tmp
[svc_emag_kpi@emag-kpis tmp]$ python3.8 -m venv keyring
[svc_emag_kpi@emag-kpis tmp]$ keyring/bin/python -m pip install keyring
... blah blah blah ...
Successfully installed SecretStorage-3.3.3 cffi-1.15.1 cryptography-41.0.1 importlib-metadata-6.7.0 importlib-resources-5.12.0 jaraco.classes-3.2.3 jeepney-0.8.0 keyring-24.0.0 more-itertools-9.1.0 pycparser-2.21 zipp-3.15.0
WARNING: You are using pip version 19.3.1; however, version 23.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
[svc_emag_kpi@emag-kpis tmp]$ keyring/bin/python
Python 3.8.6 (default, Oct 27 2020, 09:13:12)
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import keyring
>>> keyring.get_password("foo", "bar")
Keyring config file contains incorrect values.
Config file: /u/users/svc_emag_kpi/.config/python_keyring/keyringrc.cfg
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/keyring/lib64/python3.8/site-packages/keyring/core.py", line 56, in get_password
    return get_keyring().get_password(service_name, username)
  File "/tmp/keyring/lib64/python3.8/site-packages/keyring/backends/fail.py", line 28, in get_password
    raise NoKeyringError(msg)
keyring.errors.NoKeyringError: No recommended backend was available. Install a recommended 3rd party backend package; or, install the keyrings.alt package if you want to use the non-recommended backends. See https://pypi.org/project/keyring for details.
>>>

Before you ask: in our production code we catch the "NoKeyringError" and just continue. There's sense in a portable code that stuff might come from keyring (e.g. on Windows) and ignore anything else.

ThimoNeubauer commented 1 year ago

As a cross-check (CentOS 7 is old, the Python 3.8 there compiled by us) I ran the reproducer in a Rockylinux 9 container. Same result:

[root@rocky tmp]# python3 -m venv keyring
[root@rocky tmp]# keyring/bin/python -m pip install keyring
... blah blah blah...
Successfully installed SecretStorage-3.3.3 cffi-1.15.1 cryptography-41.0.1 importlib-metadata-6.7.0 jaraco.classes-3.2.3 jeepney-0.8.0 keyring-24.0.0 more-itertools-9.1.0 pycparser-2.21 zipp-3.15.0
WARNING: You are using pip version 21.2.3; however, version 23.1.2 is available.
You should consider upgrading via the '/tmp/keyring/bin/python -m pip install --upgrade pip' command.
[root@rocky tmp]# keyring/bin/python
Python 3.9.14 (main, Nov  7 2022, 00:00:00)
[GCC 11.3.1 20220421 (Red Hat 11.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import keyring
>>> keyring.get_password("foo", "bar")
Keyring config file contains incorrect values.
Config file: /root/.config/python_keyring/keyringrc.cfg
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/keyring/lib64/python3.9/site-packages/keyring/core.py", line 56, in get_password
    return get_keyring().get_password(service_name, username)
  File "/tmp/keyring/lib64/python3.9/site-packages/keyring/backends/fail.py", line 28, in get_password
    raise NoKeyringError(msg)
keyring.errors.NoKeyringError: No recommended backend was available. Install a recommended 3rd party backend package; or, install the keyrings.alt package if you want to use the non-recommended backends. See https://pypi.org/project/keyring for details.
>>>

Additionally I checked that this is indeed a regression:

[root@rocky tmp]# python3 -m venv old_keyring
[root@rocky tmp]# old_keyring/bin/python -m pip install 'keyring<24.0.0'
... blah blah blah ...
Successfully installed SecretStorage-3.3.3 cffi-1.15.1 cryptography-41.0.1 importlib-metadata-6.7.0 jaraco.classes-3.2.3 jeepney-0.8.0 keyring-23.13.1 more-itertools-9.1.0 pycparser-2.21 zipp-3.15.0
WARNING: You are using pip version 21.2.3; however, version 23.1.2 is available.
You should consider upgrading via the '/tmp/old_keyring/bin/python -m pip install --upgrade pip' command.
[root@rocky tmp]# old_keyring/bin/python
Python 3.9.14 (main, Nov  7 2022, 00:00:00)
[GCC 11.3.1 20220421 (Red Hat 11.3.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import keyring
>>> keyring.get_password("foo", "bar")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/old_keyring/lib64/python3.9/site-packages/keyring/core.py", line 55, in get_password
    return get_keyring().get_password(service_name, username)
  File "/tmp/old_keyring/lib64/python3.9/site-packages/keyring/backends/fail.py", line 25, in get_password
    raise NoKeyringError(msg)
keyring.errors.NoKeyringError: No recommended backend was available. Install a recommended 3rd party backend package; or, install the keyrings.alt package if you want to use the non-recommended backends. See https://pypi.org/project/keyring for details.
>>>
natehardison commented 1 year ago

I see this as well on macOS 13.4. Since it's just a warning message, I'm still able to successfully set / get items from the keychain, but the messages are confusing.

vbrett commented 1 year ago

Just have the same behavior on my side. I have no cfg file, still "Keyring config file contains incorrect values." warning message is displayed

working on Windows 11

damarvin commented 1 year ago

Just have the same behavior on my side. I have no cfg file, still "Keyring config file contains incorrect values." warning message is displayed

working on Windows 11

I see this ...\AppData\Local\Python Keyring\keyringrc.cfg too, never used such, just the Windows Credentials. I need to give keyring<24 in the requirements to make it work as expected.

jaraco commented 1 year ago

Here are the differences.

jaraco commented 1 year ago

Probably 104c130d597589a753b72aaa6f15d63c0fbe482b is to blame.

vbrett commented 1 year ago

Confirm the warning has disappeared. Thanks for the fix!

zoni commented 1 year ago

@jaraco I realize all the tests pass, but didn't https://github.com/jaraco/keyring/commit/e4c7d96acdadd052a7ad009f512d98e746a2d378 just break this for cases where a config file does exist?

I'm hitting:

  File "/home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py", line 33, in get_keyring
    init_backend()
  File "/home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py", line 84, in init_backend
    set_keyring(_detect_backend(limit))
                ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py", line 99, in _detect_backend
    or load_config()
       ^^^^^^^^^^^^^
  File "/home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py", line 163, in load_config
    config.read(_ensure_path(_config_path()), encoding="utf-8")
  File "/usr/lib/python3.11/configparser.py", line 710, in read
    for filename in filenames:
TypeError: 'NoneType' object is not iterable

..with a config file, and the error goes away when the config file doesn't exist.

Looking at the code in question, my LSP immediately throws type errors:

➜  pyright /home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py
/home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py
  /home/zoni/.local/pipx/venvs/ansible/lib/python3.11/site-packages/keyring/core.py:163:21 - error: Argument of type "None" cannot be assigned to parameter "filenames" of type "StrOrBytesPath | Iterable[StrOrBytesPath]" in function "read"
    Type "None" cannot be assigned to type "StrOrBytesPath | Iterable[StrOrBytesPath]"
      Type "None" cannot be assigned to type "str"
      Type "None" cannot be assigned to type "bytes"
      "__fspath__" is not present
      "__fspath__" is not present
      "__iter__" is not present (reportGeneralTypeIssues)
1 error, 0 warnings, 0 informations

In the case where a config file DOES exist, this line:

config.read(_ensure_path(_config_path()), encoding="utf-8")

causes _config_path() to return None, which then gets passed to config.read() which causes the exception.

I'm pretty sure you'd want _ensure_path to look as follows (note the addition of the return):

def _ensure_path(path):
    if not path.exists():
        raise FileNotFoundError(path)
    return path

I'd make a better bug report and/or a PR to fix it directly including a test that covers/exposes this, but I'm in the middle of chasing another issue (outside this library) so I don't have the time right now to go off on this tangent any more than I already have :smile:

Edit: I should look through open PRs in addition to looking through issues next time :stuck_out_tongue: Somebody else already did the work: https://github.com/jaraco/keyring/pull/638