question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItΒ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Further SSL problems with Poetry and a private Gitlab package registry

See original GitHub issue
  • I am on the latest Poetry version.
  • I have searched the issues of this repo and believe that this is not a duplicate.
  • If an exception occurs when executing a command, I executed it again in debug mode (-vvv option).
  • OS version and name: macOS 11.3
  • Poetry version: 1.1.6

Issue

Closely related to #745 and #1012, I am experiencing problems working with poetry against a private (Gitlab) based package registry, on an internal project. The locked nature of this make this very hard for me to do a public replication of the problem, so apologies whilst I have to be descriptive (if a little vague for some sensitive info).

I have two poetry based python+django projects. The first (atlas-models) I have managed to package as a reusable app, and build and publish (with just poetry) to our internal Gitlab Package Registry. Presently there are two versions of the package in the registry (but I’ve tried with between 1 & 3 versions there, that doesn’t appear to be a factor).

In my second project, when I attempt to add the first package via poetry add atlas-models -vvv, I get the following (abbreviated) output:

➜  ouh-mpages-development-repo git:(master) βœ— poetry add atlas-models -vvv

Using virtualenv: /Users/carl/Projects/pages.oxnet/documentation/ouh-mpages-development/ouh-mpages-development-repo/.venv
pages-oxnet-atlas: 2 packages found for atlas-models *
PyPI: No packages found for atlas-models *
Using version ^0.3.1 for atlas-models

Updating dependencies
Resolving dependencies...
   1: fact: mpages mkdocs build is 0.1.0
   1: derived: mpages mkdocs build
   1: fact: mpages mkdocs build depends on Django (^3.2)
   1: fact: mpages mkdocs build depends on atlas-models (^0.3.1)
   1: selecting mpages mkdocs build (0.1.0)
   1: derived: atlas-models (>=0.3.1,<0.4.0)
   1: derived: Django (>=3.2,<4.0)
pages-oxnet-atlas: 1 packages found for atlas-models >=0.3.1,<0.4.0
PyPI: No packages found for atlas-models >=0.3.1,<0.4.0
   1: fact: atlas-models (0.3.1) depends on Django (>=3.2,<4.0)
   1: fact: atlas-models (0.3.1) depends on cx-oracle (>=8,<9)
   1: selecting atlas-models (0.3.1)
   1: derived: cx-oracle (>=8,<9)
   1: fact: django (3.2) depends on asgiref (>=3.3.2,<4)
   1: fact: django (3.2) depends on pytz (*)
   1: fact: django (3.2) depends on sqlparse (>=0.2.2)
   1: selecting django (3.2)
   1: derived: sqlparse (>=0.2.2)
   1: derived: pytz
   1: derived: asgiref (>=3.3.2,<4)
   1: selecting cx-oracle (8.1.0)
   1: selecting sqlparse (0.4.1)
   1: selecting pytz (2021.1)
   1: selecting asgiref (3.3.4)
   1: Version solving took 0.723 seconds.
   1: Tried 1 solutions.

Finding the necessary packages for the current system

Package operations: 1 install, 0 updates, 0 removals, 5 skipped

  β€’ Installing asgiref (3.3.4): Pending...
  β€’ Installing asgiref (3.3.4): Skipped for the following reason: Already installed
  β€’ Installing pytz (2021.1): Pending...
  β€’ Installing pytz (2021.1): Skipped for the following reason: Already installed
  β€’ Installing sqlparse (0.4.1): Pending...
  β€’ Installing sqlparse (0.4.1): Skipped for the following reason: Already installed
  β€’ Installing cx-oracle (8.1.0): Pending...
  β€’ Installing cx-oracle (8.1.0): Skipped for the following reason: Already installed
  β€’ Installing django (3.2): Pending...
  β€’ Installing django (3.2): Skipped for the following reason: Already installed
  β€’ Installing atlas-models (0.3.1): Pending...
Retrying HTTP request in 0.5 seconds.
Retrying HTTP request in 1.0 seconds.
Retrying HTTP request in 1.5 seconds.
Retrying HTTP request in 2.0 seconds.
Retrying HTTP request in 2.5 seconds.
  β€’ Installing atlas-models (0.3.1): Failed

  SSLError

  HTTPSConnectionPool(host='oxnetcnsc01.oxnet.nhs.uk', port=443): Max retries exceeded with url: /api/v4/projects/202/packages/pypi/files/b278cb68cacfff2d3fd4a3d1a82c6ff12dc192c332e67db76cbdf03a02a10c2a/atlas_models-0.3.1-py3-none-any.whl (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)')))

  at ~/.poetry/lib/poetry/_vendor/py3.9/requests/adapters.py:514 in send
      510β”‚                 raise ProxyError(e, request=request)
      511β”‚ 
      512β”‚             if isinstance(e.reason, _SSLError):
      513β”‚                 # This branch is for urllib3 v1.22 and later.
    β†’ 514β”‚                 raise SSLError(e, request=request)
      515β”‚ 
      516β”‚             raise ConnectionError(e, request=request)
      517β”‚ 
      518β”‚         except ClosedPoolError as e:


Failed to add packages, reverting the pyproject.toml file to its original content.

The pyproject.toml reads as:

name = "MPages MkDocs Build"
version = "0.1.0"
description = "Python / Django application *snip*"
authors = ["Carl Marshall <email-redacted>"]
license = "Apache-2.0"

[tool.poetry.dependencies]
python = "^3.9"
Django = "^3.2"

[tool.poetry.dev-dependencies]

[[tool.poetry.source]]
name = "pages-oxnet-atlas"
url = "https://oxnetcnsc01.oxnet.nhs.uk/api/v4/projects/202/packages/pypi/simple"
secondary = true

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

Additionally, poetry config --list -vvv results in:

Loading configuration file /Users/carl/Library/Application Support/pypoetry/config.toml
Loading configuration file /Users/carl/Library/Application Support/pypoetry/auth.toml
cache-dir = "/Users/carl/Library/Caches/pypoetry"
certificates.oxnetcnsc01.cert = "/Users/carl/Projects/pages.oxnet/oxnet-combined.pem"  # None
certificates.pages-oxnet.cert = "/Users/carl/Projects/pages.oxnet/oxnet-combined.pem"  # None
certificates.pages-oxnet-atlas.cert = "/Users/carl/Projects/pages.oxnet/oxnet-combined.pem"  # None
experimental.new-installer = true
installer.parallel = true
repositories.pages-oxnet.url = "https://oxnetcnsc01.oxnet.nhs.uk/api/v4/projects/202/packages/pypi"
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/carl/Library/Caches/pypoetry/virtualenvs

I have also done poetry config http-basic.pages-oxnet user.name token-code for both .pages-oxnet and .pages-oxnet-atlas. This was all pretty much put in place to get the build and publish workflows to succeed. I also added certificates.oxnetcnsc01.cert and http-basic.oxnetcnsc01 as well to ensure I hadn’t overlooked anything.

I can see that the process is locating the latest version of the atlas-models package from the gitlab private registry, but is clearly having a problem with downloading the wheel file.

The SSL certificates you can see in the config output above are seemingly valid as they resolved the publish SSL connection issues.

If I try to set the environment variable though (to catch a potential issue with requests as suggested in an earlier bug report), I get a whole host of different errors, i.e.:

  • export REQUESTS_CA_BUNDLE=/Users/carl/Projects/pages.oxnet/oxnet-combined.pem followed by
  • poetry add atlas-models -vvv results in a much faster set of errors:
Using virtualenv: /Users/carl/Projects/pages.oxnet/documentation/ouh-mpages-development/ouh-mpages-development-repo/.venv
pages-oxnet-atlas: 2 packages found for atlas-models *

  Stack trace:

  23  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/console_application.py:131 in run
       129β”‚             parsed_args = resolved_command.args
       130β”‚ 
     β†’ 131β”‚             status_code = command.handle(parsed_args, io)
       132β”‚         except KeyboardInterrupt:
       133β”‚             status_code = 1

  22  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/api/command/command.py:120 in handle
       118β”‚     def handle(self, args, io):  # type: (Args, IO) -> int
       119β”‚         try:
     β†’ 120β”‚             status_code = self._do_handle(args, io)
       121β”‚         except KeyboardInterrupt:
       122β”‚             if io.is_debug():

  21  ~/.poetry/lib/poetry/_vendor/py3.9/clikit/api/command/command.py:171 in _do_handle
       169β”‚         handler_method = self._config.handler_method
       170β”‚ 
     β†’ 171β”‚         return getattr(handler, handler_method)(args, io, self)
       172β”‚ 
       173β”‚     def __repr__(self):  # type: () -> str

  20  ~/.poetry/lib/poetry/_vendor/py3.9/cleo/commands/command.py:92 in wrap_handle
        90β”‚         self._command = command
        91β”‚ 
     β†’  92β”‚         return self.handle()
        93β”‚ 
        94β”‚     def handle(self):  # type: () -> Optional[int]

  19  ~/.poetry/lib/poetry/console/commands/add.py:106 in handle
       104β”‚             return 0
       105β”‚ 
     β†’ 106β”‚         requirements = self._determine_requirements(
       107β”‚             packages,
       108β”‚             allow_prereleases=self.option("allow-prereleases"),

  18  ~/.poetry/lib/poetry/console/commands/init.py:328 in _determine_requirements
       326β”‚             elif "version" not in requirement:
       327β”‚                 # determine the best version automatically
     β†’ 328β”‚                 name, version = self._find_best_version_for_package(
       329β”‚                     requirement["name"],
       330β”‚                     allow_prereleases=allow_prereleases,

  17  ~/.poetry/lib/poetry/console/commands/init.py:361 in _find_best_version_for_package
       359β”‚ 
       360β”‚         selector = VersionSelector(self._get_pool())
     β†’ 361β”‚         package = selector.find_best_candidate(
       362β”‚             name, required_version, allow_prereleases=allow_prereleases, source=source
       363β”‚         )

  16  ~/.poetry/lib/poetry/version/version_selector.py:32 in find_best_candidate
       30β”‚             },
       31β”‚         )
     β†’ 32β”‚         candidates = self._pool.find_packages(dependency)
       33β”‚         only_prereleases = all([c.version.is_prerelease() for c in candidates])
       34β”‚ 

  15  ~/.poetry/lib/poetry/repositories/pool.py:165 in find_packages
       163β”‚         packages = []
       164β”‚         for repo in self._repositories:
     β†’ 165β”‚             packages += repo.find_packages(dependency)
       166β”‚ 
       167β”‚         return packages

  14  ~/.poetry/lib/poetry/repositories/pypi_repository.py:101 in find_packages
        99β”‚ 
       100β”‚         try:
     β†’ 101β”‚             info = self.get_package_info(dependency.name)
       102β”‚         except PackageNotFound:
       103β”‚             self._log(

  13  ~/.poetry/lib/poetry/repositories/pypi_repository.py:202 in get_package_info
       200β”‚             return self._get_package_info(name)
       201β”‚ 
     β†’ 202β”‚         return self._cache.store("packages").remember_forever(
       203β”‚             name, lambda: self._get_package_info(name)
       204β”‚         )

  12  ~/.poetry/lib/poetry/_vendor/py3.9/cachy/repository.py:174 in remember_forever
       172β”‚             return val
       173β”‚ 
     β†’ 174β”‚         val = value(callback)
       175β”‚ 
       176β”‚         self.forever(key, val)

  11  ~/.poetry/lib/poetry/_vendor/py3.9/cachy/helpers.py:6 in value
       4β”‚ def value(val):
       5β”‚     if callable(val):
     β†’ 6β”‚         return val()
       7β”‚ 
       8β”‚     return val

  10  ~/.poetry/lib/poetry/repositories/pypi_repository.py:203 in <lambda>
       201β”‚ 
       202β”‚         return self._cache.store("packages").remember_forever(
     β†’ 203β”‚             name, lambda: self._get_package_info(name)
       204β”‚         )
       205β”‚ 

   9  ~/.poetry/lib/poetry/repositories/pypi_repository.py:207 in _get_package_info
       205β”‚ 
       206β”‚     def _get_package_info(self, name):  # type: (str) -> dict
     β†’ 207β”‚         data = self._get("pypi/{}/json".format(name))
       208β”‚         if data is None:
       209β”‚             raise PackageNotFound("Package [{}] not found.".format(name))

   8  ~/.poetry/lib/poetry/repositories/pypi_repository.py:315 in _get
       313β”‚     def _get(self, endpoint):  # type: (str) -> Union[dict, None]
       314β”‚         try:
     β†’ 315β”‚             json_response = self.session.get(self._base_url + endpoint)
       316β”‚         except requests.exceptions.TooManyRedirects:
       317β”‚             # Cache control redirect loop.

   7  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:555 in get
       553β”‚ 
       554β”‚         kwargs.setdefault('allow_redirects', True)
     β†’ 555β”‚         return self.request('GET', url, **kwargs)
       556β”‚ 
       557β”‚     def options(self, url, **kwargs):

   6  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:542 in request
       540β”‚         }
       541β”‚         send_kwargs.update(settings)
     β†’ 542β”‚         resp = self.send(prep, **send_kwargs)
       543β”‚ 
       544β”‚         return resp

   5  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:677 in send
       675β”‚             # Redirect resolving generator.
       676β”‚             gen = self.resolve_redirects(r, request, **kwargs)
     β†’ 677β”‚             history = [resp for resp in gen]
       678β”‚         else:
       679β”‚             history = []

   4  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:677 in <listcomp>
       675β”‚             # Redirect resolving generator.
       676β”‚             gen = self.resolve_redirects(r, request, **kwargs)
     β†’ 677β”‚             history = [resp for resp in gen]
       678β”‚         else:
       679β”‚             history = []

   3  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:237 in resolve_redirects
       235β”‚             else:
       236β”‚ 
     β†’ 237β”‚                 resp = self.send(
       238β”‚                     req,
       239β”‚                     stream=stream,

   2  ~/.poetry/lib/poetry/_vendor/py3.9/requests/sessions.py:655 in send
       653β”‚ 
       654β”‚         # Send the request
     β†’ 655β”‚         r = adapter.send(request, **kwargs)
       656β”‚ 
       657β”‚         # Total elapsed time of the request (approximately)

   1  ~/.poetry/lib/poetry/_vendor/py3.9/cachecontrol/adapter.py:53 in send
        51β”‚             request.headers.update(self.controller.conditional_headers(request))
        52β”‚ 
     β†’  53β”‚         resp = super(CacheControlAdapter, self).send(request, **kw)
        54β”‚ 
        55β”‚         return resp

  SSLError

  HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /pypi/atlas-models/json/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)')))

  at ~/.poetry/lib/poetry/_vendor/py3.9/requests/adapters.py:514 in send
      510β”‚                 raise ProxyError(e, request=request)
      511β”‚ 
      512β”‚             if isinstance(e.reason, _SSLError):
      513β”‚                 # This branch is for urllib3 v1.22 and later.
    β†’ 514β”‚                 raise SSLError(e, request=request)
      515β”‚ 
      516β”‚             raise ConnectionError(e, request=request)
      517β”‚ 
      518β”‚         except ClosedPoolError as e:

When I unset REQUESTS_CA_BUNDLE and retry the add command, we’re back to the original error outputs and timeout.

I am now at a loss of what else to try here. Something appears to be partly broken in the process of adding my package from the internal registry, and this is now stalling my whole development plan. I don’t really want to have to remove poetry from this setup, but I do note there’s very little Gitlab recognition of Poetry usage (none in their own documentation) and most examples I’m finding at either general pip or GitHub solutions.

Please let me know if there’s any other practical tests, or configuration I can attempt, or if this is enough information on which to diagnose a bug.

Thank you for your time and help.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:2
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

5reactions
nylocxcommented, May 6, 2021

I hope it is ok to piggyback on this ticket. I have a pretty simple project and a self signed repository. I did the following:

poetry config repositories.myrepo "https://my.repo.tld/simple/"
poetry config certificates.myrepo.cert "/absolute/path/to/my.repo.tld.pem"

Than I added a section in my pyproject.toml

[[tool.poetry.source]]
name = "myrepo"
url = "https://my.repo.tld/simple/"
secondary = true

If I run a poetry add <any-package-that-is-on-pypi> I get:

HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/networkx/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1123)')))

If I just remove the tool.poetry.source block from my pyproject.toml everything is back to normal and works. I’m on Poetry 1.1.6

It looks like setting any certificate in the config overrides the my system certificate and the workaround from marshalc does not work for me setting SSL_CERT_FILE or REQUESTS_CA_BUNDLE to a valid certificate bundle does not change the behavior. I’m happy for any hint, as this currently blocks my progress.

0reactions
R1tschYcommented, Sep 5, 2022

I also had this problem. In the end I fixed it for me with removing the cert repository configuration in the auth.toml:

poetry config certificates.myrepo.cert --unset

Additional I used the fix from marshalc to set the explicit certificate store and added the missing certificate to the CERT_PATH file:

CERT_PATH=$(python -c "import certifi; print(certifi.where())")
echo PATH/TO/CA.crt >> $CERT_PATH
export REQUESTS_CA_BUNDLE=${CERT_PATH}
export SSL_CERT_FILE=${CERT_PATH}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Error with pip install from PyPI in self hosted Gitlab - General
so far I am quite happy with our self hosted Gitlab but I cannot pip install the release of a library I uploaded...
Read more >
Repositories | Documentation | Poetry - Python dependency ...
Repositories Poetry supports the use of PyPI and private repositories for discovery of packages as well as for publishing your projects.
Read more >
python poetry installing from private repo using pyproject.toml ...
hi am trying to to use poetry to install a package with my private repo but it doesn't seem to work. Any idea...
Read more >
Private package support - Renovate Docs
It's also quite common to need to look up packages on other protected hosts, including npmjs, Docker Hub, or private registries like Nexus...
Read more >
CI/CD with GitHub Actions with poetry - DonOfDen
how can we use it with GitHub Actions? Install Dependencies using Poetry; Config Github URL to download Private Repo; Run pytest in GitHub...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found