python-poetry / python-poetry/poetry

Crash when configuring secrets from stdin

Open
#7,420 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

kind/bug status/triage
Dominant language
Python
Stars
34.3k
Forks
2.5k
Avg merge
2d 19h
Merged PRs (30d)
30

Description

  • Poetry version: 1.3.2
  • Python version: 3.10.9
  • OS version and name: Arch Linux
  • pyproject.toml:
Click to expand
[tool.poetry]
name = "<name>"
version = "0.1.0"
description = ""
authors = ["Your Name <you@foo.com>"]
packages = [
    { include = "service" }
]

[tool.poetry.dependencies]
python = ">=3.9,<3.11"
uvicorn = "0.17.0"
requests = "^2.27.1"
fastapi = "0.73.0"
cryptography = "^39.0.0"
pydantic = "^1.10.4"
pyjwt = "^2.6.0"

[tool.poetry.dev-dependencies]

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.1"

[[tool.poetry.source]]
name = "<name>"
url = "<url>"
default = true

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
  • I am on the latest stable Poetry version, installed using a recommended method.
  • I have searched the issues of this repo and believe that this is not a duplicate.
  • I have consulted the FAQ and blog for any relevant entries or release notes.
  • If an exception occurs when executing a command, I executed it again in debug mode (-vvv option) and have included the output below.

Issue

A crash occurs when trying to configure HTTP Basic login crendetials while supplying the password on stdin. See the output:

Click to expand
$ echo <password> | poetry config -vvv http-basic.<source> <username>
Loading configuration file /home/user/.config/pypoetry/config.toml
Loading configuration file /home/user/.config/pypoetry/auth.toml
Adding repository <name> (<url>) and setting it as the default one
Deactivating the PyPI repository
[keyring.backend] Loading KWallet
[keyring.backend] Loading SecretService
[keyring.backend] Loading Windows
[keyring.backend] Loading chainer
[keyring.backend] Loading libsecret
[keyring.backend] Loading macOS

  Stack trace:

  14  /usr/lib/python3.10/site-packages/cleo/application.py:327 in run
       325│ 
       326│             try:
     → 327│                 exit_code = self._run(io)
       328│             except BrokenPipeError:
       329│                 # If we are piped to another process, it may close early and send a

  13  /usr/lib/python3.10/site-packages/poetry/console/application.py:190 in _run
       188│         self._load_plugins(io)
       189│ 
     → 190│         exit_code: int = super()._run(io)
       191│         return exit_code
       192│ 

  12  /usr/lib/python3.10/site-packages/cleo/application.py:431 in _run
       429│             io.input.interactive(interactive)
       430│ 
     → 431│         exit_code = self._run_command(command, io)
       432│         self._running_command = None
       433│ 

  11  /usr/lib/python3.10/site-packages/cleo/application.py:473 in _run_command
       471│ 
       472│         if error is not None:
     → 473│             raise error
       474│ 
       475│         return terminate_event.exit_code

  10  /usr/lib/python3.10/site-packages/cleo/application.py:457 in _run_command
       455│ 
       456│             if command_event.command_should_run():
     → 457│                 exit_code = command.run(io)
       458│             else:
       459│                 exit_code = ConsoleCommandEvent.RETURN_CODE_DISABLED

   9  /usr/lib/python3.10/site-packages/cleo/commands/base_command.py:119 in run
       117│         io.input.validate()
       118│ 
     → 119│         status_code = self.execute(io)
       120│ 
       121│         if status_code is None:

   8  /usr/lib/python3.10/site-packages/cleo/commands/command.py:62 in execute
        60│ 
        61│         try:
     →  62│             return self.handle()
        63│         except KeyboardInterrupt:
        64│             return 1

   7  /usr/lib/python3.10/site-packages/poetry/console/commands/config.py:267 in handle
       265│                     password = values[1]
       266│ 
     → 267│                 password_manager.set_http_password(m.group(2), username, password)
       268│             elif m.group(1) == "pypi-token":
       269│                 if len(values) != 1:

   6  /usr/lib/python3.10/site-packages/poetry/utils/password_manager.py:219 in set_http_password
       217│             auth["password"] = password
       218│         else:
     → 219│             self.keyring.set_password(name, username, password)
       220│ 
       221│         self._config.auth_config_source.add_property(f"http-basic.{name}", auth)

   5  /usr/lib/python3.10/site-packages/poetry/utils/password_manager.py:85 in set_password
        83│ 
        84│         try:
     →  85│             keyring.set_password(name, username, password)
        86│         except (RuntimeError, keyring.errors.KeyringError) as e:
        87│             raise PoetryKeyringError(

   4  /usr/lib/python3.10/site-packages/keyring/core.py:60 in set_password
        58│ def set_password(service_name: str, username: str, password: str) -> None:
        59│     """Set password for the user in the specified service."""
     →  60│     get_keyring().set_password(service_name, username, password)
        61│ 
        62│ 

   3  /usr/lib/python3.10/site-packages/keyring/backends/chainer.py:56 in set_password
        54│         for keyring in self.backends:
        55│             try:
     →  56│                 return keyring.set_password(service, username, password)
        57│             except NotImplementedError:
        58│                 pass

   2  /usr/lib/python3.10/site-packages/keyring/backends/SecretService.py:91 in set_password
        89│         label = "Password for '{}' on '{}'".format(username, service)
        90│         with closing(collection.connection):
     →  91│             collection.create_item(label, attributes, password, replace=True)
        92│ 
        93│     def delete_password(self, service, username):

   1  /usr/lib/python3.10/site-packages/secretstorage/collection.py:119 in create_item
       117│         if not self.session:
       118│             self.session = open_session(self.connection)
     → 119│         _secret = format_secret(self.session, secret, content_type)
       120│         properties = {
       121│             SS_PREFIX + 'Item.Label': ('s', label),

  TypeError

  secret must be bytes

  at /usr/lib/python3.10/site-packages/secretstorage/util.py:108 in format_secret
      104│     Secret Service API."""
      105│     if isinstance(secret, str):
      106│         secret = secret.encode('utf-8')
      107│     elif not isinstance(secret, bytes):
    → 108│         raise TypeError('secret must be bytes')
      109│     assert session.object_path is not None
      110│     if not session.encrypted:
      111│         return (session.object_path, b'', secret, content_type)
      112│     assert session.aes_key is not None

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with poetry/console/commands/config.py and poetry/utils/password_manager.py, following the HTTP Basic configuration path shown in the traceback. Reproduce the stdin password case and inspect the related keyring interaction; done means the command completes without the reported TypeError and the credentials are configured successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.