python-poetry / poetry

Python packaging and dependency management made easy
https://python-poetry.org
MIT License
31.25k stars 2.26k forks source link

poetry stores repo credentials by host, it should include path #5107

Open kapilt opened 2 years ago

kapilt commented 2 years ago

if you have multiple pypi repositories off the same domain but with different paths, poetry will fail to authenticate properly because it will store the credentials for the repository based on the domain, but not inclusive of path, meaning it will use the wrong credentials for a given domain.

tldr poetry credential cache keys are not correct per python spec on pypi, as poetry doesn't address repositories by suffix. https://www.python.org/dev/peps/pep-0503/

separately there's an issue is that the url doesn't get normalized early, so subsequent lookups in different parts of the codebase but same cli exec will do lookups with and without + 'simple' on the url.

$ poetry config --list | grep repo

repositories.assetdb.url = "https://corp-1122334455.d.codeartifact.us-east-1.amazonaws.com/pypi/assetdb/"
repositories.c7n-next.url = "https://corp-1122334455.d.codeartifact.us-east-1.amazonaws.com/pypi/c7n/"

traceback

  • Installing c7n (0.1.2): Pending...
  • Installing c7n (0.1.2): Failed

  RepositoryError                                                                                         

  401 Client Error: Unauthorized for url: https://corp-1122334455.d.codeartifact.us-east-1.amazonaws.com/pypi/c7n/simple/c7n/

  at ~/.local/share/pypoetry/venv/lib/python3.9/site-packages/poetry/repositories/legacy_repository.py:393 in _get
      389│             if response.status_code == 404:
      390│                 return                                                                         
      391│             response.raise_for_status()                                                                                                                                                                  
      392│         except requests.HTTPError as e:                                                        
    → 393│             raise RepositoryError(e)                                                           
      394│                                           
      395│         if response.status_code in (401, 403):
      396│             self._log(
      397│                 "Authorization error accessing {url}".format(url=response.url),

Versions

The underlying issue appears to be how credentials are retrieved, it simply grabs the credentials for the first repository that has a domain match https://github.com/python-poetry/poetry/blob/master/src/poetry/utils/authenticator.py#L151

kapilt commented 2 years ago

instead the url comparison should be made with netloc + path

kapilt commented 2 years ago

actually its a slightly more complex, as the path has some variance due to the simple suffix

(Pdb) parsed_url.netloc + parsed_url.path
'corp-1122334455.d.codeartifact.us-east-1.amazonaws.com/pypi/c7n/'
(Pdb) pp netloc
'corp-1122334455.d.codeartifact.us-east-1.amazonaws.com/pypi/c7n/simple'

passing in parsed.netloc + parsed.path and doing the repo url check against startswith sufficed.

if netloc.startswith(parsed_url.netloc + parsed_url.path)
abn commented 2 years ago

@kapilt does #5518 help with this issue?